diff -Naur linux.2210/Documentation/Configure.help linux.2210.vw/Documentation/Configure.help --- linux.2210/Documentation/Configure.help Sun Jun 13 19:54:06 1999 +++ linux.2210.vw/Documentation/Configure.help Wed Jul 28 08:56:41 1999 @@ -9681,6 +9681,12 @@ you compiled aedsp16.o as a module you can specify this parameter as 'mpu_irq=NN'. +SGI Visual Workstation on-board audio +CONFIG_SOUND_VWSND + Say Y or M if you have an SGI Visual Workstation and you want to + be able to use its on-board audio. Read Documentation/sound/visws + for more info on this driver's capabilities. + Ensoniq ES1370 based PCI sound cards CONFIG_SOUND_ES1370 Say Y or M if you have a PCI sound card utilizing the Ensoniq diff -Naur linux.2210/Documentation/sound/vwsnd linux.2210.vw/Documentation/sound/vwsnd --- linux.2210/Documentation/sound/vwsnd Wed Dec 31 16:00:00 1969 +++ linux.2210.vw/Documentation/sound/vwsnd Wed Jul 28 08:56:41 1999 @@ -0,0 +1,285 @@ +vwsnd - Sound driver for the Silicon Graphics 320 and 540 Visual +Workstations' onboard audio. + +Copyright 1999 Silicon Graphics, Inc. All rights reserved. + + +At the time of this writing, March 1999, there are two models of +Visual Workstation, the 320 and the 540. This document only describes +those models. Future Visual Workstation models may have different +sound capabilities, and this driver will probably not work on those +boxes. + +The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio +codec chip. The AD1843 is accessed through the Cobalt I/O ASIC, also +known as Lithium. This driver programs both both chips. + +============================================================================== +QUICK CONFIGURATION + + # insmod soundcore + # insmod vwsnd + +============================================================================== +I/O CONNECTIONS + +On the Visual Workstation, only three of the AD1843 inputs are hooked +up. The analog line in jacks are connected to the AD1843's AUX1 +input. The CD audio lines are connected to the AD1843's AUX2 input. +The microphone jack is connected to the AD1843's MIC input. The mic +jack is mono, but the signal is delivered to both the left and right +MIC inputs. You can record in stereo from the mic input, but you will +get the same signal on both channels (within the limits of A/D +accuracy). Full scale on the Line input is +/- 2.0 V. Full scale on +the MIC input is 20 dB less, or +/- 0.2 V. + +The AD1843's LOUT1 outputs are connected to the Line Out jacks. The +AD1843's HPOUT outputs are connected to the speaker/headphone jack. +LOUT2 is not connected. Line out's maximum level is +/- 2.0 V peak to +peak. The speaker/headphone out's maximum is +/- 4.0 V peak to peak. + +The AD1843's PCM input channel and one of its output channels (DAC1) +are connected to Lithium. The other output channel (DAC2) is not +connected. + +============================================================================== +CAPABILITIES + +The AD1843 has PCM input and output (Pulse Code Modulation, also known +as wavetable). PCM input and output can be mono or stereo in any of +four formats. The formats are 16 bit signed and 8 bit unsigned, +u-Law, and A-Law format. Any sample rate from 4 KHz to 49 KHz is +available, in 1 Hz increments. + +The AD1843 includes an analog mixer that can mix all three input +signals (line, mic and CD) into the analog outputs. The mixer has a +separate gain control and mute switch for each input. + +There are two outputs, line out and speaker/headphone out. They +always produce the same signal, and the speaker always has 3 dB more +gain than the line out. The speaker/headphone output can be muted, +but this driver does not export that function. + +The hardware can sync audio to the video clock, but this driver does +not have a way to specify syncing to video. + +============================================================================== +PROGRAMMING + +This section explains the API supported by the driver. Also see the +Open Sound Programming Guide at http://www.opensound.com/pguide/ . +This section assumes familiarity with that document. + +The driver has two interfaces, an I/O interface and a mixer interface. +There is no MIDI or sequencer capability. + +============================================================================== +PROGRAMMING PCM I/O + +The I/O interface is usually accessed as /dev/audio or /dev/dsp. +Using the standard Open Sound System (OSS) ioctl calls, the sample +rate, number of channels, and sample format may be set within the +limitations described above. The driver supports triggering. It also +supports getting the input and output pointers with one-sample +accuracy. XXX GETISPACE and GETOSPACE aren't implemented yet. + +The SNDCTL_DSP_GETCAP ioctl returns these capabilities. + + DSP_CAP_DUPLEX - driver supports full duplex. + + DSP_CAP_TRIGGER - driver supports triggering. + + not DSP_CAP_REALTIME - Not yet implemented. + +Memory mapping (mmap) is not implemented. + +When this driver is switched into or out of mu-Law or A-Law mode on +output, it may produce an audible click. This is unavoidable. To +prevent clicking, use signed 16-bit mode instead, and convert from +mu-Law or A-Law format in software. + +============================================================================== +PROGRAMMING THE MIXER INTERFACE + +The mixer interface is usually accessed as /dev/mixer. It is accessed +through ioctls. The mixer allows the application to control gain or +mute several audio signal paths, and also allows selection of the +recording source. + +Each of the constants described here can be read using the +MIXER_READ(SOUND_MIXER_xxx) ioctl. Those that are not read-only can +also be written using the MIXER_WRITE(SOUND_MIXER_xxx) ioctl. In most +cases, defines constants SOUND_MIXER_READ_xxx and +SOUND_MIXER_WRITE_xxx which work just as well. + +SOUND_MIXER_CAPS Read-only + +This is a mask of optional driver capabilities that are implemented. +This driver's only capability is SOUND_CAP_EXCL_INPUT, which means +that only one recording source can be active at a time. + +SOUND_MIXER_DEVMASK Read-only + +This is a mask of the sound channels. This driver's channels are PCM, +LINE, MIC, CD, and RECLEV. + +SOUND_MIXER_STEREODEVS Read-only + +This is a mask of which sound channels are capable of stereo. All +channels are capable of stereo. (But see caveat on MIC input in I/O +CONNECTIONS section above). + +SOUND_MIXER_OUTMASK Read-only + +This is a mask of channels that route inputs through to outputs. +Those are LINE, MIC, and CD. + +SOUND_MIXER_RECMASK Read-only + +This is a mask of channels that can be recording sources. Those are +PCM, LINE, MIC, CD. + +SOUND_MIXER_PCM Default: 0x5757 (0 dB) + +This is the gain control for PCM output. The left and right channel +gain are controlled independently. This gain control has 64 levels, +which range from -82.5 dB to +12.0 dB in 1.5 dB steps. Those 64 +levels are mapped onto 100 levels at the ioctl, see below. + +SOUND_MIXER_LINE Default: 0x4a4a (0 dB) + +This is the gain control for mixing the Line In source into the +outputs. The left and right channel gain are controlled +independently. This gain control has 32 levels, which range from +-34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto +100 levels at the ioctl, see below. + +SOUND_MIXER_MIC Default: 0x4a4a (0 dB) + +This is the gain control for mixing the MIC source into the outputs. +The left and right channel gain are controlled independently. This +gain control has 32 levels, which range from -34.5 dB to +12.0 dB in +1.5 dB steps. Those 32 levels are mapped onto 100 levels at the +ioctl, see below. + +SOUND_MIXER_CD Default: 0x4a4a (0 dB) + +This is the gain control for mixing the CD audio source into the +outputs. The left and right channel gain are controlled +independently. This gain control has 32 levels, which range from +-34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto +100 levels at the ioctl, see below. + +SOUND_MIXER_RECLEV Default: 0 (0 dB) + +This is the gain control for PCM input (RECording LEVel). The left +and right channel gain are controlled independently. This gain +control has 16 levels, which range from 0 dB to +22.5 dB in 1.5 dB +steps. Those 16 levels are mapped onto 100 levels at the ioctl, see +below. + +SOUND_MIXER_RECSRC Default: SOUND_MASK_LINE + +This is a mask of currently selected PCM input sources (RECording +SouRCes). Because the AD1843 can only have a single recording source +at a time, only one bit at a time can be set in this mask. The +allowable values are SOUND_MASK_PCM, SOUND_MASK_LINE, SOUND_MASK_MIC, +or SOUND_MASK_CD. Selecting SOUND_MASK_PCM sets up internal +resampling which is useful for loopback testing and for hardware +sample rate conversion. But software sample rate conversion is +probably faster, so I don't know how useful that is. + +SOUND_MIXER_OUTSRC DEFAULT: SOUND_MASK_LINE|SOUND_MASK_MIC|SOUND_MASK_CD + +This is a mask of sources that are currently passed through to the +outputs. Those sources whose bits are not set are muted. + +============================================================================== +GAIN CONTROL + +There are five gain controls listed above. Each has 16, 32, or 64 +steps. Each control has 1.5 dB of gain per step. Each control is +stereo. + +The OSS defines the argument to a channel gain ioctl as having two +components, left and right, each of which ranges from 0 to 100. The +two components are packed into the same word, with the left side gain +in the least significant byte, and the right side gain in the second +least significant byte. In C, we would say this. + + #include + + ... + + assert(leftgain >= 0 && leftgain <= 100); + assert(rightgain >= 0 && rightgain <= 100); + arg = leftgain | rightgain << 8; + +So each OSS gain control has 101 steps. But the hardware has 16, 32, +or 64 steps. The hardware steps are spread across the 101 OSS steps +nearly evenly. The conversion formulas are like this, given N equals +16, 32, or 64. + + int round = N/2 - 1; + OSS_gain_steps = (hw_gain_steps * 100 + round) / (N - 1); + hw_gain_steps = (OSS_gain_steps * (N - 1) + round) / 100; + +Here is a snippet of C code that will return the left and right gain +of any channel in dB. Pass it one of the predefined gain_desc_t +structures to access any of the five channels' gains. + + typedef struct gain_desc { + float min_gain; + float gain_step; + int nbits; + int chan; + } gain_desc_t; + + const gain_desc_t gain_pcm = { -82.5, 1.5, 6, SOUND_MIXER_PCM }; + const gain_desc_t gain_line = { -34.5, 1.5, 5, SOUND_MIXER_LINE }; + const gain_desc_t gain_mic = { -34.5, 1.5, 5, SOUND_MIXER_MIC }; + const gain_desc_t gain_cd = { -34.5, 1.5, 5, SOUND_MIXER_CD }; + const gain_desc_t gain_reclev = { 0.0, 1.5, 4, SOUND_MIXER_RECLEV }; + + int get_gain_dB(int fd, const gain_desc_t *gp, + float *left, float *right) + { + int word; + int lg, rg; + int mask = (1 << gp->nbits) - 1; + + if (ioctl(fd, MIXER_READ(gp->chan), &word) != 0) + return -1; /* fail */ + lg = word & 0xFF; + rg = word >> 8 & 0xFF; + lg = (lg * mask + mask / 2) / 100; + rg = (rg * mask + mask / 2) / 100; + *left = gp->min_gain + gp->gain_step * lg; + *right = gp->min_gain + gp->gain_step * rg; + return 0; + } + +And here is the corresponding routine to set a channel's gain in dB. + + int set_gain_dB(int fd, const gain_desc_t *gp, float left, float right) + { + float max_gain = + gp->min_gain + (1 << gp->nbits) * gp->gain_step; + float round = gp->gain_step / 2; + int mask = (1 << gp->nbits) - 1; + int word; + int lg, rg; + + if (left < gp->min_gain || right < gp->min_gain) + return EINVAL; + lg = (left - gp->min_gain + round) / gp->gain_step; + rg = (right - gp->min_gain + round) / gp->gain_step; + if (lg >= (1 << gp->nbits) || rg >= (1 << gp->nbits)) + return EINVAL; + lg = (100 * lg + mask / 2) / mask; + rg = (100 * rg + mask / 2) / mask; + word = lg | rg << 8; + + return ioctl(fd, MIXER_WRITE(gp->chan), &word); + } + diff -Naur linux.2210/Makefile linux.2210.vw/Makefile --- linux.2210/Makefile Fri May 28 18:10:19 1999 +++ linux.2210.vw/Makefile Wed Jul 28 08:56:41 1999 @@ -18,7 +18,7 @@ HOSTCC =gcc HOSTCFLAGS =-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -CROSS_COMPILE = +CROSS_COMPILE = AS =$(CROSS_COMPILE)as LD =$(CROSS_COMPILE)ld @@ -91,6 +91,11 @@ ifdef CONFIG_SMP CFLAGS += -D__SMP__ AFLAGS += -D__SMP__ +endif + +ifdef CONFIG_VISWS +CFLAGS += -DCONFIG_VISWS_HACKS +AFLAGS += -DCONFIG_VISWS_HACKS endif # diff -Naur linux.2210/arch/i386/config.in linux.2210.vw/arch/i386/config.in --- linux.2210/arch/i386/config.in Mon Apr 26 13:49:17 1999 +++ linux.2210.vw/arch/i386/config.in Wed Jul 28 08:56:41 1999 @@ -194,6 +194,8 @@ fi endmenu +source drivers/usb/Config.in + mainmenu_option next_comment comment 'Kernel hacking' diff -Naur linux.2210/arch/i386/kernel/bios32.c linux.2210.vw/arch/i386/kernel/bios32.c --- linux.2210/arch/i386/kernel/bios32.c Sat Apr 24 17:49:37 1999 +++ linux.2210.vw/arch/i386/kernel/bios32.c Wed Jul 28 08:56:41 1999 @@ -352,6 +352,7 @@ * * This should be close to trivial, but it isn't, because there are buggy * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. + * XXX maybe Lithium is "buggy" this way as well? */ __initfunc(int pci_sanity_check(struct pci_access *a)) { @@ -1145,7 +1146,12 @@ pci_write_config_word(dev, PCI_COMMAND, cmd); } } -#if defined(CONFIG_X86_IO_APIC) +#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_VISWS_APIC) +#ifdef CONFIG_X86_IO_APIC +#define PCI_IRQ(b,s,p) IO_APIC_get_PCI_irq_vector(b,s,p) +#elif CONFIG_X86_VISWS_APIC +#define PCI_IRQ(b,s,p) visws_get_PCI_irq_vector(b,s,p) +#endif /* * Recalculate IRQ numbers if we use the I/O APIC */ @@ -1157,13 +1163,14 @@ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (pin) { pin--; /* interrupt pins are numbered starting from 1 */ - irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); + irq = PCI_IRQ(dev->bus->number, + PCI_SLOT(dev->devfn), pin); if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ struct pci_dev * bridge = dev->bus->self; pin = (pin + PCI_SLOT(dev->devfn)) % 4; - irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), pin); + irq = PCI_IRQ(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); if (irq >= 0) printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); diff -Naur linux.2210/arch/i386/kernel/head.S linux.2210.vw/arch/i386/kernel/head.S --- linux.2210/arch/i386/kernel/head.S Thu Jan 14 22:57:25 1999 +++ linux.2210.vw/arch/i386/kernel/head.S Wed Jul 28 08:56:41 1999 @@ -40,6 +40,12 @@ ENTRY(stext) ENTRY(_stext) startup_32: +#ifdef CONFIG_VISWS_HACKS + movl $0x101000,%eax + movl %eax,%cr3 + lgdt gdt_descr + lidt idt_descr +#endif /* * Set segments to known values */ diff -Naur linux.2210/arch/i386/kernel/i386_ksyms.c linux.2210.vw/arch/i386/kernel/i386_ksyms.c --- linux.2210/arch/i386/kernel/i386_ksyms.c Mon May 10 10:32:45 1999 +++ linux.2210.vw/arch/i386/kernel/i386_ksyms.c Wed Jul 28 08:56:41 1999 @@ -115,3 +115,10 @@ #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif + +#ifdef CONFIG_VISWS_HACKS +extern u_long sgivw_gfx_mem_phys; +extern u_long sgivw_gfx_mem_size; +EXPORT_SYMBOL(sgivw_gfx_mem_phys); +EXPORT_SYMBOL(sgivw_gfx_mem_size); +#endif diff -Naur linux.2210/arch/i386/kernel/io_apic.c linux.2210.vw/arch/i386/kernel/io_apic.c --- linux.2210/arch/i386/kernel/io_apic.c Thu May 6 16:07:03 1999 +++ linux.2210.vw/arch/i386/kernel/io_apic.c Wed Jul 28 08:56:41 1999 @@ -558,27 +558,6 @@ return 0; } -int irq_vector[NR_IRQS] = { IRQ0_TRAP_VECTOR , 0 }; - -static int __init assign_irq_vector(int irq) -{ - static int current_vector = IRQ0_TRAP_VECTOR, offset = 0; - if (IO_APIC_VECTOR(irq) > 0) - return IO_APIC_VECTOR(irq); - current_vector += 8; - if (current_vector > 0xFE) { - offset++; - current_vector = IRQ0_TRAP_VECTOR + offset; - printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n", - current_vector); - } - if (current_vector == SYSCALL_VECTOR) - panic("ran out of interrupt sources!"); - - IO_APIC_VECTOR(irq) = current_vector; - return current_vector; -} - void __init setup_IO_APIC_irqs(void) { struct IO_APIC_route_entry entry; @@ -985,7 +964,7 @@ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { desc->status = status | IRQ_REPLAY; - send_IPI_self(IO_APIC_VECTOR(irq)); + send_IPI_self(IRQ_VECTOR(irq)); } } @@ -1175,7 +1154,7 @@ * 0x80, because int 0x80 is hm, kind of importantish. ;) */ for (i = 0; i < NR_IRQS ; i++) { - if (IO_APIC_VECTOR(i) > 0) { + if (IRQ_VECTOR(i) > 0) { if (IO_APIC_irq_trigger(i)) irq_desc[i].handler = &ioapic_level_irq_type; else @@ -1203,7 +1182,7 @@ irq_desc[i].handler = &no_irq_type; } } - init_IRQ_SMP(); + init_IRQ_MORE_TRAPS(); } /* diff -Naur linux.2210/arch/i386/kernel/irq.c linux.2210.vw/arch/i386/kernel/irq.c --- linux.2210/arch/i386/kernel/irq.c Mon May 10 10:32:45 1999 +++ linux.2210.vw/arch/i386/kernel/irq.c Wed Jul 28 08:56:41 1999 @@ -292,7 +292,7 @@ */ BUILD_16_IRQS(0x0) -#ifdef CONFIG_X86_IO_APIC +#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_VISWS_APIC) /* * The IO-APIC gives us many more interrupt sources. Most of these * are unused but an SMP system is supposed to have enough memory ... @@ -348,7 +348,7 @@ static void (*interrupt[NR_IRQS])(void) = { IRQLIST_16(0x0), -#ifdef CONFIG_X86_IO_APIC +#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_VISWS_APIC) IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3), IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), @@ -955,6 +955,11 @@ */ unsigned long probe_irq_on(void) { +#ifdef CONFIG_VISWS_HACKS +/* XXX current startup/shutdown_cobalt_irq() code + * XXX will break if we use it this way + */ +#else unsigned int i; unsigned long delay; @@ -993,7 +998,7 @@ } } spin_unlock_irq(&irq_controller_lock); - +#endif return 0x12345678; } @@ -1006,6 +1011,12 @@ nr_irqs = 0; irq_found = 0; +#ifdef CONFIG_VISWS_HACKS +/* XXX we _could_ look in the 8259 and if we see what we + * XXX know is IDEn we can here return the proper + * XXX cobalt-direct entry... hmmm + */ +#else spin_lock_irq(&irq_controller_lock); for (i=0; i 1) irq_found = -irq_found; +#endif return irq_found; } +#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_VISWS_APIC) + +int irq_vector[NR_IRQS] = { IRQ0_TRAP_VECTOR , 0 }; + +int __init assign_irq_vector(int irq) +{ + static int current_vector = IRQ0_TRAP_VECTOR, offset = 0; + if (IRQ_VECTOR(irq) > 0) + return IRQ_VECTOR(irq); + current_vector += 8; + if (current_vector > 0xFE) { + offset++; + current_vector = IRQ0_TRAP_VECTOR + offset; + printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n", + current_vector); + } + if (current_vector == SYSCALL_VECTOR) + panic("ran out of interrupt sources!"); + + IRQ_VECTOR(irq) = current_vector; + return current_vector; +} +#endif + void init_ISA_irqs (void) { int i; @@ -1055,11 +1091,6 @@ { int i; -#ifndef CONFIG_X86_VISWS_APIC - init_ISA_irqs(); -#else - init_VISWS_APIC_irqs(); -#endif /* * Cover the whole vector space, no vector can escape * us. (some of these will be overridden and become @@ -1071,11 +1102,17 @@ set_intr_gate(vector, interrupt[i]); } +#ifndef CONFIG_X86_VISWS_APIC + init_ISA_irqs(); +#else + init_VISWS_APIC_irqs(); +#endif + #ifdef __SMP__ /* IRQ0 must be given a fixed assignment and initialized - before init_IRQ_SMP. + before init_IRQ_MORE_TRAPS. */ set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]); @@ -1117,13 +1154,52 @@ #endif } -#ifdef CONFIG_X86_IO_APIC -__initfunc(void init_IRQ_SMP(void)) +#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_VISWS_APIC) +/* + * An IO-APIC PC has more traps if SMP. + * The Visual Workstation always has more traps (whether SMP or not). + */ +__initfunc(void init_IRQ_MORE_TRAPS(void)) { int i; for (i = 0; i < NR_IRQS ; i++) - if (IO_APIC_VECTOR(i) > 0) - set_intr_gate(IO_APIC_VECTOR(i), interrupt[i]); + if (IRQ_VECTOR(i) > 0) + set_intr_gate(IRQ_VECTOR(i), interrupt[i]); } -#endif +/* + * Visual Workstation always uses the cpu/local APICs for interrupts. + * IO-APIC PCs use this only when SMP + */ +void __init enable_local_APIC(void) +{ + unsigned long value; + + value = apic_read(APIC_SPIV); + value |= (1<<8); /* Enable APIC (bit==1) */ + value &= ~(1<<9); /* Enable focus processor (bit==0) */ + value |= 0xff; /* Set spurious IRQ vector to 0xff */ + apic_write(APIC_SPIV,value); + + /* + * Set Task Priority to 'accept all' + */ + value = apic_read(APIC_TASKPRI); + value &= ~APIC_TPRI_MASK; + apic_write(APIC_TASKPRI,value); + + /* + * Clear the logical destination ID, just to be safe. + * also, put the APIC into flat delivery mode. + */ + value = apic_read(APIC_LDR); + value &= ~APIC_LDR_MASK; + apic_write(APIC_LDR,value); + + value = apic_read(APIC_DFR); + value |= SET_APIC_DFR(0xf); + apic_write(APIC_DFR, value); + + udelay(100); /* B safe */ +} +#endif diff -Naur linux.2210/arch/i386/kernel/irq.h linux.2210.vw/arch/i386/kernel/irq.h --- linux.2210/arch/i386/kernel/irq.h Tue May 11 10:37:06 1999 +++ linux.2210.vw/arch/i386/kernel/irq.h Wed Jul 28 14:25:55 1999 @@ -79,9 +79,10 @@ extern irq_desc_t irq_desc[NR_IRQS]; extern int irq_vector[NR_IRQS]; -#define IO_APIC_VECTOR(irq) irq_vector[irq] +#define IRQ_VECTOR(irq) irq_vector[irq] -extern void init_IRQ_SMP(void); +extern int assign_irq_vector(int irq); +extern void init_IRQ_MORE_TRAPS(void); extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); extern int setup_x86_irq(unsigned int, struct irqaction *); @@ -102,6 +103,7 @@ extern void init_VISWS_APIC_irqs(void); extern void setup_IO_APIC(void); extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); +extern int visws_get_PCI_irq_vector(int bus, int slot, int fn); extern void make_8259A_irq(unsigned int irq); extern void send_IPI(int dest, int vector); extern void init_pic_mode(void); diff -Naur linux.2210/arch/i386/kernel/process.c linux.2210.vw/arch/i386/kernel/process.c --- linux.2210/arch/i386/kernel/process.c Fri Apr 30 08:13:37 1999 +++ linux.2210.vw/arch/i386/kernel/process.c Wed Jul 28 08:56:41 1999 @@ -168,6 +168,57 @@ return 0; } +#ifdef CONFIG_VISWS + +#include +#include + +static void +visws_restart(void) +{ + /* + * This machine resets by poking this + * register on PIIX4. + */ + outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT); +} + +static void +visws_power_off(void) +{ + unsigned short pm_status; + + /* + * Clearing the event before the button is released seems to + * re-enable it, thus preventing shutdown. + */ + while ((pm_status = inw(PMSTS_PORT)) & 0x100) { + outw(pm_status, PMSTS_PORT); + } + + /* + * Here's the magic write that actually sequences + * the PIIX4 to shutdown the power. + */ + outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT); + + /* + * Need 10msec delay before generating special + * cycle so PIIX4 will shut down system. + */ + udelay(10000); + + /* + * PIIX4 has asserted stopclk and is waiting to see + * the stop special cycle. Generate one of those + * by hand now. + */ + pcibios_write_config_dword(PIIX4_BUS, SPECIAL_DEV, SPECIAL_REG, + PIIX_SPECIAL_STOP); +} +#endif /* CONFIG_VISWS */ + + /* * This routine reboots the machine by asking the keyboard * controller to pulse the reset-line low. We try that for a while, @@ -279,6 +330,10 @@ init_pic_mode(); #endif +#ifdef CONFIG_VISWS + visws_restart(); +#endif /* CONFIG_VISWS */ + if(!reboot_thru_bios) { /* rebooting needs to touch the page at absolute addr 0 */ *((unsigned short *)__va(0x472)) = reboot_mode; @@ -386,6 +441,9 @@ void machine_power_off(void) { +#ifdef CONFIG_VISWS + visws_power_off(); +#endif /* CONFIG_VISWS */ #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) apm_power_off(); #endif diff -Naur linux.2210/arch/i386/kernel/setup.c linux.2210.vw/arch/i386/kernel/setup.c --- linux.2210/arch/i386/kernel/setup.c Tue Jun 8 10:43:21 1999 +++ linux.2210.vw/arch/i386/kernel/setup.c Wed Jul 28 08:56:41 1999 @@ -47,8 +47,11 @@ #include #include #include -#include #include +#ifdef CONFIG_VISWS +#include +#include +#endif /* * Machine setup.. @@ -123,54 +126,17 @@ char visws_board_type = -1; char visws_board_rev = -1; -#define PIIX_PM_START 0x0F80 - -#define SIO_GPIO_START 0x0FC0 - -#define SIO_PM_START 0x0FC8 - -#define PMBASE PIIX_PM_START -#define GPIREG0 (PMBASE+0x30) -#define GPIREG(x) (GPIREG0+((x)/8)) -#define PIIX_GPI_BD_ID1 18 -#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) - -#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) - -#define SIO_INDEX 0x2e -#define SIO_DATA 0x2f - -#define SIO_DEV_SEL 0x7 -#define SIO_DEV_ENB 0x30 -#define SIO_DEV_MSB 0x60 -#define SIO_DEV_LSB 0x61 - -#define SIO_GP_DEV 0x7 - -#define SIO_GP_BASE SIO_GPIO_START -#define SIO_GP_MSB (SIO_GP_BASE>>8) -#define SIO_GP_LSB (SIO_GP_BASE&0xff) - -#define SIO_GP_DATA1 (SIO_GP_BASE+0) - -#define SIO_PM_DEV 0x8 - -#define SIO_PM_BASE SIO_PM_START -#define SIO_PM_MSB (SIO_PM_BASE>>8) -#define SIO_PM_LSB (SIO_PM_BASE&0xff) -#define SIO_PM_INDEX (SIO_PM_BASE+0) -#define SIO_PM_DATA (SIO_PM_BASE+1) - -#define SIO_PM_FER2 0x1 - -#define SIO_PM_GP_EN 0x80 +#ifdef CONFIG_VISWS_HACKS +u_long sgivw_gfx_mem_phys = 0; +u_long sgivw_gfx_mem_size = -1; +#endif static void visws_get_board_type_and_rev(void) { int raw; - visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) + visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_MASK) >> PIIX_GPI_BD_SHIFT; /* * Get Board rev. @@ -222,29 +188,31 @@ raw = inb_p(SIO_GP_DATA1); raw &= 0x7f; /* 7 bits of valid board revision ID. */ - if (visws_board_type == VISWS_320) { + switch (visws_board_type) { + case VISWS_320: if (raw < 0x6) { visws_board_rev = 4; } else if (raw < 0xc) { visws_board_rev = 5; } else { visws_board_rev = 6; - } - } else if (visws_board_type == VISWS_540) { - visws_board_rev = 2; - } else { - visws_board_rev = raw; - } - - printk("Silicon Graphics %s (rev %d)\n", - visws_board_type == VISWS_320 ? "320" : - (visws_board_type == VISWS_540 ? "540" : - "unknown"), - visws_board_rev); + break; + case VISWS_540: + visws_board_rev = 2; + break; + default: + visws_board_rev = raw; + break; } -#endif + printk("Silicon Graphics %s (rev %d)\n", + visws_board_type == VISWS_320 ? "320" : + (visws_board_type == VISWS_540 ? "540" : + "unknown"), + visws_board_rev); +} +#endif static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; @@ -257,9 +225,19 @@ int len = 0; #ifdef CONFIG_VISWS + /* + * Except for COMMAND_LINE nothing presently (July 15, 1999) fills + * out the PARAM block on a Visual Workstation. We'll make this + * explicit by skipping any code that looks in there. + */ visws_get_board_type_and_rev(); -#endif +#define MEGS 128 /* XXX HACK how to get mem config? */ + /* XXX 128 will always work... smallest mem size */ + printk("VISWS HACK: hard-wiring physical mem size to %dMb\n", MEGS); + memory_end = MEGS<<20; /* Happens to be PAGE_MASK safe */ + +#else /* !CONFIG_VISWS */ ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; @@ -284,6 +262,8 @@ #endif memory_end &= PAGE_MASK; + + #ifdef CONFIG_BLK_DEV_RAM rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); @@ -291,6 +271,7 @@ #endif if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; +#endif memory_start = (unsigned long) &_end; init_task.mm->start_code = PAGE_OFFSET; init_task.mm->end_code = (unsigned long) &_etext; @@ -323,6 +304,23 @@ } } } +#ifdef CONFIG_VISWS_HACKS + /* + * "gfxmem=XXX[kKmM]" overrides the default + * graphics memory size + */ + if (c == ' ' && !memcmp(from,"gfxmem=",7)) { + if (to != command_line) to--; + sgivw_gfx_mem_size = simple_strtoul(from+7, &from, 0); + if ( *from == 'K' || *from == 'k' ) { + sgivw_gfx_mem_size <<= 10; + from++; + } else if ( *from == 'M' || *from == 'm' ) { + sgivw_gfx_mem_size <<= 20; + from++; + } + } +#endif c = *(from++); if (!c) break; @@ -333,6 +331,28 @@ *to = '\0'; *cmdline_p = command_line; +#ifdef CONFIG_VISWS_HACKS + #define VISWS_GFX_MEM_MEGS 16 + if (sgivw_gfx_mem_size == -1) + sgivw_gfx_mem_size = VISWS_GFX_MEM_MEGS<<20; + /* truncate gfxmem size down to nearest megabyte */ + sgivw_gfx_mem_size &= ~((1<<20)-1); + memory_end -= sgivw_gfx_mem_size; + printk("VISWS HACK: taking %ldMb for gfx memory -- leaving %ldMb for kernel\n", + sgivw_gfx_mem_size>>20, memory_end>>20); + sgivw_gfx_mem_phys = memory_end; + printk("sgivw_gfx_mem_phys %lx\n", sgivw_gfx_mem_phys); +#endif + +#ifdef CONFIG_VISWS + /* + * Using 'hlt' in cpu_idle() on a Visual Workstation can tickle + * a h/w bug in memory refresh that can spontaneously reset + * or even power-off the system. + */ + boot_cpu_data.hlt_works_ok = 0; +#endif + #define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */ #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) @@ -375,12 +395,13 @@ request_region(0xf0,0x10,"fpu"); #ifdef CONFIG_VT -#if defined(CONFIG_VGA_CONSOLE) +#if defined(CONFIG_VGA_CONSOLE) && !defined(CONFIG_VISWS) conswitchp = &vga_con; #elif defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; #endif #endif + /* * Check the bugs that will bite us before we get booting */ diff -Naur linux.2210/arch/i386/kernel/smp.c linux.2210.vw/arch/i386/kernel/smp.c --- linux.2210/arch/i386/kernel/smp.c Wed Jun 2 11:29:27 1999 +++ linux.2210.vw/arch/i386/kernel/smp.c Wed Jul 28 14:26:24 1999 @@ -185,19 +185,6 @@ * Intel MP BIOS table parsing routines: */ -#ifndef CONFIG_X86_VISWS_APIC -/* - * Checksum an MP configuration block. - */ - -static int mpf_checksum(unsigned char *mp, int len) -{ - int sum=0; - while(len--) - sum+=*mp++; - return sum&0xFF; -} - /* * Processor encoding in an MP configuration block */ @@ -225,6 +212,69 @@ return n; } +static void __init smp_read_mpc_processor(struct mpc_config_processor *m) +{ + if (!(m->mpc_cpuflag&CPU_ENABLED)) { + return; + } + printk("Processor #%d %s APIC version %d\n", + m->mpc_apicid, + mpc_family((m->mpc_cpufeature& + CPU_FAMILY_MASK)>>8, + (m->mpc_cpufeature& + CPU_MODEL_MASK)>>4), + m->mpc_apicver); +#ifdef SMP_DEBUG + if (m->mpc_featureflag&(1<<0)) + printk(" Floating point unit present.\n"); + if (m->mpc_featureflag&(1<<7)) + printk(" Machine Exception supported.\n"); + if (m->mpc_featureflag&(1<<8)) + printk(" 64 bit compare & exchange supported.\n"); + if (m->mpc_featureflag&(1<<9)) + printk(" Internal APIC present.\n"); +#endif + if (m->mpc_cpuflag&CPU_BOOTPROCESSOR) + { + SMP_PRINTK((" Bootup CPU\n")); + boot_cpu_id=m->mpc_apicid; + } + else /* Boot CPU already counted */ + num_processors++; + + if (m->mpc_apicid>NR_CPUS) + printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS); + else + { + int ver = m->mpc_apicver; + + cpu_present_map|=(1<mpc_apicid); + /* + * Validate version + */ + if (ver == 0x0) { + printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); + ver = 0x10; + } + apic_version[m->mpc_apicid] = ver; + } +} + +#ifndef CONFIG_X86_VISWS_APIC +/* + * Checksum an MP configuration block. + */ + +static int mpf_checksum(unsigned char *mp, int len) +{ + int sum=0; + while(len--) + sum+=*mp++; + return sum&0xFF; +} + + + /* * Read the MPC */ @@ -280,52 +330,9 @@ { case MP_PROCESSOR: { - struct mpc_config_processor *m= + struct mpc_config_bus *m= (struct mpc_config_processor *)mpt; - if (m->mpc_cpuflag&CPU_ENABLED) - { - printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, - mpc_family((m->mpc_cpufeature& - CPU_FAMILY_MASK)>>8, - (m->mpc_cpufeature& - CPU_MODEL_MASK)>>4), - m->mpc_apicver); -#ifdef SMP_DEBUG - if (m->mpc_featureflag&(1<<0)) - printk(" Floating point unit present.\n"); - if (m->mpc_featureflag&(1<<7)) - printk(" Machine Exception supported.\n"); - if (m->mpc_featureflag&(1<<8)) - printk(" 64 bit compare & exchange supported.\n"); - if (m->mpc_featureflag&(1<<9)) - printk(" Internal APIC present.\n"); -#endif - if (m->mpc_cpuflag&CPU_BOOTPROCESSOR) - { - SMP_PRINTK((" Bootup CPU\n")); - boot_cpu_id=m->mpc_apicid; - } - else /* Boot CPU already counted */ - num_processors++; - - if (m->mpc_apicid>NR_CPUS) - printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS); - else - { - int ver = m->mpc_apicver; - - cpu_present_map|=(1<mpc_apicid); - /* - * Validate version - */ - if (ver == 0x0) { - printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); - ver = 0x10; - } - apic_version[m->mpc_apicid] = ver; - } - } + smp_read_mpc_processor(m); mpt+=sizeof(*m); count+=sizeof(*m); break; @@ -608,17 +615,33 @@ /* * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesnt have a BIOS(-configuration table). + * sense, but it doesn't have a completely MP compliant MP table. * No problem for Linux. */ +#define CO_CPU_NUM_PHYS 0x1e00 +#define CO_CPU_TAB_PHYS (CO_CPU_NUM_PHYS + 2) + +#define CO_CPU_MAX 4 + void __init init_visws_smp(void) { - smp_found_config = 1; + struct mpc_config_processor *mp = (struct mpc_config_processor *) + (PAGE_OFFSET + CO_CPU_TAB_PHYS); + unsigned short ncpus = *(unsigned short*) + (PAGE_OFFSET + CO_CPU_NUM_PHYS); + + if (ncpus > CO_CPU_MAX) { + printk("init_visws_smp: insane cpu count %d, addr %p\n", + ncpus, mp); + return; + } - cpu_present_map |= 2; /* or in id 1 */ - apic_version[1] |= 0x10; /* integrated APIC */ - apic_version[0] |= 0x10; + smp_found_config = 1; + while (ncpus--) { + smp_read_mpc_processor(mp++); + } + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; } @@ -716,37 +739,6 @@ atomic_set(&smp_commenced,1); } -void __init enable_local_APIC(void) -{ - unsigned long value; - - value = apic_read(APIC_SPIV); - value |= (1<<8); /* Enable APIC (bit==1) */ - value &= ~(1<<9); /* Enable focus processor (bit==0) */ - value |= 0xff; /* Set spurious IRQ vector to 0xff */ - apic_write(APIC_SPIV,value); - - /* - * Set Task Priority to 'accept all' - */ - value = apic_read(APIC_TASKPRI); - value &= ~APIC_TPRI_MASK; - apic_write(APIC_TASKPRI,value); - - /* - * Clear the logical destination ID, just to be safe. - * also, put the APIC into flat delivery mode. - */ - value = apic_read(APIC_LDR); - value &= ~APIC_LDR_MASK; - apic_write(APIC_LDR,value); - - value = apic_read(APIC_DFR); - value |= SET_APIC_DFR(0xf); - apic_write(APIC_DFR, value); - - udelay(100); /* B safe */ -} unsigned long __init init_smp_mappings(unsigned long memory_start) { diff -Naur linux.2210/arch/i386/kernel/time.c linux.2210.vw/arch/i386/kernel/time.c --- linux.2210/arch/i386/kernel/time.c Thu Apr 29 11:53:41 1999 +++ linux.2210.vw/arch/i386/kernel/time.c Wed Jul 28 08:56:41 1999 @@ -54,7 +54,7 @@ #include #include -#include +#include /* * for x86_do_profile() @@ -680,9 +680,6 @@ /* Enable (unmask) the timer interrupt */ co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); - /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ - setup_x86_irq(CO_IRQ_TIMER, &irq0); -#else - setup_x86_irq(0, &irq0); #endif + setup_x86_irq(0, &irq0); } diff -Naur linux.2210/arch/i386/kernel/trampoline.S linux.2210.vw/arch/i386/kernel/trampoline.S --- linux.2210/arch/i386/kernel/trampoline.S Wed May 6 11:42:54 1998 +++ linux.2210.vw/arch/i386/kernel/trampoline.S Wed Jul 28 08:56:41 1999 @@ -54,8 +54,13 @@ lmsw %ax # into protected mode jmp flush_instr flush_instr: +#ifdef CONFIG_VISWS_HACKS + ljmpl $__KERNEL_CS, $0x00100016 + # jump to startup_32 + 0x16 +#else ljmpl $__KERNEL_CS, $0x00100000 # jump to startup_32 +#endif idt_48: .word 0 # idt limit = 0 diff -Naur linux.2210/arch/i386/kernel/traps.c linux.2210.vw/arch/i386/kernel/traps.c --- linux.2210/arch/i386/kernel/traps.c Tue Feb 16 14:20:05 1999 +++ linux.2210.vw/arch/i386/kernel/traps.c Wed Jul 28 08:56:41 1999 @@ -38,8 +38,8 @@ #ifdef CONFIG_X86_VISWS_APIC #include -#include -#include +#include +#include #endif #include "irq.h" @@ -579,57 +579,6 @@ } #ifdef CONFIG_X86_VISWS_APIC - -/* - * On Rev 005 motherboards legacy device interrupt lines are wired directly - * to Lithium from the 307. But the PROM leaves the interrupt type of each - * 307 logical device set appropriate for the 8259. Later we'll actually use - * the 8259, but for now we have to flip the interrupt types to - * level triggered, active lo as required by Lithium. - */ - -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ - -static void -superio_outb(int dev, int reg, int val) -{ - outb(DEV, REG); - outb(dev, VAL); - outb(reg, REG); - outb(val, VAL); -} - -static int __attribute__ ((unused)) -superio_inb(int dev, int reg) -{ - outb(DEV, REG); - outb(dev, VAL); - outb(reg, REG); - return inb(VAL); -} - -#define FLOP 3 /* floppy logical device */ -#define PPORT 4 /* parallel logical device */ -#define UART5 5 /* uart2 logical device (not wired up) */ -#define UART6 6 /* uart1 logical device (THIS is the serial port!) */ -#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */ -#define ITYPE 0x71 /* interrupt type register */ - -/* interrupt type bits */ -#define LEVEL 0x01 /* bit 0, 0 == edge triggered */ -#define ACTHI 0x02 /* bit 1, 0 == active lo */ - -static void -superio_init(void) -{ - if (visws_board_type == VISWS_320 && visws_board_rev == 5) { - superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */ - printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n"); - } -} - static void lithium_init(void) { @@ -640,22 +589,33 @@ printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n", li_pcib_read16(LI_PCI_BUSNUM) & 0xff); - /* XXX blindly enables all interrupts */ - li_pcia_write16(LI_PCI_INTEN, 0xffff); - li_pcib_write16(LI_PCI_INTEN, 0xffff); + /* XXX blindly enables all device interrupts */ + /* XXX even more blindly does not enable any error interrupts */ + /* NOTE: Lithium error interrupts share LI_INTD */ +#define A01234 (LI_INTA_0|LI_INTA_1|LI_INTA_2|LI_INTA_3|LI_INTA_4) +#define BCD (LI_INTB|LI_INTC|LI_INTD) +#define ALLDEVS (A01234|BCD) + li_pcia_write16(LI_PCI_INTEN, ALLDEVS); + li_pcib_write16(LI_PCI_INTEN, ALLDEVS); } static void cobalt_init(void) { /* - * On normal SMP PC this is used only with SMP, but we have to - * use it and set it up here to start the Cobalt clock + * On normal SMP PC the local APIC is used only with SMP. + * On Visual Workstations all interrupts always go through + * the local APIC including the clock which is why we have + * initialize and enable the local APIC so early. */ set_fixmap(FIX_APIC_BASE, APIC_PHYS_BASE); + enable_local_APIC(); printk("Local APIC ID %lx\n", apic_read(APIC_ID)); printk("Local APIC Version %lx\n", apic_read(APIC_VERSION)); + /* + * And, now we go out to the Cobalt APIC and enable it. + */ set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); @@ -702,7 +662,6 @@ load_TR(0); load_ldt(0); #ifdef CONFIG_X86_VISWS_APIC - superio_init(); lithium_init(); cobalt_init(); #endif diff -Naur linux.2210/arch/i386/kernel/visws_apic.c linux.2210.vw/arch/i386/kernel/visws_apic.c --- linux.2210/arch/i386/kernel/visws_apic.c Thu May 6 16:12:23 1999 +++ linux.2210.vw/arch/i386/kernel/visws_apic.c Wed Jul 28 08:56:41 1999 @@ -36,10 +36,18 @@ #include #include -#include +#include #include "irq.h" +#define LEGACY_IRQS +#define SERIAL_HACK + +#ifndef CONFIG_SMP +int skip_ioapic_setup; /* No IO-APIC to ever skip on Cobalt! */ +#endif + +#ifdef LEGACY_IRQS /* * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt * -- not the manner expected by the normal 8259 code in irq.c. @@ -51,8 +59,6 @@ * controller. Device drivers only see the virtual interrupt sources. */ -#define CO_IRQ_BASE 0x20 /* This is the 0x20 in init_IRQ()! */ - static void startup_piix4_master_irq(unsigned int irq); static void shutdown_piix4_master_irq(unsigned int irq); static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs); @@ -81,6 +87,7 @@ enable_piix4_virtual_irq, disable_piix4_virtual_irq }; +#endif /* * This is the SGI Cobalt (IO-)APIC: @@ -90,7 +97,7 @@ static void enable_cobalt_irq(unsigned int irq); static void disable_cobalt_irq(unsigned int irq); static void startup_cobalt_irq(unsigned int irq); -#define shutdown_cobalt_irq disable_cobalt_irq +static void shutdown_cobalt_irq(unsigned int irq); static struct hw_interrupt_type cobalt_irq_type = { "Cobalt-APIC", @@ -112,32 +119,87 @@ /* * Cobalt (IO)-APIC functions to handle PCI devices. + * + * Correctness and clarity are prioritized over performance. */ -static void disable_cobalt_irq(unsigned int irq) +static int +co_apic_ide0_hack(void) /* terribly inefficiently extensible */ { - /* XXX undo the APIC entry here? */ + extern char visws_board_type; + extern char visws_board_rev; - /* - * definitely, we do not want to have IRQ storms from - * unused devices --mingo - */ + /* XXX really only for the 5 alpha boxes in Ken Nicholson's group! */ + if (visws_board_type == VISWS_320 && visws_board_rev == 5) { + return 5; + } + return CO_APIC_IDE0; } -static void enable_cobalt_irq(unsigned int irq) +/* + * Returns Cobalt APIC entry for this irq + * + * 'irq' MUST be a cobalt-direct interrupt. something's coded very wrong + * if we get here with a piix4-8259 irq + * + * Note: here we know that the ide driver defaults IDE{0,1} to IRQ 1{4,5}! + * A drag, because we need to check/map these aliases/warts in IRQ number space. + * (Ideally we'd rather give IDEx CO_IRQ(CO_APIC_IDEx), but there's no great way + * to implement probe_irq_on/off) + */ +static int is_co_apic(unsigned int irq) { + if (IS_CO_APIC(irq)) { + return CO_APIC(irq); + } + /* Here are those yucky aliases that wreak havoc on beauty */ + switch (irq) { + case 0: return CO_APIC_CPU; + case CO_IRQ_IDE0: return co_apic_ide0_hack(); + case CO_IRQ_IDE1: return CO_APIC_IDE1; + default: return -1; + } + /* NOTREACHED */ +} + +/* XXX ouch... is this really our only choice for masking this interrupt? */ +/* XXX not fully safe for 2 reasons: + * 1) should not touch an apic entry while (whole) apic is enabled + * 2) careful about storing to IRR bit (unless we know this intr is idle) + */ +static void disable_cobalt_irq(unsigned int irq) /* disable_irq() */ +{ + int ent = is_co_apic(irq); + if (ent == -1) { + return; /* could actually be a panic */ + } + + /* Note: h/w nada like read-mod-write! Vec saved in IRQ_VECTOR() */ + co_apic_write(CO_APIC_LO(ent), CO_APIC_MASK); + (void)co_apic_read(CO_APIC_LO(ent)); /* sync cpu to cobalt apic */ +} + +static void enable_cobalt_irq(unsigned int irq) /* enable_irq() */ +{ + int ent = is_co_apic(irq); + if (ent == -1) { + return; /* ALL irqs use do_cobalt_IRQ() which calls here */ + } + + /* Note: this clears the CO_APIC_MASK bit, and assumes _HI okay */ + co_apic_write(CO_APIC_LO(ent), CO_APIC_LEVEL|IRQ_VECTOR(irq)); } /* * Set the given Cobalt APIC Redirection Table entry to point * to the given IDT vector/index. */ -static void co_apic_set(int entry, int idtvec) +static void co_apic_set(int entry, int irq) { - co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec)); + printk("IRQ %d, Cobalt APIC Entry %d, IDT Vector %x: enabling\n", + irq, entry, IRQ_VECTOR(irq)); + co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL|IRQ_VECTOR(irq)); co_apic_write(CO_APIC_HI(entry), 0); - - printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec); } /* @@ -145,48 +207,39 @@ * map this to the Cobalt APIC entry where it's physically wired. * This is called via request_irq -> setup_x86_irq -> irq_desc->startup() */ -static void startup_cobalt_irq(unsigned int irq) +static void startup_cobalt_irq(unsigned int irq) /* request_irq() */ { + int ent; /* - * These "irq"'s are wired to the same Cobalt APIC entries - * for all (known) motherboard types/revs + * Protect this code from probe_irq_on/off() */ - switch (irq) { - case CO_IRQ_TIMER: co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER); - return; + if (irq_desc[irq].status & IRQ_AUTODETECT) { + return; + } - case CO_IRQ_ENET: co_apic_set(CO_APIC_ENET, CO_IRQ_ENET); - return; +#ifdef SERIAL_HACK + if (irq == 4) { /* XXX terrible hack for serial interrupt prob */ + return; /* XXX fixed on factory h/w? */ + } +#endif + ent = is_co_apic(irq); + if (ent == -1) { + return; /* Could very well be a panic */ + } - case CO_IRQ_SERIAL: return; /* XXX move to piix4-8259 "virtual" */ + co_apic_set(ent, irq); +} - case CO_IRQ_8259: co_apic_set(CO_APIC_8259, CO_IRQ_8259); - return; - - case CO_IRQ_IDE: - switch (visws_board_type) { - case VISWS_320: - switch (visws_board_rev) { - case 5: - co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE); - co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE); - return; - case 6: - co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE); - co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE); - return; - } - case VISWS_540: - switch (visws_board_rev) { - case 2: - co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE); - return; - } - } - break; - default: - panic("huh?"); +static void shutdown_cobalt_irq(unsigned int irq) /* free_irq() */ +{ +#ifdef SERIAL_HACK + if (irq == 4) { /* XXX terrible hack for serial interrupt prob */ + return; /* XXX fixed on factory h/w? */ } +#endif + printk("IRQ %d, Cobalt APIC Entry %d, IDT Vector %x: masking\n", + irq, is_co_apic(irq), IRQ_VECTOR(irq)); + disable_cobalt_irq(irq); } /* @@ -200,7 +253,8 @@ spin_lock(&irq_controller_lock); { unsigned int status; - /* XXX APIC EOI? */ + disable_cobalt_irq(irq); + apic_write(APIC_EOI, APIC_EIO_ACK); status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); action = NULL; if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { @@ -217,9 +271,6 @@ handle_IRQ_event(irq, regs, action); - (void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */ - apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */ - spin_lock(&irq_controller_lock); { unsigned int status = desc->status & ~IRQ_INPROGRESS; @@ -230,13 +281,15 @@ spin_unlock(&irq_controller_lock); } +#ifdef LEGACY_IRQS /* * PIIX4-8259 master/virtual functions to handle: * * floppy * parallel * serial - * audio (?) + * [ps2 kbd] + * [ps2 mouse] * * None of these get Cobalt APIC entries, neither do they have IDT * entries. These interrupts are purely virtual and distributed from @@ -252,6 +305,8 @@ static void startup_piix4_master_irq(unsigned int irq) { + /* irq should only ever be CO_IRQ_8259 */ + /* ICW1 */ outb(0x11, 0x20); outb(0x11, 0xa0); @@ -277,10 +332,6 @@ static void shutdown_piix4_master_irq(unsigned int irq) { - /* - * [we skip the 8259 magic here, not strictly necessary] - */ - shutdown_cobalt_irq(irq); } @@ -324,6 +375,7 @@ * handle this 'virtual interrupt' as a Cobalt one now. */ kstat.irqs[smp_processor_id()][irq]++; + kstat.irqs[smp_processor_id()][realirq]++; do_cobalt_IRQ(realirq, regs); spin_lock(&irq_controller_lock); @@ -343,14 +395,9 @@ static void enable_piix4_virtual_irq(unsigned int irq) { - /* - * assumes this irq is one of the legacy devices - */ - unsigned int mask = inb(0x21); mask &= ~(1 << irq); outb(mask, 0x21); - enable_cobalt_irq(irq); } /* @@ -358,52 +405,104 @@ */ static void disable_piix4_virtual_irq(unsigned int irq) { - unsigned int mask; - - disable_cobalt_irq(irq); - - mask = inb(0x21); + unsigned int mask = inb(0x21); mask &= ~(1 << irq); outb(mask, 0x21); } static struct irqaction master_action = { no_action, 0, 0, "PIIX4-8259", NULL, NULL }; +#endif -void init_VISWS_APIC_irqs(void) +/* + * Called from bios32.c:pcibios_fixup_devices() + * Our chance to fill in the proper irqs. + * XXX properly map bus num to _bridge_ num + * XXX a big table (indexed by bridge/slot/line) might really be easiest! + */ +int +visws_get_PCI_irq_vector(int bus, int slot, int line) +{ +#define BRIDGE_A 1 /* XXX simplistic bus numbering! */ +#define BRIDGE_B 0 /* XXX simplistic bus numbering! */ +/* XXX note how we pass the bus number as the "bridge id" -- simplistic! */ +#define BASE(bridge) ((bridge) == BRIDGE_B ? \ + CO_APIC_PCIB_BASE0 : \ + CO_APIC_PCIA_BASE0) + if (bus == BRIDGE_B && slot == 4 && line == 3) { + return CO_IRQ(CO_APIC_PIIX4_USB); /* Breaks all patterns */ + } + if (line == 0) { /* First pin spread down 1 APIC entry per slot */ + return CO_IRQ(BASE(bus) + slot); + } + /* lines 1,2,3 from any slot is shared in this twirly pattern */ + if (bus == BRIDGE_A) { + /* lines 1-3 from devices 0 1 rotate over 2 apic entries */ + return CO_IRQ(CO_APIC_PCIA_BASE123 + ((slot + (line-1)) % 2)); + } else { /* bus == BRIDGE_B */ + /* lines 1-3 from devices 0-3 rotate over 3 apic entries */ + if (slot == 0) slot = 3; /* same pattern */ + return CO_IRQ(CO_APIC_PCIA_BASE123 + ((3-slot) + (line-1) % 3)); + } + /* NOTREACHED */ +#undef BRIDGE_A +#undef BRIDGE_B +#undef BASE +} + +/* + * Maps the combination of PIIX4 8259-pair irqs plus Cobalt APIC irqs + * to CPU IDT vectors. Just initializes visws_irq_vector[] and IRQ_VEC(irq). + */ +#if (CO_IRQ_APIC0 + CO_APIC_LAST + 1) > NR_IRQS +_NR_IRQS too small +#endif + + +void init_VISWS_APIC_irqs(void) /* init_IRQ() */ { int i; - for (i = 0; i < 16; i++) { + for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0; irq_desc[i].depth = 0; - /* - * Cobalt IRQs are mapped to standard ISA - * interrupt vectors: - */ - switch (i) { - /* - * Only CO_IRQ_8259 will be raised - * externally. - */ - case CO_IRQ_8259: + /* Some legacy irqs are handled specially */ + /* This if/else "switch" must match co_apic_entry()! */ + if (i == 0) { /* IRQ 0 is system clock -- Cobalt timer */ + irq_desc[i].handler = &cobalt_irq_type; +#ifdef SERIAL_HACK + } else if (i == 4) { /* serial hack! */ + irq_desc[i].handler = &cobalt_irq_type; +#endif + } else if (i == CO_IRQ_IDE0) { + irq_desc[i].handler = &cobalt_irq_type; + } else if (i == CO_IRQ_IDE1) { + irq_desc[i].handler = &cobalt_irq_type; +#ifdef LEGACY_IRQS + } else if (i == CO_IRQ_8259) { irq_desc[i].handler = &piix4_master_irq_type; - break; - case CO_IRQ_FLOPPY: - case CO_IRQ_PARLL: + } else if (i < CO_IRQ_APIC0) { /* normal legacy */ irq_desc[i].handler = &piix4_virtual_irq_type; - break; - default: +#endif + } else if (IS_CO_APIC(i)) { irq_desc[i].handler = &cobalt_irq_type; - break; } + (void)assign_irq_vector(i); } +#ifdef LEGACY_IRQS /* * The master interrupt is always present: */ setup_x86_irq(CO_IRQ_8259, &master_action); -} +#endif + /* + * Enable IDT vectors for all valid IRQs. + * All unused IDT vectors generate 'Unexpected interrupt', + * see irq.c:strange_interrupt(). + */ + init_IRQ_MORE_TRAPS(); +} diff -Naur linux.2210/drivers/block/floppy.c linux.2210.vw/drivers/block/floppy.c --- linux.2210/drivers/block/floppy.c Wed Jun 9 16:42:49 1999 +++ linux.2210.vw/drivers/block/floppy.c Wed Jul 28 08:56:41 1999 @@ -3589,11 +3589,21 @@ /* read drive info out of physical CMOS */ drive=0; +#ifdef CONFIG_VISWS_HACKS +printk("VISWS HACK: floppy drive 0 hardwired to 1.44Mb (cmos WAR)\n"); + UDP->cmos = 4; /* drivers/block/README.fd */ +#else if (!UDP->cmos) UDP->cmos = FLOPPY0_TYPE; +#endif drive=1; +#ifdef CONFIG_VISWS_HACKS +printk("VISWS HACK: floppy drive 1 hardwired to (none) (cmos WAR)\n"); + UDP->cmos = 16; /* means "no drive" */ +#else if (!UDP->cmos && FLOPPY1_TYPE) UDP->cmos = FLOPPY1_TYPE; +#endif /* XXX */ /* additional physical CMOS drive detection should go here */ diff -Naur linux.2210/drivers/block/ide-probe.c linux.2210.vw/drivers/block/ide-probe.c --- linux.2210/drivers/block/ide-probe.c Mon Mar 22 12:44:18 1999 +++ linux.2210.vw/drivers/block/ide-probe.c Wed Jul 28 08:56:41 1999 @@ -409,8 +409,10 @@ if (hwif->noprobe) return; +#ifndef CONFIG_VISWS_HACKS if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) probe_cmos_for_drives (hwif); +#endif if ((hwif->chipset != ide_4drives || !hwif->mate->present) #if CONFIG_BLK_DEV_PDC4030 && (hwif->chipset != ide_pdc4030 || hwif->channel == 0) diff -Naur linux.2210/drivers/char/i2c.c linux.2210.vw/drivers/char/i2c.c --- linux.2210/drivers/char/i2c.c Thu Jan 14 22:53:02 1999 +++ linux.2210.vw/drivers/char/i2c.c Wed Jul 28 08:56:41 1999 @@ -387,7 +387,10 @@ return bus->i2c_read(bus, addr); i2c_start(bus); - i2c_sendbyte(bus,addr,0); + if (i2c_sendbyte(bus,addr,0)) { + i2c_stop(bus); + return -1; + } ret = i2c_readbyte(bus,1); i2c_stop(bus); return ret; diff -Naur linux.2210/drivers/char/serial.c linux.2210.vw/drivers/char/serial.c --- linux.2210/drivers/char/serial.c Tue Mar 23 13:13:58 1999 +++ linux.2210.vw/drivers/char/serial.c Wed Jul 28 08:56:41 1999 @@ -100,7 +100,7 @@ #undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT -#define RS_STROBE_TIME (10*HZ) +#define RS_STROBE_TIME (HZ/10) #define RS_ISR_PASS_LIMIT 256 #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) diff -Naur linux.2210/drivers/scsi/Config.in linux.2210.vw/drivers/scsi/Config.in --- linux.2210/drivers/scsi/Config.in Wed Jun 9 16:59:34 1999 +++ linux.2210.vw/drivers/scsi/Config.in Wed Jul 28 08:56:41 1999 @@ -122,6 +122,7 @@ dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI + dep_tristate 'Qlogic 1X80 SCSI support' CONFIG_SCSI_QLOGIC_1X80 $CONFIG_SCSI dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI diff -Naur linux.2210/drivers/scsi/Makefile linux.2210.vw/drivers/scsi/Makefile --- linux.2210/drivers/scsi/Makefile Thu Apr 29 11:53:41 1999 +++ linux.2210.vw/drivers/scsi/Makefile Wed Jul 28 08:56:41 1999 @@ -282,6 +282,16 @@ endif endif + + +ifeq ($(CONFIG_SCSI_QLOGIC_1X80),y) +L_OBJS += qla1280.o +else + ifeq ($(CONFIG_SCSI_QLOGIC_1X80),m) + M_OBJS += qla1280.o + endif +endif + ifeq ($(CONFIG_SCSI_ACARD),y) L_OBJS += atp870u.o else diff -Naur linux.2210/drivers/scsi/hosts.c linux.2210.vw/drivers/scsi/hosts.c --- linux.2210/drivers/scsi/hosts.c Mon Apr 12 09:51:04 1999 +++ linux.2210.vw/drivers/scsi/hosts.c Wed Jul 28 08:56:41 1999 @@ -175,6 +175,10 @@ #include "qlogicisp.h" #endif +#ifdef CONFIG_SCSI_QLOGIC_1X80 +#include "qla1280host.h" +#endif + #ifdef CONFIG_SCSI_QLOGIC_FC #include "qlogicfc.h" #endif @@ -487,6 +491,9 @@ #endif #ifdef CONFIG_SCSI_QLOGIC_ISP QLOGICISP, +#endif +#ifdef CONFIG_SCSI_QLOGIC_1X80 + QLA1280, #endif #ifdef CONFIG_SCSI_QLOGIC_FC QLOGICFC, diff -Naur linux.2210/drivers/scsi/isp_fw.h linux.2210.vw/drivers/scsi/isp_fw.h --- linux.2210/drivers/scsi/isp_fw.h Wed Dec 31 16:00:00 1969 +++ linux.2210.vw/drivers/scsi/isp_fw.h Wed Jul 28 08:56:41 1999 @@ -0,0 +1,1894 @@ +/************************************************************************ + * * + * --- ISP1240/1080/1280 Initiator Firmware --- * + * 32 LUN Support * + * * + ************************************************************************ + * * + * NOTICE * + * * + * COPYRIGHT 1999 QLOGIC CORPORATION * + * ALL RIGHTS RESERVED * + * * + * This computer program is CONFIDENTIAL and contains TRADE SECRETS of * + * QLOGIC CORPORATION. The receipt or possession of this program does * + * not convey any rights to reproduce or disclose its contents, or to * + * manufacture, use, or sell anything that it may describe, in whole or * + * in part, without the specific written consent of QLOGIC CORPORATION. * + * Any reproduction of this program without the express written consent * + * of QLOGIC CORPORATION is a violation of the copyright laws and may * + * subject you to civil liability and criminal prosecution. * + * * + ************************************************************************ + */ + + +/* + * Firmware Version 8.09.00 (10:38 Apr 16, 1999) + */ + +unsigned short ql12_risc_code_version = 8*1024+9; + +unsigned char ql12_firmware_version[] = {8,9,0}; + +#define QL12_FW_VERSION_STRING "8.9.0" + +unsigned short ql12_risc_code_addr01 = 0x1000 ; + +unsigned short ql12_risc_code01[] = { + 0x0078, 0x1041, 0x0000, 0x39e3, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, + 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, + 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, + 0x3132, 0x3430, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, + 0x6572, 0x7369, 0x6f6e, 0x2030, 0x382e, 0x3039, 0x2020, 0x2043, + 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, + 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, + 0x2400, 0x20c9, 0x93ff, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1080, + 0x00c0, 0x1054, 0x2071, 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, + 0x2089, 0x136a, 0x0078, 0x106d, 0x2001, 0x04fc, 0x2004, 0xa086, + 0x1280, 0x00c0, 0x1069, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2071, + 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, 0x2089, 0x13ea, 0x0078, + 0x106d, 0x20c1, 0x0020, 0x2089, 0x1312, 0x2071, 0x0010, 0x70c3, + 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, + 0x0008, 0x2001, 0x04fe, 0x70d6, 0x20c1, 0x0021, 0x2019, 0x0000, + 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, + 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, + 0xa286, 0xa5a5, 0x0040, 0x10a4, 0xa386, 0x000f, 0x0040, 0x10a0, + 0x2c6a, 0x2a5a, 0x20c1, 0x0020, 0x2019, 0x000f, 0x0078, 0x1080, + 0x2c6a, 0x2a5a, 0x0078, 0x10a2, 0x2c6a, 0x2a5a, 0x2130, 0x2128, + 0xa1a2, 0x4a00, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0xa192, 0x9400, 0x2009, 0x0000, 0x2001, 0x0032, 0x1078, 0x2078, + 0x2218, 0x2079, 0x4a00, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, + 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10bf, 0x2001, 0x04fc, 0x2004, + 0xa086, 0x1080, 0x00c0, 0x10db, 0x2071, 0x0100, 0x0d7e, 0x2069, + 0x4a40, 0x1078, 0x49ae, 0x0d7f, 0x7810, 0xc0ed, 0x7812, 0x781b, + 0x0064, 0x0078, 0x1100, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1280, + 0x00c0, 0x10fb, 0x7814, 0xc0ed, 0xc0d5, 0x7816, 0x781b, 0x0064, + 0x2071, 0x0200, 0x0d7e, 0x2069, 0x4a40, 0x1078, 0x49ae, 0x2069, + 0x4a80, 0x2071, 0x0100, 0x1078, 0x49ae, 0x7814, 0xc0d4, 0x7816, + 0x0d7f, 0x0078, 0x1100, 0x7814, 0xc0e5, 0x7816, 0x781b, 0x003c, + 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802, + 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002, + 0x2009, 0x0002, 0x2069, 0x4a40, 0x681b, 0x0003, 0x6823, 0x0007, + 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0000, + 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, 0x8109, 0x0040, + 0x1154, 0x68d3, 0x000a, 0x68c3, 0x4ac0, 0x2079, 0x4a00, 0x7814, + 0xd0e4, 0x00c0, 0x113a, 0xd0ec, 0x00c0, 0x113e, 0x68d7, 0x7329, + 0x0078, 0x1140, 0x68d7, 0x730d, 0x0078, 0x1140, 0x68d7, 0x7329, + 0x68c7, 0x4fc0, 0x68cb, 0x4ec0, 0x68cf, 0x8fc0, 0x68ab, 0x9244, + 0x68af, 0x9249, 0x68b3, 0x9244, 0x68b7, 0x9244, 0x68a7, 0x0001, + 0x2069, 0x4a80, 0x0078, 0x1114, 0x68d3, 0x000a, 0x68c3, 0x4cc0, + 0x7814, 0xd0e4, 0x00c0, 0x1160, 0x68d7, 0x7439, 0x0078, 0x1162, + 0x68d7, 0x7419, 0x68c7, 0x6fc0, 0x68cb, 0x4f40, 0x68cf, 0x90d0, + 0x68ab, 0x9249, 0x68af, 0x924e, 0x68b3, 0x9249, 0x68b7, 0x9249, + 0x68a7, 0x0001, 0x7810, 0xd0ec, 0x00c0, 0x11b8, 0x7814, 0xd0e4, + 0x00c0, 0x11aa, 0x0e7e, 0x2069, 0x4ec0, 0x2071, 0x0200, 0x70ec, + 0xd0e4, 0x00c0, 0x118b, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, + 0x2007, 0x0078, 0x1191, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, + 0x2007, 0x2069, 0x4f40, 0x2071, 0x0100, 0x70ec, 0xd0e4, 0x00c0, + 0x11a1, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, 0x2007, 0x0078, + 0x11a7, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, 0x2007, 0x0e7f, + 0x0078, 0x11d1, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x2069, 0x4ec0, + 0x1078, 0x2007, 0x2069, 0x4f40, 0x1078, 0x2007, 0x0078, 0x11d1, + 0x2069, 0x4ec0, 0x0e7e, 0x2071, 0x0100, 0x70ec, 0xd0e4, 0x00c0, + 0x11ca, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, 0x2007, 0x0e7f, + 0x0078, 0x11d1, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, 0x2007, + 0x0e7f, 0x2011, 0x0002, 0x2069, 0x4fc0, 0x2009, 0x0002, 0x20a9, + 0x0100, 0x683f, 0x0000, 0x680b, 0x0040, 0x7bc8, 0xa386, 0xfeff, + 0x00c0, 0x11e8, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x11ec, + 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x00f0, 0x11d9, + 0x8109, 0x00c0, 0x11d7, 0x8211, 0x0040, 0x11fa, 0x2069, 0x6fc0, + 0x0078, 0x11d5, 0x1078, 0x2611, 0x1078, 0x441d, 0x1078, 0x1df2, + 0x1078, 0x4957, 0x2091, 0x2100, 0x2079, 0x4a00, 0x7810, 0xd0ec, + 0x0040, 0x120e, 0x2071, 0x0020, 0x0078, 0x1210, 0x2071, 0x0050, + 0x2091, 0x2200, 0x2079, 0x4a00, 0x2071, 0x0020, 0x2091, 0x2300, + 0x2079, 0x4a00, 0x7810, 0xd0ec, 0x0040, 0x1222, 0x2079, 0x0100, + 0x0078, 0x1224, 0x2079, 0x0200, 0x2071, 0x4a40, 0x2091, 0x2400, + 0x2079, 0x0100, 0x2071, 0x4a80, 0x2091, 0x2000, 0x2079, 0x4a00, + 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, 0x2071, 0x0010, + 0x70c3, 0x0000, 0x0090, 0x1243, 0x70c0, 0xa086, 0x0002, 0x00c0, + 0x1243, 0x1078, 0x159d, 0x2039, 0x0000, 0x7810, 0xd0ec, 0x00c0, + 0x12c5, 0x1078, 0x1472, 0x78ac, 0xa005, 0x00c0, 0x1261, 0x0068, + 0x1257, 0x786c, 0xa065, 0x0040, 0x1257, 0x1078, 0x2368, 0x1078, + 0x209f, 0x0068, 0x126e, 0x786c, 0xa065, 0x0040, 0x1261, 0x1078, + 0x2368, 0x0068, 0x126e, 0x2009, 0x4a47, 0x2011, 0x4a87, 0x2104, + 0x220c, 0xa105, 0x0040, 0x126e, 0x1078, 0x1f1e, 0x2071, 0x4a40, + 0x70a4, 0xa005, 0x0040, 0x1293, 0x7450, 0xa485, 0x0000, 0x0040, + 0x1293, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, 0xa28c, 0x303d, + 0x2190, 0x1078, 0x2a9c, 0x2091, 0x8000, 0x2091, 0x303d, 0x0068, + 0x1293, 0x2079, 0x4a00, 0x786c, 0xa065, 0x0040, 0x1293, 0x2071, + 0x0010, 0x1078, 0x2368, 0x00e0, 0x129b, 0x2079, 0x4a00, 0x2071, + 0x0010, 0x1078, 0x4765, 0x2071, 0x4a80, 0x70a4, 0xa005, 0x0040, + 0x12b3, 0x7050, 0xa025, 0x0040, 0x12b3, 0x2079, 0x0100, 0x2091, + 0x8000, 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, 0x2a9c, 0x2091, + 0x8000, 0x2091, 0x303d, 0x2079, 0x4a00, 0x2071, 0x0010, 0x0068, + 0x12bf, 0x786c, 0xa065, 0x0040, 0x12bf, 0x1078, 0x2368, 0x00e0, + 0x1249, 0x1078, 0x4765, 0x0078, 0x1249, 0x1078, 0x1472, 0x78ac, + 0xa005, 0x00c0, 0x12dd, 0x0068, 0x12d3, 0x786c, 0xa065, 0x0040, + 0x12d3, 0x1078, 0x2368, 0x1078, 0x209f, 0x0068, 0x12e7, 0x786c, + 0xa065, 0x0040, 0x12dd, 0x1078, 0x2368, 0x0068, 0x12e7, 0x2009, + 0x4a47, 0x2104, 0xa005, 0x0040, 0x12e7, 0x1078, 0x1f1e, 0x2071, + 0x4a40, 0x70a4, 0xa005, 0x0040, 0x1302, 0x7450, 0xa485, 0x0000, + 0x0040, 0x1302, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d4, 0xa28c, + 0x303d, 0x2190, 0x1078, 0x2a9c, 0x2091, 0x8000, 0x2091, 0x303d, + 0x2079, 0x4a00, 0x2071, 0x0010, 0x0068, 0x130c, 0x786c, 0xa065, + 0x0040, 0x130c, 0x1078, 0x2368, 0x00e0, 0x12c5, 0x1078, 0x4765, + 0x0078, 0x12c5, 0x1332, 0x1332, 0x1334, 0x1334, 0x1341, 0x1341, + 0x1341, 0x1341, 0x134c, 0x134c, 0x1359, 0x1359, 0x1341, 0x1341, + 0x1341, 0x1341, 0x1332, 0x1332, 0x1334, 0x1334, 0x1341, 0x1341, + 0x1341, 0x1341, 0x134c, 0x134c, 0x1359, 0x1359, 0x1341, 0x1341, + 0x1341, 0x1341, 0x0078, 0x1332, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13ba, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x290b, + 0x2091, 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, + 0x8001, 0x007c, 0x138a, 0x138a, 0x138c, 0x138c, 0x1399, 0x1399, + 0x1399, 0x1399, 0x13a4, 0x13a4, 0x138c, 0x138c, 0x1399, 0x1399, + 0x1399, 0x1399, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, + 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, + 0x13a5, 0x13a5, 0x0078, 0x138a, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13c7, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x007c, 0x107e, 0x127e, 0x0d7e, + 0x0e7e, 0x0f7e, 0x007e, 0x2071, 0x0100, 0x2069, 0x4a40, 0x2079, + 0x4a00, 0x1078, 0x49ae, 0x007f, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, + 0x107f, 0x007c, 0x3c00, 0xa084, 0x0007, 0x0079, 0x13bf, 0x13d0, + 0x13d0, 0x13d2, 0x13d2, 0x13d7, 0x13d7, 0x13dc, 0x13dc, 0x3c00, + 0xa084, 0x0003, 0x0079, 0x13cc, 0x13d0, 0x13d0, 0x13e5, 0x13e5, + 0x1078, 0x28ec, 0x2091, 0x2200, 0x1078, 0x44b7, 0x007c, 0x2091, + 0x2100, 0x1078, 0x44b7, 0x007c, 0x2091, 0x2100, 0x1078, 0x44b7, + 0x2091, 0x2200, 0x1078, 0x44b7, 0x007c, 0x2091, 0x2100, 0x1078, + 0x44b7, 0x007c, 0x140a, 0x140a, 0x140c, 0x140c, 0x1419, 0x1419, + 0x1419, 0x1419, 0x1424, 0x1424, 0x1431, 0x1431, 0x1419, 0x1419, + 0x1419, 0x1419, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, + 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, + 0x1442, 0x1442, 0x0078, 0x140a, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13ba, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x290b, + 0x2091, 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, + 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, + 0x2079, 0x4a00, 0x2071, 0x0200, 0x2069, 0x4a40, 0x3d00, 0xd08c, + 0x00c0, 0x1456, 0x2069, 0x4a80, 0x2071, 0x0100, 0x1078, 0x49ae, + 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, 0x107f, 0x007f, 0x007c, 0x7008, + 0x800b, 0x00c8, 0x146d, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, + 0x146e, 0xd09c, 0x0040, 0x146d, 0x087a, 0x097a, 0x70c3, 0x4002, + 0x0078, 0x15a0, 0x0068, 0x14f7, 0x2061, 0x0000, 0x6018, 0xd084, + 0x00c0, 0x14f7, 0x7828, 0xa005, 0x00c0, 0x1482, 0x0010, 0x14f8, + 0x0078, 0x14f7, 0x7910, 0xd1f4, 0x0040, 0x148a, 0x2001, 0x4007, + 0x0078, 0x159f, 0x7914, 0xd1ec, 0x0040, 0x14a5, 0xd0fc, 0x0040, + 0x149b, 0x007e, 0x1078, 0x1d82, 0x007f, 0x0040, 0x14a5, 0x2001, + 0x4007, 0x0078, 0x159f, 0x007e, 0x1078, 0x1d72, 0x007f, 0x0040, + 0x14a5, 0x2001, 0x4007, 0x0078, 0x159f, 0x7910, 0xd0fc, 0x00c0, + 0x14af, 0x2061, 0x4a40, 0xc19c, 0xc7fc, 0x0078, 0x14b3, 0x2061, + 0x4a80, 0xc19d, 0xc7fd, 0x6064, 0xa005, 0x00c0, 0x14f7, 0x7912, + 0x6083, 0x0000, 0x7828, 0xc0fc, 0xa086, 0x0018, 0x00c0, 0x14c4, + 0x0c7e, 0x1078, 0x1b13, 0x0c7f, 0x782b, 0x0000, 0x607c, 0xa065, + 0x0040, 0x14dd, 0x0c7e, 0x609c, 0x1078, 0x1e5d, 0x0c7f, 0x609f, + 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, 0x6087, 0x0103, 0x1078, + 0x1d92, 0x00c0, 0x14f1, 0x1078, 0x1de4, 0x7810, 0xd09c, 0x00c0, + 0x14e5, 0x2061, 0x4a40, 0x0078, 0x14e9, 0x2061, 0x4a80, 0xc09c, + 0x7812, 0x607f, 0x0000, 0x60d4, 0xd0dc, 0x0040, 0x14f5, 0xc0dc, + 0x60d6, 0x2001, 0x4005, 0x0078, 0x159f, 0x0078, 0x159d, 0x007c, + 0x7810, 0xd0f4, 0x0040, 0x1500, 0x2001, 0x4007, 0x0078, 0x159f, + 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, 0xa08a, + 0x0040, 0x00c8, 0x150d, 0x0079, 0x1514, 0x2100, 0xa08a, 0x0040, + 0x00c8, 0x15ab, 0x0079, 0x1554, 0x159d, 0x15f3, 0x15bc, 0x162b, + 0x1663, 0x1663, 0x15b3, 0x1c57, 0x166e, 0x15ab, 0x15c0, 0x15c2, + 0x15c4, 0x15c6, 0x1c5c, 0x15ab, 0x167c, 0x16d4, 0x1b35, 0x1c51, + 0x15c8, 0x19a7, 0x19e9, 0x1a1f, 0x1a6b, 0x1962, 0x196f, 0x1983, + 0x1996, 0x17a4, 0x1cdc, 0x1706, 0x1713, 0x171f, 0x172b, 0x1741, + 0x174d, 0x1750, 0x175c, 0x1768, 0x1770, 0x178c, 0x1798, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x17b1, 0x17c3, 0x17df, 0x1815, 0x183d, + 0x184d, 0x1850, 0x1881, 0x18b2, 0x18c4, 0x1931, 0x1941, 0x1d32, + 0x15ab, 0x15ab, 0x15ab, 0x1951, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x1c81, 0x1c87, 0x15ab, 0x15ab, 0x15ab, 0x1c8b, 0x1cd8, + 0x15ab, 0x15ab, 0x1ce8, 0x1cf7, 0x15ed, 0x165d, 0x1676, 0x16ce, + 0x1b2f, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x1d39, 0x1c73, 0x1c7d, + 0x15ab, 0x15ab, 0x1d02, 0x1d1b, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x72ca, 0x71c6, 0x2001, 0x4006, + 0x0078, 0x159f, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, + 0x0068, 0x15a0, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, + 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001, 0x0078, 0x15a0, 0x70c3, + 0x4006, 0x0078, 0x15a0, 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, + 0x0005, 0x53a3, 0x0078, 0x159d, 0x70c4, 0x70c3, 0x0004, 0x007a, + 0x0078, 0x159d, 0x0078, 0x159d, 0x0078, 0x159d, 0x0078, 0x159d, + 0x2091, 0x8000, 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, + 0x70cf, 0x2020, 0x70d3, 0x0008, 0x2001, 0x0009, 0x70d6, 0x2079, + 0x0000, 0x781b, 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, + 0x041a, 0x2051, 0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, + 0x5000, 0x2091, 0x4080, 0x0078, 0x0418, 0x75d8, 0x74dc, 0x75da, + 0x74de, 0x0078, 0x15f6, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, + 0x73cc, 0x70c4, 0x20a0, 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, + 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, + 0x0040, 0x159d, 0xa182, 0x0040, 0x00c8, 0x1610, 0x2120, 0xa006, + 0x2008, 0x8403, 0x7012, 0x7007, 0x0004, 0x7007, 0x0001, 0x7008, + 0xd0fc, 0x0040, 0x1617, 0x7007, 0x0002, 0xa084, 0x01e0, 0x0040, + 0x1625, 0x70c3, 0x4002, 0x0078, 0x15a0, 0x24a8, 0x53a5, 0x0078, + 0x1607, 0x0078, 0x159d, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, + 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x7007, + 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x7007, + 0x0006, 0x81ff, 0x0040, 0x159d, 0xa182, 0x0040, 0x00c8, 0x164a, + 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, + 0x0001, 0x7008, 0xd0fc, 0x0040, 0x1651, 0xa084, 0x01e0, 0x0040, + 0x163f, 0x70c3, 0x4002, 0x0078, 0x15a0, 0x75d8, 0x74dc, 0x75da, + 0x74de, 0x0078, 0x162e, 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, + 0x00c0, 0x166b, 0x200a, 0x72ca, 0x0078, 0x159c, 0x70c7, 0x0008, + 0x70cb, 0x0009, 0x70cf, 0x0000, 0x0078, 0x159d, 0x75d8, 0x76dc, + 0x75da, 0x76de, 0x0078, 0x167f, 0x2029, 0x0000, 0x2530, 0x70c4, + 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, + 0x0040, 0x16c9, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0040, 0x1697, + 0x78ac, 0xc085, 0x78ae, 0x2001, 0x4005, 0x0078, 0x159f, 0x7b7e, + 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00, 0x0040, 0x16af, + 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f, 0xa118, 0xa291, + 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0078, 0x16b9, 0x8407, + 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, + 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, 0x0040, 0x16c3, + 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae, 0x0078, + 0x16cc, 0x78ac, 0xc085, 0x78ae, 0x0078, 0x159d, 0x75d8, 0x76dc, + 0x75da, 0x76de, 0x0078, 0x16d7, 0x2029, 0x0000, 0x2530, 0x70c4, + 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, + 0x0040, 0x1701, 0x8001, 0x7892, 0xa084, 0xfc00, 0x0040, 0x16ef, + 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0078, 0x159f, 0x7a9a, + 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0040, 0x16fa, 0x7a10, + 0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0078, + 0x1704, 0x78ac, 0xc0c5, 0x78ae, 0x0078, 0x159d, 0x2009, 0x0000, + 0x786c, 0xa065, 0x0040, 0x1710, 0x8108, 0x6000, 0x0078, 0x1709, + 0x7ac4, 0x0078, 0x159b, 0x2009, 0x4a48, 0x210c, 0x7810, 0xd0ec, + 0x00c0, 0x159c, 0x2011, 0x4a88, 0x2214, 0x0078, 0x159b, 0x2009, + 0x4a49, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2011, 0x4a89, + 0x2214, 0x0078, 0x159b, 0x2061, 0x4a40, 0x6128, 0x622c, 0x8214, + 0x8214, 0x8214, 0x7810, 0xd0ec, 0x00c0, 0x173f, 0x2061, 0x4a80, + 0x6328, 0x73da, 0x632c, 0x831c, 0x831c, 0x831c, 0x73de, 0x0078, + 0x159b, 0x2009, 0x4a4c, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, + 0x2011, 0x4a8c, 0x2214, 0x0078, 0x159b, 0x7918, 0x0078, 0x159c, + 0x2009, 0x4a4d, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2011, + 0x4a8d, 0x2214, 0x0078, 0x159b, 0x2009, 0x4a4e, 0x210c, 0x7810, + 0xd0ec, 0x00c0, 0x159c, 0x2011, 0x4a8e, 0x2214, 0x0078, 0x159b, + 0x7920, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x7a24, 0x0078, 0x159b, + 0x71c4, 0xd1fc, 0x00c0, 0x1778, 0x2011, 0x4ec0, 0x0078, 0x177a, + 0x2011, 0x4f40, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xa268, 0x6a00, 0x6804, 0xd09c, 0x0040, 0x1789, 0x6b08, 0x0078, + 0x178a, 0x6b0c, 0x0078, 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, + 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x159a, + 0x2061, 0x4a40, 0x6118, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2061, + 0x4a80, 0x6218, 0x0078, 0x159b, 0x77c4, 0x1078, 0x1e02, 0x2091, + 0x8000, 0x6908, 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0078, + 0x159a, 0x71c4, 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x00c8, + 0x1595, 0x1078, 0x2729, 0xa384, 0x4000, 0x0040, 0x17c1, 0xa295, + 0x0020, 0x0078, 0x159a, 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, + 0x00c8, 0x1595, 0xd1bc, 0x00c0, 0x17d2, 0x2011, 0x4a48, 0x2204, + 0x0078, 0x17d6, 0x2011, 0x4a88, 0x2204, 0xc0bd, 0x007e, 0x2100, + 0xc0bc, 0x2012, 0x1078, 0x2686, 0x017f, 0x0078, 0x159c, 0x71c4, + 0x2021, 0x4a49, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0078, 0x17ee, + 0x71c8, 0x2021, 0x4a89, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x180d, + 0x20a9, 0x0008, 0x2204, 0xa106, 0x0040, 0x17fd, 0x8210, 0x00f0, + 0x17f2, 0x71c4, 0x72c8, 0x0078, 0x1594, 0xa292, 0x180d, 0x027e, + 0x2122, 0x017f, 0x1078, 0x26a7, 0x7810, 0xd0ec, 0x00c0, 0x180b, + 0xd3fc, 0x0040, 0x17e8, 0x0078, 0x159d, 0x03e8, 0x00fa, 0x01f4, + 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x4a40, 0x6128, + 0x622c, 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, + 0x8003, 0x8003, 0x602e, 0x7810, 0xd0ec, 0x00c0, 0x183b, 0x027e, + 0x017e, 0x2061, 0x4a80, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, + 0x70d8, 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, + 0x72de, 0x017f, 0x027f, 0x0078, 0x159b, 0x2061, 0x4a40, 0x6130, + 0x70c4, 0x6032, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2061, 0x4a80, + 0x6230, 0x70c8, 0x6032, 0x0078, 0x159b, 0x7918, 0x0078, 0x159c, + 0x71c4, 0xa184, 0xffcf, 0x0040, 0x185c, 0x7810, 0xd0ec, 0x00c0, + 0x1595, 0x72c8, 0x0078, 0x1594, 0x2011, 0x4a4d, 0x2204, 0x2112, + 0x007e, 0x2019, 0x0000, 0x1078, 0x270e, 0x7810, 0xd0ec, 0x0040, + 0x186c, 0x017f, 0x0078, 0x159c, 0x71c8, 0xa184, 0xffcf, 0x0040, + 0x1875, 0x2110, 0x71c4, 0x0078, 0x1594, 0x2011, 0x4a8d, 0x2204, + 0x2112, 0x007e, 0xc3fd, 0x1078, 0x270e, 0x027f, 0x017f, 0x0078, + 0x159b, 0x71c4, 0xa182, 0x0010, 0x0048, 0x188d, 0x7810, 0xd0ec, + 0x00c0, 0x1595, 0x72c8, 0x0078, 0x1594, 0x2011, 0x4a4e, 0x2204, + 0x007e, 0x2112, 0x2019, 0x0000, 0x1078, 0x26ec, 0x7810, 0xd0ec, + 0x0040, 0x189d, 0x017f, 0x0078, 0x159c, 0x71c8, 0xa182, 0x0010, + 0x0048, 0x18a6, 0x2110, 0x71c4, 0x0078, 0x1594, 0x2011, 0x4a8e, + 0x2204, 0x007e, 0x2112, 0xc3fd, 0x1078, 0x26ec, 0x027f, 0x017f, + 0x0078, 0x159b, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x1594, + 0xa284, 0xfffd, 0x00c0, 0x1594, 0x2100, 0x7920, 0x7822, 0x2200, + 0x7a24, 0x7826, 0x0078, 0x159b, 0x71c4, 0xd1fc, 0x00c0, 0x18cc, + 0x2011, 0x4ec0, 0x0078, 0x18ce, 0x2011, 0x4f40, 0x8107, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x2019, 0x0000, 0x72c8, + 0xa284, 0x0080, 0x0040, 0x18e2, 0x6c14, 0x84ff, 0x00c0, 0x18e2, + 0x6817, 0x0040, 0xa284, 0x0040, 0x0040, 0x18ec, 0x6c10, 0x84ff, + 0x00c0, 0x18ec, 0x6813, 0x0001, 0x6800, 0x007e, 0xa226, 0x0040, + 0x1909, 0x6a02, 0xd4ec, 0x0040, 0x18f6, 0xc3a5, 0xd4e4, 0x0040, + 0x18fa, 0xc39d, 0xd4f4, 0x0040, 0x1909, 0x810f, 0xd2f4, 0x0040, + 0x1905, 0x1078, 0x276b, 0x0078, 0x1909, 0x1078, 0x2749, 0x0078, + 0x1909, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1929, 0xa2a4, 0x00ff, + 0x7814, 0xd0e4, 0x00c0, 0x191c, 0xa482, 0x0028, 0x0048, 0x1926, + 0x0040, 0x1926, 0x0078, 0x1920, 0xa482, 0x0043, 0x0048, 0x1926, + 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x1596, 0x6a0a, 0xa39d, + 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, 0x0078, + 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a14, 0x6b1c, + 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, + 0x159a, 0x70c4, 0x2061, 0x4a40, 0x6118, 0x601a, 0x7810, 0xd0ec, + 0x00c0, 0x159c, 0x70c8, 0x2061, 0x4a80, 0x6218, 0x601a, 0x0078, + 0x159b, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x1595, + 0x1078, 0x278d, 0xa384, 0x4000, 0x0040, 0x1960, 0xa295, 0x0020, + 0x0078, 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a08, + 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, + 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, + 0x6804, 0xa005, 0x0040, 0x197e, 0x1078, 0x25de, 0x2091, 0x8001, + 0x2708, 0x0078, 0x159b, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, + 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1991, 0x1078, + 0x25de, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, 0x2041, + 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, + 0x1e1d, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078, 0x159b, 0x77c4, + 0x7814, 0xd0e4, 0x00c0, 0x19bb, 0xd7fc, 0x0040, 0x19b5, 0x1078, + 0x1d82, 0x0040, 0x19bb, 0x0078, 0x159f, 0x1078, 0x1d72, 0x0040, + 0x19bb, 0x0078, 0x159f, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, + 0x1078, 0x1e9a, 0x00c0, 0x19e5, 0x6818, 0xa005, 0x0040, 0x19df, + 0x2708, 0x077e, 0x1078, 0x27bd, 0x077f, 0x00c0, 0x19df, 0x2001, + 0x0015, 0xd7fc, 0x00c0, 0x19d8, 0x2061, 0x4a40, 0x0078, 0x19db, + 0xc0fd, 0x2061, 0x4a80, 0x782a, 0x2091, 0x8001, 0x007c, 0x2091, + 0x8001, 0x2001, 0x4005, 0x0078, 0x159f, 0x2091, 0x8001, 0x0078, + 0x159d, 0x77c4, 0x7814, 0xd0e4, 0x00c0, 0x19fd, 0xd7fc, 0x0040, + 0x19f7, 0x1078, 0x1d82, 0x0040, 0x19fd, 0x0078, 0x159f, 0x1078, + 0x1d72, 0x0040, 0x19fd, 0x0078, 0x159f, 0x77c6, 0x2041, 0x0021, + 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, 0x1e1d, + 0x2009, 0x0016, 0xd7fc, 0x00c0, 0x1a11, 0x2061, 0x4a40, 0x0078, + 0x1a14, 0x2061, 0x4a80, 0xc1fd, 0x6067, 0x0003, 0x6776, 0x6083, + 0x000f, 0x792a, 0x1078, 0x25de, 0x2091, 0x8001, 0x007c, 0x77c8, + 0x77ca, 0x77c4, 0x77c6, 0x7814, 0xd0e4, 0x00c0, 0x1a36, 0xd7fc, + 0x0040, 0x1a30, 0x1078, 0x1d82, 0x0040, 0x1a36, 0x0078, 0x159f, + 0x1078, 0x1d72, 0x0040, 0x1a36, 0x0078, 0x159f, 0xa7bc, 0xff00, + 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, 0x00c0, 0x1a43, 0x2061, + 0x4a40, 0x0078, 0x1a46, 0x2061, 0x4a80, 0xc1fd, 0x6067, 0x0002, + 0x6776, 0x6083, 0x000f, 0x792a, 0x1078, 0x25de, 0x2091, 0x8001, + 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0010, 0x2091, 0x8000, + 0x70c8, 0xa005, 0x0040, 0x1a5f, 0x60d4, 0xc0fd, 0x60d6, 0x1078, + 0x1e1d, 0x70c8, 0x683e, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1a5f, + 0x2091, 0x8001, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x1a7f, 0x72c8, + 0xd284, 0x0040, 0x1a79, 0x1078, 0x1d82, 0x0040, 0x1a7f, 0x0078, + 0x159f, 0x1078, 0x1d72, 0x0040, 0x1a7f, 0x0078, 0x159f, 0x72c8, + 0x72ca, 0x78ac, 0xa084, 0x0003, 0x00c0, 0x1aaa, 0x2039, 0x0000, + 0xd284, 0x0040, 0x1a8c, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, + 0x2051, 0x0008, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6808, 0xc0d4, + 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x1a92, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, + 0x00c0, 0x1a92, 0x2091, 0x8000, 0x72c8, 0xd284, 0x00c0, 0x1abc, + 0x7810, 0xd0ec, 0x0040, 0x1ab8, 0x2069, 0x0100, 0x0078, 0x1abe, + 0x2069, 0x0200, 0x0078, 0x1abe, 0x2069, 0x0100, 0x6830, 0xd0b4, + 0x0040, 0x1ada, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, + 0x0040, 0x1acc, 0x00f0, 0x1ac6, 0x684b, 0x0009, 0x20a9, 0x0014, + 0x6848, 0xd084, 0x0040, 0x1ad6, 0x00f0, 0x1ad0, 0x20a9, 0x00fa, + 0x00f0, 0x1ad8, 0x2079, 0x4a00, 0x2009, 0x0018, 0x72c8, 0xd284, + 0x00c0, 0x1ae6, 0x2061, 0x4a40, 0x0078, 0x1ae9, 0x2061, 0x4a80, + 0xc1fd, 0x792a, 0x6067, 0x0001, 0x6083, 0x000f, 0x60a7, 0x0000, + 0x60a8, 0x60b2, 0x60b6, 0x60d4, 0xd0b4, 0x0040, 0x1b03, 0xc0b4, + 0x60d6, 0x0c7e, 0x60b8, 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, + 0x8001, 0x601a, 0x0c7f, 0x60d4, 0xa084, 0x77ff, 0x60d6, 0x78ac, + 0xc08d, 0x78ae, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0047, + 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x1b1a, 0x2069, 0x4a40, + 0x0078, 0x1b1c, 0x2069, 0x4a80, 0x78ac, 0xc08c, 0x78ae, 0xd084, + 0x00c0, 0x1b26, 0x0d7e, 0x1078, 0x1efa, 0x0d7f, 0x71c4, 0x71c6, + 0x6916, 0x81ff, 0x00c0, 0x1b2e, 0x68a7, 0x0001, 0x007c, 0x75d8, + 0x74dc, 0x75da, 0x74de, 0x0078, 0x1b38, 0x2029, 0x0000, 0x2520, + 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4a00, + 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x1078, 0x1ddb, 0x0040, 0x1c3b, + 0x20a9, 0x0005, 0x20a1, 0x4a14, 0x2091, 0x8000, 0x41a1, 0x2091, + 0x8001, 0x2009, 0x0040, 0x1078, 0x1fcf, 0x0040, 0x1b5b, 0x1078, + 0x1de4, 0x0078, 0x1c3b, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, + 0x00c0, 0x1b66, 0x007e, 0x1078, 0x234b, 0x007f, 0xa084, 0xff00, + 0x8007, 0x8009, 0x0040, 0x1bda, 0x0c7e, 0x2c68, 0x1078, 0x1ddb, + 0x0040, 0x1bac, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x1b6d, 0x609f, + 0x0000, 0x0c7f, 0x0c7e, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, + 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, + 0x7cda, 0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1bd9, + 0x2009, 0x0040, 0x1078, 0x1fcf, 0x00c0, 0x1bc3, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0002, 0x00c0, 0x1bac, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x000a, 0x00c0, 0x1ba8, 0x017e, 0x1078, 0x2347, 0x017f, + 0x2d00, 0x6002, 0x0078, 0x1b7b, 0x0c7f, 0x0c7e, 0x609c, 0x1078, + 0x1e5d, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, + 0x6008, 0xc0cd, 0x600a, 0x6004, 0x6086, 0x1078, 0x1d92, 0x1078, + 0x1de4, 0x0078, 0x1c3b, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e5d, + 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, 0x6087, + 0x0103, 0x601b, 0x0003, 0x1078, 0x1d92, 0x1078, 0x1de4, 0x0078, + 0x1c3b, 0x0c7f, 0x7814, 0xd0e4, 0x00c0, 0x1bff, 0x6114, 0xd1fc, + 0x0040, 0x1be8, 0x1078, 0x1d82, 0x0040, 0x1bff, 0x0078, 0x1bec, + 0x1078, 0x1d72, 0x0040, 0x1bff, 0x2029, 0x0000, 0x2520, 0x2009, + 0x0018, 0x73c8, 0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x1078, + 0x1d92, 0x1078, 0x1de4, 0x2001, 0x4007, 0x0078, 0x159f, 0x74c4, + 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x0e7e, 0x2009, 0x0012, + 0xd0fc, 0x00c0, 0x1c0f, 0x2071, 0x4a40, 0x0078, 0x1c12, 0x2071, + 0x4a80, 0xc1fd, 0x792a, 0x7067, 0x0005, 0x71d4, 0xa18c, 0xf77f, + 0x71d6, 0x736a, 0x726e, 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, + 0x707e, 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x1c2a, + 0x1078, 0x43c1, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, + 0x0000, 0x60b3, 0x0000, 0x6714, 0x6023, 0x0000, 0x1078, 0x25de, + 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x15a0, 0x20a9, + 0x0005, 0x2099, 0x4a14, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, + 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, + 0x007c, 0x71c4, 0x70c7, 0x0000, 0x791e, 0x0078, 0x159d, 0x71c4, + 0x71c6, 0x2168, 0x0078, 0x1c5e, 0x2069, 0x1000, 0x690c, 0xa016, + 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1c60, 0xa285, 0x0000, + 0x00c0, 0x1c6e, 0x70c3, 0x4000, 0x0078, 0x1c70, 0x70c3, 0x4003, + 0x70ca, 0x0078, 0x15a0, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, + 0x00c8, 0x1595, 0x7966, 0x0078, 0x159d, 0x7964, 0x71c6, 0x0078, + 0x159d, 0x7900, 0x71c6, 0x71c4, 0x7902, 0x0078, 0x159d, 0x7900, + 0x71c6, 0x0078, 0x159d, 0x70c4, 0xd08c, 0x0040, 0x1c94, 0x7a10, + 0xd2ec, 0x00c0, 0x1c94, 0xc08c, 0x2011, 0x0000, 0xa08c, 0x000d, + 0x0040, 0x1ca8, 0x810c, 0x0048, 0x1ca4, 0x8210, 0x810c, 0x810c, + 0x0048, 0x1ca4, 0x8210, 0x810c, 0x81ff, 0x00c0, 0x1596, 0x8210, + 0x7a0e, 0xd28c, 0x0040, 0x1cd4, 0x7910, 0xc1cd, 0x7912, 0x2009, + 0x0021, 0x2019, 0x0003, 0xd284, 0x0040, 0x1cce, 0x8108, 0x2019, + 0x0041, 0x2011, 0x924e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, + 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, + 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x9253, + 0x2112, 0x2011, 0x9273, 0x2312, 0x7904, 0x7806, 0x0078, 0x159c, + 0x7804, 0x70c6, 0x0078, 0x159d, 0x2091, 0x8000, 0x2019, 0x0000, + 0x2011, 0x0000, 0x2009, 0x0000, 0x2091, 0x8001, 0x0078, 0x159a, + 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6830, 0xa084, 0xff00, + 0x8007, 0x2010, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, + 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a34, 0x2091, 0x8001, 0x2708, + 0x0078, 0x159b, 0x77c4, 0x077e, 0xa7bc, 0xff00, 0x20a9, 0x0008, + 0x72c8, 0x8217, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6c30, 0x6a32, + 0x2091, 0x8001, 0x8738, 0x00f0, 0x1d0a, 0x077f, 0x2708, 0x8427, + 0x2410, 0x0078, 0x159b, 0x77c4, 0x077e, 0xa7bc, 0xff00, 0x20a9, + 0x0008, 0x72c8, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6c34, 0x6a36, + 0x2091, 0x8001, 0x8738, 0x00f0, 0x1d22, 0x077f, 0x2708, 0x2410, + 0x0078, 0x159b, 0x2011, 0x4a3c, 0x220c, 0x70c4, 0x2012, 0x0078, + 0x159c, 0x71c4, 0xd1fc, 0x00c0, 0x1d41, 0x2011, 0x4ec0, 0x0078, + 0x1d43, 0x2011, 0x4f40, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa268, 0x6a14, 0xd2b4, 0x0040, 0x1d52, 0x2011, 0x0001, + 0x0078, 0x1d54, 0x2011, 0x0000, 0x6b0c, 0x0078, 0x159a, 0x017e, + 0x7814, 0xd0f4, 0x0040, 0x1d64, 0x2001, 0x4007, 0x70db, 0x0000, + 0xa18d, 0x0001, 0x0078, 0x1d70, 0xd0fc, 0x0040, 0x1d6f, 0x2001, + 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d70, 0xa006, + 0x017f, 0x007c, 0x017e, 0x7814, 0xd0f4, 0x0040, 0x1d7f, 0x2001, + 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0078, 0x1d80, 0xa006, + 0x017f, 0x007c, 0x017e, 0x7814, 0xd0fc, 0x0040, 0x1d8f, 0x2001, + 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d90, 0xa006, + 0x017f, 0x007c, 0x7112, 0x721a, 0x731e, 0x7810, 0xd0c4, 0x0040, + 0x1d9b, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, + 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, 0x53a6, + 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0040, 0x1db8, 0x810f, + 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, 0x1dbb, + 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, + 0x7d10, 0xd5c4, 0x0040, 0x1dc8, 0x7b84, 0xa319, 0x7c80, 0xa421, + 0x7008, 0xd0fc, 0x0040, 0x1dc8, 0x7003, 0x0001, 0x7007, 0x0006, + 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0040, 0x1dd8, 0x7322, 0x7426, + 0xa084, 0x01e0, 0x007c, 0x7848, 0xa065, 0x0040, 0x1de3, 0x2c04, + 0x784a, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x4a00, 0x7848, + 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1def, 0x1078, 0x28ec, 0x784a, + 0x0f7f, 0x007c, 0x2011, 0x9400, 0x7a4a, 0x7bc4, 0x8319, 0x0040, + 0x1dff, 0xa280, 0x0032, 0x2012, 0x2010, 0x0078, 0x1df6, 0x2013, + 0x0000, 0x007c, 0x017e, 0x027e, 0xd7fc, 0x00c0, 0x1e0b, 0x2011, + 0x4fc0, 0x0078, 0x1e0d, 0x2011, 0x6fc0, 0xa784, 0x0f00, 0x800b, + 0xa784, 0x001f, 0x0040, 0x1e18, 0x8003, 0x8003, 0x8003, 0x8003, + 0xa105, 0xa268, 0x027f, 0x017f, 0x007c, 0x1078, 0x1e02, 0x2900, + 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, 0x690a, + 0xd7fc, 0x00c0, 0x1e2f, 0x2009, 0x4a53, 0x0078, 0x1e31, 0x2009, + 0x4a93, 0x210c, 0x6804, 0xa005, 0x0040, 0x1e41, 0xa116, 0x00c0, + 0x1e41, 0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, + 0x1e44, 0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1e59, + 0x6000, 0x6806, 0x1078, 0x1e6f, 0x1078, 0x201b, 0x6810, 0x7908, + 0x8109, 0x790a, 0x8001, 0x6812, 0x00c0, 0x1e44, 0x7910, 0xc1a5, + 0x7912, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x1e6e, + 0x2008, 0x609c, 0xa005, 0x0040, 0x1e6b, 0x2062, 0x609f, 0x0000, + 0xa065, 0x0078, 0x1e61, 0x7848, 0x794a, 0x2062, 0x007c, 0x6007, + 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005, 0x20a0, + 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022, 0x007c, + 0x0e7e, 0xd7fc, 0x00c0, 0x1e8a, 0x2071, 0x4a40, 0x2031, 0x4ac0, + 0x0078, 0x1e8e, 0x2071, 0x4a80, 0x2031, 0x4cc0, 0x7050, 0xa08c, + 0x0200, 0x00c0, 0x1e98, 0xa608, 0x2d0a, 0x8000, 0x7052, 0xa006, + 0x0e7f, 0x007c, 0x0f7e, 0xd7fc, 0x00c0, 0x1ea2, 0x2079, 0x4a40, + 0x0078, 0x1ea4, 0x2079, 0x4a80, 0x1078, 0x1e02, 0x2091, 0x8000, + 0x6804, 0x780a, 0xa065, 0x0040, 0x1ef8, 0x0078, 0x1eb6, 0x2c00, + 0x780a, 0x2060, 0x6000, 0xa065, 0x0040, 0x1ef8, 0x6010, 0xa306, + 0x00c0, 0x1eaf, 0x600c, 0xa206, 0x00c0, 0x1eaf, 0x2c28, 0x784c, + 0xac06, 0x00c0, 0x1ec5, 0x0078, 0x1ef5, 0x6804, 0xac06, 0x00c0, + 0x1ed3, 0x6000, 0x2060, 0x6806, 0xa005, 0x00c0, 0x1ed3, 0x6803, + 0x0000, 0x0078, 0x1edd, 0x6400, 0x7808, 0x2060, 0x6402, 0xa486, + 0x0000, 0x00c0, 0x1edd, 0x2c00, 0x6802, 0x2560, 0x0f7f, 0x1078, + 0x1e6f, 0x0f7e, 0x601b, 0x0005, 0x6023, 0x0020, 0x0f7f, 0x1078, + 0x201b, 0x0f7e, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, 0x6812, + 0x00c0, 0x1ef5, 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, + 0x0f7f, 0x007c, 0x077e, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0040, + 0x1f02, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, + 0x2091, 0x8000, 0x1078, 0x1e1d, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x1f0a, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, + 0x00c0, 0x1f0a, 0x2091, 0x8001, 0x077f, 0x007c, 0x2061, 0x0000, + 0x6018, 0xd084, 0x00c0, 0x1f3e, 0x7810, 0xd08c, 0x0040, 0x1f2f, + 0xc08c, 0x7812, 0xc7fc, 0x2069, 0x4a40, 0x0078, 0x1f34, 0xc08d, + 0x7812, 0x2069, 0x4a80, 0xc7fd, 0x2091, 0x8000, 0x681c, 0x681f, + 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0, 0x1f3f, 0x007c, 0xa08c, + 0xfff0, 0x0040, 0x1f45, 0x1078, 0x28ec, 0x0079, 0x1f47, 0x1f57, + 0x1f5a, 0x1f60, 0x1f64, 0x1f58, 0x1f68, 0x1f58, 0x1f58, 0x1f58, + 0x1f6e, 0x1f9f, 0x1fa3, 0x1fa9, 0x1f58, 0x1f58, 0x1f58, 0x007c, + 0x1078, 0x28ec, 0x1078, 0x1efa, 0x2001, 0x8001, 0x0078, 0x1fbe, + 0x2001, 0x8003, 0x0078, 0x1fbe, 0x2001, 0x8004, 0x0078, 0x1fbe, + 0x1078, 0x1efa, 0x2001, 0x8006, 0x0078, 0x1fbe, 0x2091, 0x8000, + 0x077e, 0xd7fc, 0x00c0, 0x1f7a, 0x2069, 0x4a40, 0x2039, 0x0009, + 0x0078, 0x1f7e, 0x2069, 0x4a80, 0x2039, 0x0009, 0x6800, 0xa086, + 0x0000, 0x0040, 0x1f88, 0x007f, 0x6f1e, 0x2091, 0x8001, 0x007c, + 0x6874, 0x077f, 0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, + 0x2051, 0x0010, 0x1078, 0x1e1d, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x1f92, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, 0x1fbe, 0x2001, + 0x800c, 0x0078, 0x1fbe, 0x1078, 0x1efa, 0x2001, 0x800d, 0x0078, + 0x1fbe, 0x7814, 0xd0e4, 0x00c0, 0x1fbc, 0xd0ec, 0x0040, 0x1fb6, + 0xd7fc, 0x0040, 0x1fb6, 0x78ec, 0x0078, 0x1fb7, 0x78e4, 0x70c6, + 0x2001, 0x800e, 0x0078, 0x1fbe, 0x0078, 0x1f58, 0x70c2, 0xd7fc, + 0x00c0, 0x1fc6, 0x70db, 0x0000, 0x0078, 0x1fc8, 0x70db, 0x0001, + 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, 0xac80, + 0x0001, 0x81ff, 0x0040, 0x1ffa, 0x2099, 0x0030, 0x20a0, 0x700c, + 0xa084, 0x03ff, 0x0040, 0x1fdc, 0x7018, 0x007e, 0x701c, 0x007e, + 0x7020, 0x007e, 0x7024, 0x007e, 0x7112, 0x81ac, 0x721a, 0x731e, + 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, 0x800b, + 0x00c8, 0x1fee, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x1ffa, + 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x007f, 0x7026, + 0x007f, 0x7022, 0x007f, 0x701e, 0x007f, 0x701a, 0x007c, 0x2011, + 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x6803, 0xfd00, 0x6807, + 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, + 0x00c0, 0x200b, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, + 0x7868, 0xa005, 0x796a, 0x0040, 0x2028, 0x2c02, 0x0078, 0x2029, + 0x796e, 0x007c, 0x0c7e, 0x2061, 0x4a00, 0x6887, 0x0103, 0x2d08, + 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x203a, 0x2d02, + 0x0078, 0x203b, 0x616e, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x2c04, + 0x786e, 0xa005, 0x00c0, 0x2045, 0x786a, 0x2091, 0x8001, 0x609c, + 0xa005, 0x0040, 0x205e, 0x0c7e, 0x2060, 0x2008, 0x609c, 0xa005, + 0x0040, 0x205a, 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, 0xa005, + 0x00c0, 0x2052, 0x7848, 0x794a, 0x2062, 0x0c7f, 0x7848, 0x2062, + 0x609f, 0x0000, 0xac85, 0x0000, 0x00c0, 0x2068, 0x1078, 0x28ec, + 0x784a, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, + 0x00c8, 0x2073, 0xa200, 0x00f0, 0x206e, 0x8086, 0x818e, 0x007c, + 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x2099, 0xa11a, 0x00c8, + 0x2099, 0x8213, 0x818d, 0x0048, 0x208c, 0xa11a, 0x00c8, 0x208d, + 0x00f0, 0x2081, 0x0078, 0x2091, 0xa11a, 0x2308, 0x8210, 0x00f0, + 0x2081, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, + 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x2095, 0x7d74, + 0x70d0, 0xa506, 0x0040, 0x2185, 0x7810, 0x2050, 0x7800, 0xd08c, + 0x0040, 0x20c1, 0xdaec, 0x0040, 0x20c1, 0x0e7e, 0x2091, 0x8000, + 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x20be, 0x7008, 0x0e7f, + 0xa086, 0x0008, 0x0040, 0x20c1, 0x0078, 0x2185, 0x0e7f, 0x0078, + 0x2185, 0x1078, 0x1ddb, 0x0040, 0x2185, 0xa046, 0x7970, 0x2500, + 0x8000, 0xa112, 0x2009, 0x0040, 0x00c8, 0x20d0, 0x0078, 0x20d7, + 0x72d0, 0xa206, 0x0040, 0x20d7, 0x8840, 0x2009, 0x0080, 0x0c7e, + 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, 0x0020, 0xac80, + 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0040, 0x20e9, 0x1078, + 0x1ddb, 0x7008, 0xd0fc, 0x0040, 0x20e9, 0x7007, 0x0002, 0x2091, + 0x8001, 0xa08c, 0x01e0, 0x00c0, 0x2120, 0x53a5, 0x8cff, 0x00c0, + 0x20fe, 0x88ff, 0x0040, 0x216f, 0x0078, 0x2108, 0x2c00, 0x788e, + 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0078, 0x216f, + 0xa046, 0x7218, 0x731c, 0xdac4, 0x0040, 0x2110, 0x7420, 0x7524, + 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, 0x0000, 0xa5ab, 0x0000, + 0x721a, 0x731e, 0xdac4, 0x0040, 0x2120, 0x7422, 0x7526, 0xa006, + 0x7007, 0x0004, 0x0040, 0x216f, 0x8cff, 0x0040, 0x2129, 0x1078, + 0x1de4, 0x0c7f, 0x1078, 0x1de4, 0xa046, 0x7888, 0x8000, 0x788a, + 0xa086, 0x0002, 0x0040, 0x214f, 0x7a7c, 0x7b78, 0xdac4, 0x0040, + 0x213b, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, 0xa210, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, 0x731e, + 0xdac4, 0x0040, 0x2185, 0x7422, 0x7526, 0x0078, 0x2185, 0x6014, + 0xd0fc, 0x00c0, 0x2157, 0x2069, 0x4a40, 0x0078, 0x2159, 0x2069, + 0x4a80, 0x2091, 0x8000, 0x681f, 0x0002, 0x88ff, 0x0040, 0x2165, + 0xa046, 0x788c, 0x2060, 0x0078, 0x214f, 0x788b, 0x0000, 0x78ac, + 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0078, 0x2185, 0x0c7f, + 0x788b, 0x0000, 0x1078, 0x2319, 0x6004, 0xa084, 0x000f, 0x1078, + 0x2186, 0x88ff, 0x0040, 0x2183, 0x788c, 0x2060, 0x6004, 0xa084, + 0x000f, 0x1078, 0x2186, 0x0078, 0x209f, 0x007c, 0x0079, 0x2188, + 0x2198, 0x21b6, 0x21d4, 0x2198, 0x21e5, 0x21a9, 0x2198, 0x2198, + 0x2198, 0x21b4, 0x21d2, 0x2198, 0x2198, 0x2198, 0x2198, 0x2198, + 0x2039, 0x0400, 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, + 0x1078, 0x2228, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, 0x2303, + 0x007c, 0x78bc, 0xd0c4, 0x0040, 0x21af, 0x0078, 0x2198, 0x601c, + 0xc0bd, 0x601e, 0x0078, 0x21bc, 0x1078, 0x234b, 0x78bc, 0xd0c4, + 0x0040, 0x21bc, 0x0078, 0x2198, 0x78bf, 0x0000, 0x6004, 0x8007, + 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0040, 0x21cf, 0x1078, 0x2228, + 0x0040, 0x21cf, 0x78bc, 0xc0c5, 0x78be, 0x0078, 0x21d1, 0x0078, + 0x2247, 0x007c, 0x1078, 0x2347, 0x78bc, 0xa08c, 0x0e00, 0x00c0, + 0x21dc, 0xd0c4, 0x00c0, 0x21de, 0x0078, 0x2198, 0x1078, 0x2228, + 0x00c0, 0x21e4, 0x0078, 0x2247, 0x007c, 0x78bc, 0xd0c4, 0x0040, + 0x21eb, 0x0078, 0x2198, 0x78bf, 0x0000, 0x6714, 0x2011, 0x0001, + 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, 0x220b, 0xa7bc, + 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040, 0x220b, 0xa7bc, + 0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0040, + 0x220b, 0x0078, 0x2225, 0x1078, 0x1e02, 0x2d00, 0x2091, 0x8000, + 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, + 0xade8, 0x0010, 0x2091, 0x8001, 0x00f0, 0x220e, 0x8211, 0x0040, + 0x2225, 0x20a9, 0x0100, 0x0078, 0x220e, 0x1078, 0x1de4, 0x007c, + 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, 0x00c0, 0x2233, + 0x78ba, 0x0078, 0x223b, 0x689e, 0x2d00, 0x6002, 0x78b8, 0xad06, + 0x00c0, 0x223b, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x00c0, 0x2246, + 0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x007c, 0x0e7e, + 0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, + 0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0040, 0x225a, + 0x1078, 0x43c1, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, + 0x4a80, 0xd7fc, 0x00c0, 0x2266, 0x2071, 0x4a40, 0xa784, 0x0f00, + 0x800b, 0xa784, 0x001f, 0x0040, 0x2271, 0x8003, 0x8003, 0x8003, + 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, 0x8007, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, 0x60c2, 0x2091, 0x8000, + 0x7810, 0xd0f4, 0x00c0, 0x228b, 0x6e08, 0xd684, 0x0040, 0x22a1, + 0xd9fc, 0x00c0, 0x22a1, 0x2091, 0x8001, 0x1078, 0x1e6f, 0x2091, + 0x8000, 0x1078, 0x201b, 0x2091, 0x8001, 0x7814, 0xd0e4, 0x00c0, + 0x2301, 0x7810, 0xd0f4, 0x0040, 0x2301, 0x601b, 0x0021, 0x0078, + 0x2301, 0x6024, 0xa096, 0x0001, 0x00c0, 0x22a8, 0x8000, 0x6026, + 0x6a10, 0x6814, 0xa202, 0x0048, 0x22bb, 0x0040, 0x22bb, 0x2091, + 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, + 0x2303, 0x0078, 0x2301, 0x2c08, 0xd9fc, 0x0040, 0x22de, 0x6800, + 0xa065, 0x0040, 0x22de, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0040, + 0x22d9, 0x704c, 0xa206, 0x00c0, 0x22d9, 0x6b04, 0x2160, 0x2304, + 0x6002, 0xa005, 0x00c0, 0x22d5, 0x6902, 0x2260, 0x6102, 0x0078, + 0x22ea, 0x2160, 0x6202, 0x6906, 0x0078, 0x22ea, 0x6800, 0x6902, + 0xa065, 0x0040, 0x22e6, 0x6102, 0x0078, 0x22e7, 0x6906, 0x2160, + 0x6003, 0x0000, 0x2160, 0xd9fc, 0x0040, 0x22f1, 0xa6b4, 0xfffc, + 0x6e0a, 0x6810, 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, + 0x8001, 0xd6b4, 0x0040, 0x2301, 0xa6b6, 0x0040, 0x6e0a, 0x1078, + 0x1e80, 0x0e7f, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, + 0x1078, 0x201b, 0x2091, 0x8001, 0x78b8, 0xa065, 0x0040, 0x2316, + 0x609c, 0x78ba, 0x609f, 0x0000, 0x0078, 0x2303, 0x78b6, 0x78ba, + 0x007c, 0x7970, 0x7874, 0x2818, 0xd384, 0x0040, 0x2323, 0x8000, + 0xa112, 0x0048, 0x2328, 0x8000, 0xa112, 0x00c8, 0x2338, 0xc384, + 0x7a7c, 0x721a, 0x7a78, 0x721e, 0xdac4, 0x0040, 0x2333, 0x7a84, + 0x7222, 0x7a80, 0x7226, 0xa006, 0xd384, 0x0040, 0x2338, 0x8000, + 0x7876, 0x70d2, 0x781c, 0xa005, 0x0040, 0x2346, 0x8001, 0x781e, + 0x00c0, 0x2346, 0x0068, 0x2346, 0x2091, 0x4080, 0x007c, 0x2039, + 0x235f, 0x0078, 0x234d, 0x2039, 0x2365, 0x2704, 0xa005, 0x0040, + 0x235e, 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, 0x680a, 0x690c, + 0x6814, 0x6916, 0x680e, 0x8738, 0x0078, 0x234d, 0x007c, 0x0003, + 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, + 0x2041, 0x0000, 0x780c, 0x0079, 0x236d, 0x2535, 0x2508, 0x2371, + 0x23e5, 0x2039, 0x9274, 0x2734, 0x7d10, 0x0078, 0x238c, 0x6084, + 0xa086, 0x0103, 0x00c0, 0x23ce, 0x6114, 0x6018, 0xa105, 0x00c0, + 0x23ce, 0x8603, 0xa080, 0x9255, 0x620c, 0x2202, 0x8000, 0x6210, + 0x2202, 0x1078, 0x203d, 0x8630, 0xa68e, 0x000f, 0x0040, 0x2454, + 0x786c, 0xa065, 0x00c0, 0x2377, 0x7808, 0xa602, 0x00c8, 0x239d, + 0xd5ac, 0x00c0, 0x239d, 0x263a, 0x007c, 0xa682, 0x0003, 0x00c8, + 0x2454, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, + 0x23c9, 0x2011, 0x9255, 0x2204, 0x70c6, 0x8210, 0x2204, 0x70ca, + 0xd684, 0x00c0, 0x23b9, 0x8210, 0x2204, 0x70da, 0x8210, 0x2204, + 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, + 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, 0x203b, 0x0000, + 0x007c, 0x7810, 0xc0ad, 0x7812, 0x0078, 0x2454, 0x263a, 0x1078, + 0x253f, 0x00c0, 0x254e, 0x786c, 0xa065, 0x00c0, 0x2377, 0x2091, + 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x23e0, 0xc0ad, + 0x7812, 0x2091, 0x8001, 0x0078, 0x254e, 0x2039, 0x9274, 0x2734, + 0x7d10, 0x0078, 0x23fc, 0x6084, 0xa086, 0x0103, 0x00c0, 0x243d, + 0x6114, 0x6018, 0xa105, 0x00c0, 0x243d, 0xa680, 0x9255, 0x620c, + 0x2202, 0x1078, 0x203d, 0x8630, 0xa68e, 0x001e, 0x0040, 0x2454, + 0x786c, 0xa065, 0x00c0, 0x23eb, 0x7808, 0xa602, 0x00c8, 0x240d, + 0xd5ac, 0x00c0, 0x240d, 0x263a, 0x007c, 0xa682, 0x0006, 0x00c8, + 0x2454, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, + 0x2438, 0x2011, 0x9255, 0x2009, 0x924e, 0x26a8, 0x211c, 0x2204, + 0x201a, 0x8108, 0x8210, 0x00f0, 0x241e, 0xa685, 0x8030, 0x70c2, + 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, + 0x2091, 0x8001, 0xa006, 0x2009, 0x9275, 0x200a, 0x203a, 0x007c, + 0x7810, 0xc0ad, 0x7812, 0x0078, 0x2454, 0x263a, 0x1078, 0x253f, + 0x00c0, 0x254e, 0x786c, 0xa065, 0x00c0, 0x23eb, 0x2091, 0x8000, + 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x244f, 0xc0ad, 0x7812, + 0x2091, 0x8001, 0x0078, 0x254e, 0x2091, 0x8000, 0x7007, 0x0004, + 0x7994, 0x70d4, 0xa102, 0x0048, 0x2465, 0x0040, 0x246f, 0x7b90, + 0xa302, 0x00c0, 0x246f, 0x0078, 0x2468, 0x8002, 0x00c0, 0x246f, + 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x007c, 0xa184, + 0xff00, 0x0040, 0x247c, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, + 0x8007, 0xa100, 0x0078, 0x247f, 0x8107, 0x8004, 0x8004, 0x7a9c, + 0xa210, 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0040, + 0x248f, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, + 0x0030, 0x7003, 0x0000, 0x2009, 0x9254, 0x260a, 0x8109, 0x2198, + 0x2104, 0xd084, 0x0040, 0x249d, 0x8633, 0xa6b0, 0x0002, 0x26a8, + 0x53a6, 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, + 0xa10a, 0x00c8, 0x24ac, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, + 0x0040, 0x24bb, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, + 0xa100, 0x0078, 0x24be, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, + 0x7a78, 0xa006, 0xa211, 0xd4c4, 0x0040, 0x24ca, 0x7b84, 0xa319, + 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0040, 0x24ca, 0xa084, 0x01e0, + 0x0040, 0x24ef, 0x7d10, 0x2031, 0x9254, 0x2634, 0x78a8, 0x8000, + 0x78aa, 0xd08c, 0x00c0, 0x24e4, 0x7007, 0x0006, 0x7004, 0xd094, + 0x00c0, 0x24de, 0x0078, 0x2456, 0x2069, 0x4a47, 0x206b, 0x0003, + 0x78ac, 0xa085, 0x0300, 0x78ae, 0xa006, 0x0078, 0x24f8, 0x2030, + 0x75d6, 0x2091, 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, + 0x2091, 0x8001, 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, + 0x711a, 0x721e, 0xd5c4, 0x0040, 0x2507, 0x7322, 0x7426, 0x007c, + 0x6084, 0xa086, 0x0103, 0x00c0, 0x252b, 0x6114, 0x6018, 0xa105, + 0x00c0, 0x252b, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x252b, + 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, + 0x2091, 0x4080, 0x1078, 0x203d, 0x0068, 0x252a, 0x786c, 0xa065, + 0x00c0, 0x2508, 0x007c, 0x1078, 0x253f, 0x00c0, 0x254e, 0x786c, + 0xa065, 0x00c0, 0x2508, 0x0078, 0x254e, 0x1078, 0x253f, 0x00c0, + 0x254e, 0x786c, 0xa065, 0x00c0, 0x2535, 0x0078, 0x254e, 0x1078, + 0x2554, 0x00c0, 0x2546, 0xa085, 0x0001, 0x007c, 0x1078, 0x2563, + 0x00c0, 0x254c, 0x2041, 0x0001, 0x7d10, 0x007c, 0x88ff, 0x0040, + 0x2553, 0x2091, 0x4080, 0x007c, 0x7b90, 0x7994, 0x70d4, 0xa102, + 0x00c0, 0x255d, 0xa385, 0x0000, 0x007c, 0x0048, 0x2561, 0xa302, + 0x007c, 0x8002, 0x007c, 0x7810, 0xd0ec, 0x0040, 0x257b, 0x0e7e, + 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2578, + 0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040, 0x257b, 0x0078, 0x25cc, + 0x0e7f, 0x0078, 0x25cc, 0xa184, 0xff00, 0x0040, 0x2588, 0x810f, + 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, 0x258b, + 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa210, + 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, 0xa005, + 0x0040, 0x259c, 0x2009, 0x0040, 0x1078, 0x1d92, 0x0040, 0x25be, + 0x78a8, 0x8000, 0x78aa, 0xd08c, 0x00c0, 0x25cc, 0x6014, 0xd0fc, + 0x00c0, 0x25ae, 0x2069, 0x4a40, 0x0078, 0x25b0, 0x2069, 0x4a80, + 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab, 0x0000, 0x78ac, 0xa085, + 0x0300, 0x78ae, 0x2091, 0x8001, 0x0078, 0x25cc, 0x78ab, 0x0000, + 0x1078, 0x203d, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8, 0x25c9, + 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, + 0x007c, 0x2138, 0xd7fc, 0x00c0, 0x25d9, 0x2009, 0x4a59, 0x0078, + 0x25db, 0x2009, 0x4a99, 0x2091, 0x8000, 0x200a, 0x0f7e, 0xd7fc, + 0x00c0, 0x25f2, 0x2009, 0x4a40, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x0040, 0x25ee, 0x2079, 0x0100, 0x0078, 0x25f6, 0x2079, 0x0200, + 0x0078, 0x25f6, 0x2009, 0x4a80, 0x2079, 0x0100, 0x2104, 0xa086, + 0x0000, 0x00c0, 0x260f, 0xd7fc, 0x00c0, 0x2602, 0x2009, 0x4a45, + 0x0078, 0x2604, 0x2009, 0x4a85, 0x2104, 0xa005, 0x00c0, 0x260f, + 0x7830, 0xa084, 0x00c0, 0x00c0, 0x260f, 0x781b, 0x0045, 0x0f7f, + 0x007c, 0x2009, 0x0002, 0x2069, 0x4a00, 0x6810, 0xd0ec, 0x00c0, + 0x2672, 0x2071, 0x4a80, 0x2079, 0x0100, 0x2021, 0x4cbf, 0x784b, + 0x000f, 0x2019, 0x4205, 0xd184, 0x0040, 0x2632, 0x6810, 0xd0ec, + 0x0040, 0x262e, 0x20a1, 0x012b, 0x0078, 0x2634, 0x20a1, 0x022b, + 0x0078, 0x2634, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, 0x2641, + 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, 0x0078, + 0x2634, 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, + 0x8020, 0x00f0, 0x2645, 0x7003, 0x0000, 0x017e, 0xd18c, 0x2009, + 0x0000, 0x0040, 0x2654, 0xc1bd, 0x1078, 0x283d, 0x017f, 0x7020, + 0xa084, 0x000f, 0x007e, 0x6814, 0xd0e4, 0x007f, 0x00c0, 0x2664, + 0xa085, 0x6340, 0x0078, 0x2666, 0xa085, 0x62c0, 0x7806, 0x780f, + 0x9200, 0x7843, 0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7456, + 0x7053, 0x0000, 0x8109, 0x0040, 0x2685, 0x2071, 0x4a40, 0x6810, + 0xd0ec, 0x0040, 0x267f, 0x2079, 0x0100, 0x0078, 0x2681, 0x2079, + 0x0200, 0x2021, 0x4abf, 0x0078, 0x261f, 0x007c, 0x017e, 0xd1bc, + 0x00c0, 0x269a, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x2696, 0x2011, 0x0101, 0x0078, 0x269c, 0x2011, 0x0201, + 0x0078, 0x269c, 0x2011, 0x0101, 0xa18c, 0x000f, 0x2204, 0xa084, + 0xfff0, 0xa105, 0x2012, 0x017f, 0x1078, 0x283d, 0x007c, 0xd3fc, + 0x00c0, 0x26ba, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x26b6, 0x2011, 0x0101, 0x0078, 0x26bc, 0x2011, 0x0201, + 0x0078, 0x26bc, 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x00f0, + 0x26be, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, + 0x007c, 0x2019, 0x0002, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x0040, + 0x26d6, 0x8319, 0x2009, 0x0101, 0x0078, 0x26d8, 0x2009, 0x0101, + 0x20a9, 0x0005, 0x8213, 0x00f0, 0x26da, 0xa294, 0x00e0, 0x2104, + 0xa084, 0xff1f, 0xa205, 0x200a, 0x8319, 0x0040, 0x26eb, 0x2009, + 0x0201, 0x0078, 0x26d8, 0x007c, 0xd3fc, 0x00c0, 0x26ff, 0x007e, + 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x26fb, 0x2011, + 0x0101, 0x0078, 0x2701, 0x2011, 0x0201, 0x0078, 0x2701, 0x2011, + 0x0101, 0x20a9, 0x000c, 0x810b, 0x00f0, 0x2703, 0xa18c, 0xf000, + 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x007c, 0xd3fc, 0x00c0, + 0x2721, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x271d, 0x2011, 0x0102, 0x0078, 0x2723, 0x2011, 0x0202, 0x0078, + 0x2723, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, + 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x273d, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2739, 0x2061, 0x0100, 0x0078, + 0x273f, 0x2061, 0x0200, 0x0078, 0x273f, 0x2061, 0x0100, 0xc1bc, + 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x62ac, 0x63ac, 0x0c7f, + 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x275d, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2759, 0x2061, 0x0100, 0x0078, + 0x275f, 0x2061, 0x0200, 0x0078, 0x275f, 0x2061, 0x0100, 0xc1bc, + 0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, + 0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x277f, 0x007e, + 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x277b, 0x2061, + 0x0100, 0x0078, 0x2781, 0x2061, 0x0200, 0x0078, 0x2781, 0x2061, + 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, + 0xa085, 0x0020, 0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, + 0x27a1, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x279d, 0x2061, 0x0100, 0x0078, 0x27a3, 0x2061, 0x0200, 0x0078, + 0x27a3, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, + 0x609a, 0x60a4, 0xa28c, 0x0020, 0x0040, 0x27b1, 0xc2ac, 0xa39d, + 0x4000, 0xc3fc, 0xd3b4, 0x00c0, 0x27b6, 0xc3fd, 0x62ae, 0x2010, + 0x60a4, 0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, + 0x0e7e, 0x6818, 0xa005, 0x0040, 0x281b, 0xd1fc, 0x0040, 0x27cc, + 0x2061, 0x91d0, 0x0078, 0x27ce, 0x2061, 0x90c0, 0x1078, 0x2823, + 0x0040, 0x2801, 0x20a9, 0x0101, 0xd1fc, 0x0040, 0x27db, 0x2061, + 0x90d0, 0x0078, 0x27dd, 0x2061, 0x8fc0, 0x0c7e, 0x1078, 0x2823, + 0x0040, 0x27e8, 0x0c7f, 0x8c60, 0x00f0, 0x27dd, 0x0078, 0x281b, + 0x007f, 0xd1fc, 0x0040, 0x27f2, 0xa082, 0x90d0, 0x2071, 0x4a80, + 0x0078, 0x27f6, 0xa082, 0x8fc0, 0x2071, 0x4a40, 0x707a, 0x7176, + 0x2001, 0x0004, 0x7066, 0x7083, 0x000f, 0x1078, 0x25d1, 0x0078, + 0x2817, 0xd1fc, 0x00c0, 0x2808, 0x2071, 0x4a40, 0x0078, 0x280a, + 0x2071, 0x4a80, 0x6020, 0xc0dd, 0x6022, 0x7176, 0x2c00, 0x707e, + 0x2001, 0x0006, 0x7066, 0x7083, 0x000f, 0x1078, 0x25d1, 0x2001, + 0x0000, 0x0078, 0x281d, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, + 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040, 0x283a, 0x2060, + 0x6010, 0xa306, 0x00c0, 0x2837, 0x600c, 0xa206, 0x00c0, 0x2837, + 0x6014, 0xa106, 0x00c0, 0x2837, 0xa006, 0x0078, 0x283c, 0x6000, + 0x0078, 0x2824, 0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x017e, + 0xd1bc, 0x00c0, 0x2855, 0x2079, 0x4a40, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2851, 0x2071, 0x0100, 0x0078, + 0x2859, 0x2071, 0x0200, 0x0078, 0x2859, 0x2079, 0x4a80, 0x2071, + 0x0100, 0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x00c0, 0x2863, + 0x017f, 0x0078, 0x287e, 0x810b, 0x810b, 0x810b, 0x810b, 0x007f, + 0xd0bc, 0x00c0, 0x287b, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x2877, 0xa18d, 0x0f00, 0x0078, 0x287d, 0xa18d, + 0x0f00, 0x0078, 0x287d, 0xa18d, 0x0800, 0x2104, 0x0e7f, 0x0f7f, + 0x007c, 0x0e7e, 0x2001, 0x4a01, 0x2004, 0xd0ac, 0x00c0, 0x28ea, + 0x68e4, 0xd0ac, 0x0040, 0x28ea, 0xa084, 0x0006, 0x00c0, 0x28ea, + 0x6014, 0xd0fc, 0x00c0, 0x2898, 0x2071, 0x4ec0, 0x0078, 0x289a, + 0x2071, 0x4f40, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xae70, 0x7004, 0xa084, 0x000a, 0x00c0, 0x28ea, 0x7108, 0xa194, + 0xff00, 0x0040, 0x28ea, 0xa18c, 0x00ff, 0x2001, 0x000a, 0xa106, + 0x0040, 0x28cd, 0x2001, 0x000c, 0xa106, 0x0040, 0x28d1, 0x2001, + 0x0012, 0xa106, 0x0040, 0x28d5, 0x2001, 0x0014, 0xa106, 0x0040, + 0x28d9, 0x2001, 0x0019, 0xa106, 0x0040, 0x28dd, 0x2001, 0x0032, + 0xa106, 0x0040, 0x28e1, 0x0078, 0x28e5, 0x2009, 0x000c, 0x0078, + 0x28e7, 0x2009, 0x0012, 0x0078, 0x28e7, 0x2009, 0x0014, 0x0078, + 0x28e7, 0x2009, 0x0019, 0x0078, 0x28e7, 0x2009, 0x0020, 0x0078, + 0x28e7, 0x2009, 0x003f, 0x0078, 0x28e7, 0x2011, 0x0000, 0x2100, + 0xa205, 0x700a, 0x0e7f, 0x007c, 0x0068, 0x28ec, 0x2091, 0x8000, + 0x2071, 0x0000, 0x007e, 0x7018, 0xd084, 0x00c0, 0x28f3, 0x007f, + 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, + 0x0809, 0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, + 0x4080, 0x0078, 0x2909, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, + 0x708e, 0x7592, 0x7496, 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, + 0x0040, 0x2920, 0xa784, 0x007d, 0x00c0, 0x417b, 0x1078, 0x28ec, + 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x292b, 0xa3a6, 0x0007, + 0x00c0, 0x28ec, 0x2418, 0x8507, 0xa084, 0x000f, 0x0079, 0x2930, + 0x2f45, 0x3035, 0x3060, 0x32c1, 0x363b, 0x36a1, 0x3741, 0x37bd, + 0x38a1, 0x398a, 0x2943, 0x2940, 0x2d2a, 0x2e43, 0x360e, 0x2940, + 0x1078, 0x28ec, 0x007c, 0xa006, 0x0078, 0x294d, 0x7808, 0xc08d, + 0x780a, 0xa006, 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, 0xa005, + 0x00c0, 0x2a64, 0x7064, 0xa084, 0x0007, 0x0079, 0x2957, 0x295f, + 0x29cf, 0x29d8, 0x29e3, 0x29ee, 0x2a4a, 0x29f9, 0x29cf, 0x7830, + 0xd0bc, 0x00c0, 0x2942, 0x71d4, 0xd1b4, 0x00c0, 0x29ac, 0x70a4, + 0xa086, 0x0001, 0x0040, 0x2942, 0x70b4, 0xa06d, 0x6800, 0xa065, + 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, + 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0040, 0x2982, 0x69bc, + 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0010, 0x0078, + 0x2bbd, 0x7060, 0xa005, 0x00c0, 0x2942, 0x0c7e, 0x0d7e, 0x70b4, + 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, + 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, + 0x0040, 0x29a5, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, + 0x2001, 0x0020, 0x0078, 0x2bbd, 0x1078, 0x411c, 0x00c0, 0x2942, + 0x781b, 0x005b, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x68bc, + 0x7042, 0xc1b4, 0x71d6, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x7003, + 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0x1078, + 0x411c, 0x00c0, 0x29d7, 0x781b, 0x0047, 0x7003, 0x0004, 0x007c, + 0x1078, 0x411c, 0x00c0, 0x29e2, 0x2011, 0x000c, 0x1078, 0x2a09, + 0x7003, 0x0004, 0x007c, 0x1078, 0x411c, 0x00c0, 0x29ed, 0x2011, + 0x0006, 0x1078, 0x2a09, 0x7003, 0x0004, 0x007c, 0x1078, 0x411c, + 0x00c0, 0x29f8, 0x2011, 0x000d, 0x1078, 0x2a09, 0x7003, 0x0004, + 0x007c, 0x1078, 0x411c, 0x00c0, 0x2a08, 0x2011, 0x0006, 0x1078, + 0x2a09, 0x707c, 0x707f, 0x0000, 0x2068, 0x704e, 0x7003, 0x0001, + 0x007c, 0x7174, 0xc1fc, 0x8107, 0x7882, 0x789b, 0x0010, 0xa286, + 0x000c, 0x00c0, 0x2a18, 0x7aaa, 0x2001, 0x0001, 0x0078, 0x2a2d, + 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, 0x000d, 0x0040, + 0x2a26, 0x7aaa, 0x2001, 0x0002, 0x0078, 0x2a2d, 0x78ab, 0x0020, + 0x7178, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, 0x78aa, + 0x785b, 0x0004, 0x781b, 0x0108, 0x1078, 0x4131, 0x7083, 0x000f, + 0x70d4, 0xd0b4, 0x0040, 0x2a49, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x007c, 0x1078, 0x411c, 0x00c0, 0x2942, 0x707c, 0x2068, + 0x7774, 0x1078, 0x3fe1, 0x2c50, 0x1078, 0x41f0, 0x789b, 0x0010, + 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, + 0x2001, 0x0004, 0x0078, 0x2bc3, 0x1078, 0x411c, 0x00c0, 0x2942, + 0x789b, 0x0010, 0x7060, 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0040, + 0x2a7e, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x1078, 0x3fe1, + 0x2c50, 0x1078, 0x41f0, 0x6824, 0xa005, 0x0040, 0x2a8f, 0xa082, + 0x0006, 0x0048, 0x2a8d, 0x0078, 0x2a8f, 0x6827, 0x0005, 0x6814, + 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, + 0x2001, 0x0003, 0x0078, 0x2bc3, 0xc28d, 0x72d6, 0x72c0, 0xa200, + 0xa015, 0x7154, 0x8108, 0xa12a, 0x0048, 0x2aa7, 0x71c0, 0x2164, + 0x6504, 0x85ff, 0x00c0, 0x2abe, 0x7156, 0x8421, 0x00c0, 0x2aa2, + 0x70d4, 0xd08c, 0x0040, 0x2aba, 0x70d0, 0xa005, 0x00c0, 0x2aba, + 0x70d3, 0x000a, 0x007c, 0x2200, 0x0078, 0x2aac, 0x70d4, 0xc08c, + 0x70d6, 0x70d3, 0x0000, 0x603c, 0xa005, 0x00c0, 0x2abb, 0x6708, + 0xa784, 0x073f, 0x0040, 0x2aed, 0xd7d4, 0x00c0, 0x2abb, 0xa784, + 0x0021, 0x00c0, 0x2abb, 0xa784, 0x0002, 0x0040, 0x2ade, 0xa784, + 0x0004, 0x0040, 0x2abb, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, + 0x00c0, 0x2abb, 0xa784, 0x0100, 0x0040, 0x2aed, 0x6018, 0xa005, + 0x00c0, 0x2abb, 0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, + 0x6e1c, 0xa684, 0x000e, 0x6318, 0x0040, 0x2afe, 0x601c, 0xa302, + 0x0048, 0x2b01, 0x0040, 0x2b01, 0x0078, 0x2abb, 0x83ff, 0x00c0, + 0x2abb, 0x2d58, 0x2c50, 0x7156, 0xd7bc, 0x00c0, 0x2b09, 0x7028, + 0x6022, 0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, + 0x2041, 0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, + 0x0040, 0x2b1d, 0xd684, 0x0040, 0x2b1f, 0xa39c, 0xffbf, 0xd6a4, + 0x0040, 0x2b24, 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2b6f, + 0xc7a5, 0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, 0x00c0, + 0x2b43, 0x70d4, 0xd0b4, 0x00c0, 0x2b43, 0x7000, 0xa082, 0x0002, + 0x00c8, 0x2b43, 0x7830, 0xd0bc, 0x00c0, 0x2b43, 0x789b, 0x0010, + 0x7baa, 0x0078, 0x2bbb, 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, + 0x0005, 0x70ac, 0xa606, 0x00c0, 0x2b4e, 0x76a8, 0x76b2, 0x2c3a, + 0x8738, 0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, + 0x7830, 0xd0bc, 0x0040, 0x2b66, 0x2091, 0x8000, 0x2091, 0x303d, + 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, + 0x0040, 0x2b6e, 0x8421, 0x2200, 0x00c0, 0x2aa1, 0x007c, 0xd1dc, + 0x0040, 0x3be5, 0x2029, 0x0020, 0xd69c, 0x00c0, 0x2b7c, 0x8528, + 0xd68c, 0x00c0, 0x2b7c, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, + 0xa18c, 0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0040, 0x2b9b, + 0x6014, 0xa706, 0x00c0, 0x2b84, 0x60b8, 0x8001, 0x60ba, 0x00c0, + 0x2b7f, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, + 0x00c0, 0x2aa1, 0x007c, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, + 0x8840, 0x6008, 0xc0d5, 0x600a, 0x77a4, 0xa786, 0x0001, 0x00c0, + 0x2b43, 0x70d4, 0xd0b4, 0x00c0, 0x2b43, 0x7000, 0xa082, 0x0002, + 0x00c8, 0x2b43, 0x7830, 0xd0bc, 0x00c0, 0x2b43, 0x789b, 0x0010, + 0x7baa, 0x7daa, 0x79aa, 0x2001, 0x0002, 0x007e, 0x6018, 0x8000, + 0x601a, 0x0078, 0x2bc4, 0x007e, 0x2960, 0x6104, 0x2a60, 0xa184, + 0x0018, 0x0040, 0x2be0, 0xa184, 0x0010, 0x0040, 0x2bd3, 0x1078, + 0x3df6, 0x00c0, 0x2c05, 0xa184, 0x0008, 0x0040, 0x2be0, 0x69a0, + 0xa184, 0x0600, 0x00c0, 0x2be0, 0x1078, 0x3cda, 0x0078, 0x2c05, + 0x69a0, 0xa184, 0x1e00, 0x0040, 0x2c10, 0xa184, 0x0800, 0x0040, + 0x2bf9, 0x0c7e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, + 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x1078, 0x3df6, 0x00c0, 0x2c05, + 0x69a0, 0xa184, 0x0200, 0x0040, 0x2c01, 0x1078, 0x3d3a, 0x0078, + 0x2c05, 0xa184, 0x0400, 0x00c0, 0x2bdc, 0x69a0, 0xa184, 0x1000, + 0x0040, 0x2c10, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x2749, + 0x027f, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x2c1d, 0xa086, + 0x0060, 0x00c0, 0x2c1d, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, + 0x789b, 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, + 0x0040, 0x2c38, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0050, + 0x2c36, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, + 0x78aa, 0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, + 0x20a0, 0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, + 0x2898, 0x25a0, 0xa286, 0x0020, 0x00c0, 0x2c70, 0x70d4, 0xc0b5, + 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, + 0x7882, 0xa286, 0x0002, 0x0040, 0x2ca6, 0x70a4, 0x8000, 0x70a6, + 0x74b4, 0xa498, 0x0005, 0x70ac, 0xa306, 0x00c0, 0x2c68, 0x73a8, + 0x73b6, 0xa286, 0x0010, 0x0040, 0x2942, 0x0d7f, 0x0c7f, 0x007c, + 0x7000, 0xa005, 0x00c0, 0x2c4e, 0xa286, 0x0002, 0x00c0, 0x2cc0, + 0x1078, 0x411c, 0x00c0, 0x2c4e, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0x2091, 0x8000, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, + 0x780a, 0x127e, 0x0d7e, 0x0c7e, 0x70d4, 0xa084, 0x2700, 0x2090, + 0x0c7f, 0x0d7f, 0x127f, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, + 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x7830, 0xd0bc, + 0x0040, 0x2cb2, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, + 0x8000, 0x2090, 0x70a4, 0xa005, 0x00c0, 0x2cb7, 0x007c, 0x8421, + 0x0040, 0x2cb6, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0078, 0x2aa1, + 0xa286, 0x0010, 0x00c0, 0x2cf1, 0x1078, 0x411c, 0x00c0, 0x2c4e, + 0x6814, 0xc0fc, 0x8007, 0x7882, 0x781b, 0x005b, 0x68b4, 0x785a, + 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, + 0x780a, 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, + 0xa206, 0x00c0, 0x2ce4, 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, + 0x7042, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, + 0x007c, 0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, + 0x7882, 0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, + 0x005b, 0x2900, 0x705a, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, + 0xa605, 0x0040, 0x2d1c, 0x70d4, 0xa084, 0x2700, 0xa086, 0x2300, + 0x00c0, 0x2d16, 0x2009, 0x0000, 0x0078, 0x2d18, 0x2009, 0x0001, + 0xa284, 0x000f, 0x1079, 0x2d20, 0xad80, 0x0009, 0x7046, 0x007c, + 0x2d28, 0x45f7, 0x45f7, 0x45e4, 0x45f7, 0x2d28, 0x2d28, 0x2d28, + 0x1078, 0x28ec, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, + 0x4a00, 0x78ac, 0x0f7f, 0xd084, 0x0040, 0x2d4e, 0x7064, 0xa086, + 0x0001, 0x00c0, 0x2d3e, 0x7066, 0x0078, 0x2e27, 0x7064, 0xa086, + 0x0005, 0x00c0, 0x2d4c, 0x707c, 0x2068, 0x681b, 0x0004, 0x6817, + 0x0000, 0x6820, 0xc09d, 0x6822, 0x7067, 0x0000, 0x70a7, 0x0000, + 0x70a8, 0x70b2, 0x70b6, 0x70d4, 0xd0b4, 0x0040, 0x2d64, 0xc0b4, + 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x6018, 0x8001, 0x601a, 0x0c7f, 0x157e, 0x2011, 0x0004, 0x7164, + 0xa186, 0x0001, 0x0040, 0x2d7d, 0xa186, 0x0007, 0x00c0, 0x2d74, + 0x701f, 0x0005, 0x0078, 0x2d7d, 0x701f, 0x0001, 0x7067, 0x0000, + 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x2d7f, 0x7067, 0x0000, 0x2001, + 0x4a0a, 0x2004, 0xa084, 0x00ff, 0xa086, 0x0018, 0x0040, 0x2d8f, + 0x7018, 0x7016, 0xa005, 0x00c0, 0x2d8f, 0x70a7, 0x0001, 0x1078, + 0x4326, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078, 0x3edb, 0xa7b8, + 0x0100, 0x00f0, 0x2d95, 0x7000, 0x0079, 0x2d9e, 0x2dcd, 0x2db3, + 0x2db3, 0x2da8, 0x2dcd, 0x2dcd, 0x2dcd, 0x2da6, 0x1078, 0x28ec, + 0x7060, 0xa005, 0x0040, 0x2dcd, 0xad06, 0x00c0, 0x2db3, 0x6800, + 0x7062, 0x0078, 0x2dc5, 0x6820, 0xd084, 0x00c0, 0x2dc1, 0x6f14, + 0x1078, 0x3fe1, 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3bb5, 0x0078, + 0x2dc5, 0x705c, 0x2060, 0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, + 0x6820, 0xc09d, 0x6822, 0x1078, 0x202a, 0xb284, 0x0400, 0x0040, + 0x2dd5, 0x2021, 0x91d0, 0x0078, 0x2dd7, 0x2021, 0x90c0, 0x1078, + 0x2e2c, 0xb284, 0x0400, 0x0040, 0x2de1, 0x2021, 0x4a98, 0x0078, + 0x2de3, 0x2021, 0x4a58, 0x1078, 0x2e2c, 0x20a9, 0x0101, 0xb284, + 0x0400, 0x0040, 0x2def, 0x2021, 0x90d0, 0x0078, 0x2df1, 0x2021, + 0x8fc0, 0x1078, 0x2e2c, 0x8420, 0x00f0, 0x2df1, 0xb284, 0x0300, + 0x0040, 0x2dfe, 0x2061, 0x4fc0, 0x0078, 0x2e00, 0x2061, 0x6fc0, + 0x2021, 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0040, 0x2e1d, + 0x6018, 0x017e, 0x007e, 0x2011, 0x4a02, 0x220c, 0xa102, 0x2012, + 0x007f, 0x017f, 0xa102, 0x0050, 0x2e1d, 0x6012, 0x00c0, 0x2e1d, + 0x2011, 0x4a04, 0x2204, 0xc0a5, 0x2012, 0x601b, 0x0000, 0xace0, + 0x0010, 0x00f0, 0x2e04, 0x8421, 0x00c0, 0x2e02, 0x157f, 0x7003, + 0x0000, 0x704f, 0x0000, 0x007c, 0x047e, 0x2404, 0xa005, 0x0040, + 0x2e3f, 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6817, 0x0000, 0x6820, + 0xc09d, 0x6822, 0x1078, 0x202a, 0x007f, 0x0078, 0x2e2e, 0x047f, + 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, 0x2e49, 0x1078, + 0x28ec, 0x2300, 0x0079, 0x2e4c, 0x2e4f, 0x2eda, 0x2ef7, 0xa282, + 0x0002, 0x0040, 0x2e55, 0x1078, 0x28ec, 0x7064, 0x7067, 0x0000, + 0x7083, 0x0000, 0x0079, 0x2e5c, 0x2e64, 0x2e64, 0x2e66, 0x2ea6, + 0x3bf1, 0x2e64, 0x2ea6, 0x2e64, 0x1078, 0x28ec, 0x7774, 0x1078, + 0x3edb, 0x7774, 0xa7bc, 0x8f00, 0x1078, 0x3fe1, 0x6018, 0xa005, + 0x0040, 0x2e9d, 0xd7fc, 0x00c0, 0x2e79, 0x2021, 0x90c0, 0x0078, + 0x2e7b, 0x2021, 0x91d0, 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, + 0x2f12, 0x0040, 0x2e9d, 0x157e, 0x20a9, 0x0101, 0xd7fc, 0x00c0, + 0x2e8d, 0x2021, 0x8fc0, 0x0078, 0x2e8f, 0x2021, 0x90d0, 0x047e, + 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, 0x2f12, 0x047f, 0x0040, + 0x2e9c, 0x8420, 0x00f0, 0x2e8f, 0x157f, 0x8738, 0xa784, 0x001f, + 0x00c0, 0x2e6c, 0x0078, 0x2946, 0x0078, 0x2946, 0x7774, 0x1078, + 0x3fe1, 0x6018, 0xa005, 0x0040, 0x2ed8, 0xd7fc, 0x00c0, 0x2eb4, + 0x2021, 0x90c0, 0x0078, 0x2eb6, 0x2021, 0x91d0, 0x2009, 0x0005, + 0x2011, 0x0020, 0x1078, 0x2f12, 0x0040, 0x2ed8, 0x157e, 0x20a9, + 0x0101, 0xd7fc, 0x00c0, 0x2ec8, 0x2021, 0x8fc0, 0x0078, 0x2eca, + 0x2021, 0x90d0, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, + 0x2f12, 0x047f, 0x0040, 0x2ed7, 0x8420, 0x00f0, 0x2eca, 0x157f, + 0x0078, 0x2946, 0x2200, 0x0079, 0x2edd, 0x2ee0, 0x2ee2, 0x2ee2, + 0x1078, 0x28ec, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002, 0x0040, + 0x2eeb, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0040, 0x2ef0, 0x691a, + 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x40c9, 0x2200, + 0x0079, 0x2efa, 0x2eff, 0x2ee2, 0x2efd, 0x1078, 0x28ec, 0x1078, + 0x4326, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3b7a, 0x1078, 0x3bd2, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3b6b, 0x0040, 0x3b7a, + 0x0078, 0x2946, 0x2404, 0xa005, 0x0040, 0x2f41, 0x2068, 0x2d04, + 0x007e, 0x6814, 0xa706, 0x0040, 0x2f21, 0x2d20, 0x007f, 0x0078, + 0x2f13, 0x007f, 0x2022, 0x691a, 0x6817, 0x0000, 0x6820, 0xa205, + 0x6822, 0x1078, 0x202a, 0x2021, 0x4a02, 0x241c, 0x8319, 0x2322, + 0x6010, 0x8001, 0x6012, 0x00c0, 0x2f3a, 0x2021, 0x4a04, 0x2404, + 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x1078, 0x3bd2, + 0x007c, 0xa085, 0x0001, 0x0078, 0x2f40, 0x2300, 0x0079, 0x2f48, + 0x2f4d, 0x2f4b, 0x2fce, 0x1078, 0x28ec, 0x78e4, 0xa005, 0x00d0, + 0x2f84, 0x3208, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x2f5e, 0xa18c, 0x0300, 0x0078, 0x2f60, 0xa18c, 0x0400, + 0x0040, 0x2f66, 0x0018, 0x2942, 0x0078, 0x2f68, 0x0028, 0x2942, + 0x2008, 0xa084, 0x0030, 0x00c0, 0x2f70, 0x781b, 0x005b, 0x007c, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x2f6d, 0x2100, 0xa084, 0x0007, + 0x0079, 0x2f7a, 0x2fae, 0x2fb8, 0x2fa3, 0x2f82, 0x4111, 0x4111, + 0x2f82, 0x2fc3, 0x1078, 0x28ec, 0x7000, 0xa086, 0x0004, 0x00c0, + 0x2f9e, 0x7064, 0xa086, 0x0002, 0x00c0, 0x2f94, 0x2011, 0x0002, + 0x2019, 0x0000, 0x0078, 0x2e43, 0x7064, 0xa086, 0x0006, 0x0040, + 0x2f8e, 0x7064, 0xa086, 0x0004, 0x0040, 0x2f8e, 0x79e4, 0x2001, + 0x0003, 0x0078, 0x3304, 0x6818, 0xd0fc, 0x0040, 0x2fa9, 0x681b, + 0x001d, 0x1078, 0x3eae, 0x781b, 0x0061, 0x007c, 0x6818, 0xd0fc, + 0x0040, 0x2fb4, 0x681b, 0x001d, 0x1078, 0x3eae, 0x0078, 0x40ed, + 0x6818, 0xd0fc, 0x0040, 0x2fbe, 0x681b, 0x001d, 0x1078, 0x3eae, + 0x781b, 0x00ef, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x2fc9, 0x681b, + 0x001d, 0x1078, 0x3eae, 0x781b, 0x00bf, 0x007c, 0xa584, 0x000f, + 0x00c0, 0x2feb, 0x7000, 0x0079, 0x2fd5, 0x2946, 0x2fdd, 0x2fdf, + 0x3b7a, 0x3b7a, 0x3b7a, 0x2fdd, 0x2fdd, 0x1078, 0x28ec, 0x1078, + 0x3bd2, 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3b6b, 0x0040, + 0x3b7a, 0x0078, 0x2946, 0x78e4, 0xa005, 0x00d0, 0x2f84, 0x3208, + 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2ffc, + 0xa18c, 0x0300, 0x0078, 0x2ffe, 0xa18c, 0x0400, 0x0040, 0x3004, + 0x0018, 0x2f84, 0x0078, 0x3006, 0x0028, 0x2f84, 0x2008, 0xa084, + 0x0030, 0x00c0, 0x300e, 0x781b, 0x005b, 0x007c, 0x78ec, 0xa084, + 0x0003, 0x0040, 0x300b, 0x2100, 0xa184, 0x0007, 0x0079, 0x3018, + 0x3027, 0x302b, 0x3022, 0x3020, 0x4111, 0x4111, 0x3020, 0x410b, + 0x1078, 0x28ec, 0x1078, 0x3eb6, 0x781b, 0x0061, 0x007c, 0x1078, + 0x3eb6, 0x0078, 0x40ed, 0x1078, 0x3eb6, 0x781b, 0x00ef, 0x007c, + 0x1078, 0x3eb6, 0x781b, 0x00bf, 0x007c, 0x2300, 0x0079, 0x3038, + 0x303d, 0x303b, 0x303f, 0x1078, 0x28ec, 0x0078, 0x37bd, 0x681b, + 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x37bd, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x37bd, 0xa184, 0x0100, 0x0040, + 0x3043, 0xa184, 0x0007, 0x0079, 0x3055, 0x305d, 0x302b, 0x2fa3, + 0x40c9, 0x4111, 0x4111, 0x40c9, 0x410b, 0x1078, 0x40d5, 0x007c, + 0xa282, 0x0005, 0x0050, 0x3066, 0x1078, 0x28ec, 0x2300, 0x0079, + 0x3069, 0x306c, 0x328b, 0x3296, 0x2200, 0x0079, 0x306f, 0x3089, + 0x3076, 0x3089, 0x3074, 0x326e, 0x1078, 0x28ec, 0x789b, 0x0018, + 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048, 0x3e9d, 0xa08a, + 0x0004, 0x00c8, 0x3e9d, 0x0079, 0x3085, 0x3e9d, 0x3e9d, 0x3e9d, + 0x3e47, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x309a, + 0x0078, 0x3e9d, 0x7000, 0xa005, 0x00c0, 0x3090, 0x2011, 0x0004, + 0x0078, 0x3998, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x3e9d, + 0x0079, 0x30a2, 0x30b4, 0x30b2, 0x30c9, 0x30cd, 0x318f, 0x3e9d, + 0x3e9d, 0x3191, 0x3e9d, 0x3e9d, 0x326a, 0x326a, 0x3e9d, 0x3e9d, + 0x3e9d, 0x326c, 0x1078, 0x28ec, 0xd6e4, 0x0040, 0x30bf, 0x2001, + 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x00ba, 0x007c, 0x6818, + 0xd0fc, 0x0040, 0x30c7, 0x681b, 0x001d, 0x0078, 0x30b7, 0x0078, + 0x40c9, 0x681b, 0x001d, 0x0078, 0x3ea7, 0x6920, 0x6922, 0xa684, + 0x1800, 0x00c0, 0x3121, 0x6820, 0xd084, 0x00c0, 0x3127, 0x6818, + 0xa086, 0x0008, 0x00c0, 0x30de, 0x681b, 0x0000, 0xd6d4, 0x0040, + 0x318c, 0xd6bc, 0x0040, 0x311e, 0x7087, 0x0000, 0x6818, 0xa084, + 0x003f, 0xa08a, 0x000d, 0x0050, 0x311e, 0xa08a, 0x000c, 0x7186, + 0x2001, 0x000c, 0x800c, 0x718a, 0x789b, 0x0061, 0x78aa, 0x157e, + 0x137e, 0x147e, 0x017e, 0x3208, 0xa18c, 0x0300, 0x0040, 0x3110, + 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x310c, + 0x20a1, 0x012b, 0x0078, 0x3112, 0x20a1, 0x022b, 0x0078, 0x3112, + 0x20a1, 0x012b, 0x017f, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, + 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b, 0x0064, + 0x007c, 0xd6e4, 0x0040, 0x3127, 0x781b, 0x0076, 0x007c, 0xa684, + 0x0060, 0x0040, 0x3189, 0xd6dc, 0x0040, 0x3189, 0xd6fc, 0x00c0, + 0x3133, 0x0078, 0x314a, 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, + 0x78d0, 0x801b, 0x00c8, 0x313d, 0x8000, 0xa084, 0x003f, 0xa108, + 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, + 0xa303, 0x68ae, 0xd6f4, 0x0040, 0x3150, 0xc6f4, 0x7e5a, 0x6eb6, + 0x7000, 0xa086, 0x0003, 0x00c0, 0x315e, 0x007e, 0x1078, 0x4326, + 0x1078, 0x45f7, 0x007f, 0x781b, 0x0073, 0x007c, 0xa006, 0x1078, + 0x46e5, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, + 0x316d, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, + 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, 0x317d, 0xc6f5, + 0x7e5a, 0x6eb6, 0x781b, 0x0073, 0x007c, 0x781b, 0x0073, 0x2200, + 0xa115, 0x00c0, 0x3186, 0x1078, 0x45f7, 0x007c, 0x1078, 0x462d, + 0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0064, 0x007c, 0x1078, + 0x28ec, 0x0078, 0x31dd, 0x6920, 0xd1c4, 0x0040, 0x31a6, 0xc1c4, + 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0e4, 0x6002, 0x6004, + 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x31d1, 0xd1cc, 0x0040, + 0x31d1, 0xc1cc, 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0ec, + 0x6002, 0x6004, 0xc0a4, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xd19c, + 0x0040, 0x31d1, 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, + 0x31d1, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, + 0xd6d4, 0x00c0, 0x31ce, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, + 0x007c, 0x7e58, 0xd6d4, 0x00c0, 0x31d8, 0x781b, 0x0064, 0x007c, + 0x781b, 0x0076, 0x007c, 0x0078, 0x3ea2, 0x2019, 0x0000, 0x7990, + 0xa18c, 0x0007, 0x00c0, 0x31eb, 0x6820, 0xa084, 0x0100, 0x0040, + 0x31db, 0x2009, 0x0008, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, + 0xa286, 0x0001, 0x00c0, 0x3207, 0x2300, 0x7ca8, 0xa400, 0x2018, + 0xa102, 0x0040, 0x31ff, 0x0048, 0x31ff, 0x0078, 0x3201, 0x0078, + 0x3193, 0x24a8, 0x7aa8, 0x00f0, 0x3201, 0x0078, 0x31ed, 0xa284, + 0x00f0, 0xa086, 0x0020, 0x00c0, 0x325b, 0x8318, 0x8318, 0x2300, + 0xa102, 0x0040, 0x3217, 0x0048, 0x3217, 0x0078, 0x3258, 0xa286, + 0x0023, 0x0040, 0x31db, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, + 0xa684, 0xfff1, 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, + 0x0c7e, 0x7058, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd1a4, + 0x0040, 0x3238, 0x1078, 0x3fdd, 0x1078, 0x3df6, 0x0078, 0x3246, + 0x0c7e, 0x7058, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd19c, + 0x0040, 0x31d1, 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, + 0x31d1, 0x789b, 0x0060, 0x2800, 0x78aa, 0xc695, 0x7e5a, 0xd6d4, + 0x00c0, 0x3255, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, + 0x7aa8, 0x0078, 0x31ed, 0x8318, 0x2300, 0xa102, 0x0040, 0x3264, + 0x0048, 0x3264, 0x0078, 0x31ed, 0xa284, 0x0080, 0x00c0, 0x3ea7, + 0x0078, 0x3ea2, 0x0078, 0x3ea7, 0x0078, 0x3e9d, 0x7058, 0xa04d, + 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0040, + 0x327b, 0x1078, 0x28ec, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, + 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x3e9d, 0x0079, 0x3287, 0x3e9d, + 0x3c2c, 0x3e9d, 0x3d9e, 0xa282, 0x0000, 0x00c0, 0x3291, 0x1078, + 0x28ec, 0x1078, 0x3eae, 0x781b, 0x0075, 0x007c, 0xa282, 0x0003, + 0x00c0, 0x329c, 0x1078, 0x28ec, 0xd4fc, 0x00c0, 0x32bc, 0x7064, + 0xa005, 0x0040, 0x32a5, 0x1078, 0x28ec, 0x6f14, 0x7776, 0xa7bc, + 0x8f00, 0x1078, 0x3fe1, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, + 0xa784, 0x001f, 0x00c0, 0x32a9, 0x1078, 0x3eb2, 0x7067, 0x0002, + 0x701f, 0x0009, 0x0078, 0x32be, 0x1078, 0x3ebe, 0x781b, 0x0075, + 0x007c, 0xa282, 0x0004, 0x0050, 0x32c7, 0x1078, 0x28ec, 0x2300, + 0x0079, 0x32ca, 0x32cd, 0x346b, 0x34ae, 0xa286, 0x0003, 0x0040, + 0x3304, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x71d4, 0xd1b4, 0x0078, + 0x32fc, 0x0040, 0x32fc, 0x7868, 0xa084, 0x00ff, 0x00c0, 0x32fc, + 0xa282, 0x0002, 0x00c8, 0x32fc, 0x0d7e, 0x783b, 0x8300, 0x781b, + 0x004c, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, + 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, + 0x2001, 0x0000, 0x0078, 0x3308, 0x783b, 0x1300, 0x781b, 0x004a, + 0x2001, 0x0000, 0x0078, 0x3308, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, + 0x704a, 0x68a0, 0xd0ec, 0x0040, 0x3310, 0x6008, 0xc08d, 0x600a, + 0xa284, 0x000f, 0x0079, 0x3314, 0x344b, 0x3321, 0x331e, 0x35ae, + 0x35f2, 0x2946, 0x331c, 0x331c, 0x1078, 0x28ec, 0x6008, 0xc0d4, + 0x600a, 0xd6e4, 0x00c0, 0x3328, 0x1078, 0x4326, 0x0040, 0x3404, + 0x7868, 0xa08c, 0x00ff, 0x0040, 0x3369, 0xa186, 0x0008, 0x00c0, + 0x333e, 0x1078, 0x3bd2, 0x6008, 0xc0a4, 0x600a, 0x1078, 0x3b6b, + 0x0040, 0x3369, 0x1078, 0x4326, 0x0078, 0x3353, 0xa186, 0x0028, + 0x00c0, 0x3369, 0x1078, 0x4326, 0x6008, 0xc0a4, 0x600a, 0x6018, + 0xa005, 0x0040, 0x3353, 0x8001, 0x601a, 0x0040, 0x3353, 0x8001, + 0x0040, 0x3353, 0x601e, 0x6820, 0xd084, 0x0040, 0x2946, 0xc084, + 0x6822, 0x705c, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, + 0x6802, 0xa005, 0x2d00, 0x00c0, 0x3366, 0x6002, 0x6006, 0x0078, + 0x2946, 0x017e, 0x81ff, 0x00c0, 0x33b0, 0x7000, 0xa086, 0x0030, + 0x0040, 0x33b0, 0x71d4, 0xd1b4, 0x00c0, 0x3397, 0x7060, 0xa005, + 0x00c0, 0x33b0, 0x70a4, 0xa086, 0x0001, 0x0040, 0x33b0, 0x7003, + 0x0000, 0x047e, 0x057e, 0x077e, 0x067e, 0x0c7e, 0x0d7e, 0x1078, + 0x296c, 0x0d7f, 0x0c7f, 0x067f, 0x077f, 0x057f, 0x047f, 0x71d4, + 0xd1b4, 0x00c0, 0x33b0, 0x7003, 0x0040, 0x0078, 0x33b0, 0x1078, + 0x411c, 0x00c0, 0x33b0, 0x781b, 0x005b, 0x0d7e, 0x70bc, 0xa06d, + 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, + 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, 0x0d7f, + 0x1078, 0x34e8, 0x017f, 0x81ff, 0x0040, 0x3403, 0xa684, 0xdf00, + 0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x00c0, 0x3404, + 0x70d4, 0xd0b4, 0x0040, 0x33d1, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x6820, 0xd0dc, 0x00c0, 0x3404, 0x8717, 0xa294, 0x000f, + 0x8213, 0x8213, 0x8213, 0xb284, 0x0300, 0x0040, 0x33e3, 0xa290, + 0x4ec0, 0x0078, 0x33e5, 0xa290, 0x4f40, 0xa290, 0x0000, 0x221c, + 0xd3c4, 0x00c0, 0x33ed, 0x0078, 0x33f3, 0x8210, 0x2204, 0xa085, + 0x0018, 0x2012, 0x8211, 0xd3d4, 0x0040, 0x33fe, 0x68a0, 0xd0c4, + 0x00c0, 0x33fe, 0x1078, 0x3562, 0x0078, 0x2946, 0x6008, 0xc08d, + 0x600a, 0x0078, 0x3404, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0040, + 0x340b, 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, + 0x0040, 0x3420, 0x2009, 0x4a02, 0x2104, 0x8001, 0x200a, 0x8421, + 0x6412, 0x00c0, 0x3420, 0x2021, 0x4a04, 0x2404, 0xc0a5, 0x2022, + 0x6018, 0xa005, 0x0040, 0x3428, 0x8001, 0x601a, 0x00c0, 0x342b, + 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084, 0x00c0, 0x3437, 0x6800, + 0xa005, 0x00c0, 0x3434, 0x6002, 0x6006, 0x0078, 0x343b, 0x705c, + 0x2060, 0x6800, 0x6002, 0x2061, 0x4a00, 0x6887, 0x0103, 0x2d08, + 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x344a, 0x2d02, + 0x0078, 0x344b, 0x616e, 0x7200, 0xa286, 0x0030, 0x0040, 0x345b, + 0xa286, 0x0040, 0x00c0, 0x2946, 0x7003, 0x0002, 0x704c, 0x2068, + 0x68c4, 0x2060, 0x007c, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, + 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, + 0x0009, 0x7046, 0x007c, 0xa282, 0x0004, 0x0048, 0x3471, 0x1078, + 0x28ec, 0x2200, 0x0079, 0x3474, 0x3478, 0x3489, 0x3496, 0x3489, + 0xa586, 0x1300, 0x0040, 0x3489, 0xa586, 0x8300, 0x00c0, 0x346f, + 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x7000, 0xa086, 0x0005, 0x0040, 0x3493, 0x1078, 0x3eae, + 0x781b, 0x0075, 0x007c, 0x781b, 0x0076, 0x007c, 0x7890, 0x8007, + 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, + 0x00ff, 0xa186, 0x0003, 0x0040, 0x34ab, 0xa186, 0x0000, 0x0040, + 0x34ab, 0x0078, 0x3e9d, 0x781b, 0x0076, 0x007c, 0x6820, 0xc095, + 0x6822, 0x82ff, 0x00c0, 0x34b8, 0x1078, 0x3eae, 0x0078, 0x34bf, + 0x8211, 0x0040, 0x34bd, 0x1078, 0x28ec, 0x1078, 0x3ebe, 0x781b, + 0x0075, 0x007c, 0x1078, 0x4131, 0x7830, 0xa084, 0x00c0, 0x00c0, + 0x34e5, 0x017e, 0x3208, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x34d7, 0xa18c, 0x0300, 0x0078, 0x34d9, 0xa18c, + 0x0400, 0x017f, 0x0040, 0x34e0, 0x0018, 0x34e5, 0x0078, 0x34e2, + 0x0028, 0x34e5, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, + 0xa684, 0x0060, 0x00c0, 0x34f2, 0x682f, 0x0000, 0x6833, 0x0000, + 0x0078, 0x3561, 0xd6dc, 0x00c0, 0x350a, 0x68b4, 0xd0dc, 0x00c0, + 0x350a, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x00c0, + 0x3507, 0x2200, 0xa105, 0x0040, 0x4326, 0x704b, 0x0015, 0x0078, + 0x4326, 0x007c, 0xd6ac, 0x0040, 0x3530, 0xd6f4, 0x0040, 0x3516, + 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x4326, 0x68b4, 0xa084, + 0x4000, 0xa635, 0xd6f4, 0x00c0, 0x3510, 0x7048, 0xa005, 0x00c0, + 0x3523, 0x704b, 0x0015, 0xd6dc, 0x00c0, 0x352c, 0x68b4, 0xd0dc, + 0x0040, 0x352c, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0078, 0x4326, + 0xd6f4, 0x0040, 0x3539, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, + 0x4326, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x00c0, 0x3533, + 0x7048, 0xa005, 0x00c0, 0x3546, 0x704b, 0x0015, 0x2408, 0x2510, + 0x2700, 0x80fb, 0x00c8, 0x354d, 0x8000, 0xa084, 0x003f, 0xa108, + 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x355a, + 0x0078, 0x4326, 0x7000, 0xa086, 0x0006, 0x0040, 0x3561, 0x0078, + 0x4326, 0x007c, 0x6008, 0xc0cd, 0xd3cc, 0x0040, 0x3568, 0xc08d, + 0x600a, 0x681b, 0x0006, 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, + 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, + 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, 0x0079, 0x3580, + 0x2946, 0x3592, 0x358a, 0x3588, 0x3588, 0x3588, 0x3588, 0x3588, + 0x1078, 0x28ec, 0x6820, 0xd084, 0x00c0, 0x3592, 0x1078, 0x3bb5, + 0x0078, 0x3598, 0x705c, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, + 0x3208, 0xa18c, 0x0300, 0x0040, 0x35a1, 0x2021, 0x4a58, 0x0078, + 0x35a3, 0x2021, 0x4a98, 0x2404, 0xa005, 0x0040, 0x35aa, 0x2020, + 0x0078, 0x35a3, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x3bbc, + 0x1078, 0x3bd2, 0x6008, 0xc0cc, 0x600a, 0x682b, 0x0000, 0x789b, + 0x000e, 0x6f14, 0x6817, 0x0002, 0x3208, 0xa18c, 0x0300, 0x0040, + 0x35c5, 0x2009, 0x0000, 0x0078, 0x35c7, 0x2009, 0x0001, 0x1078, + 0x471a, 0xd6dc, 0x0040, 0x35cf, 0x691c, 0xc1ed, 0x691e, 0x6818, + 0xd0fc, 0x0040, 0x35de, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x35dc, + 0x681b, 0x001e, 0x0078, 0x35de, 0x681b, 0x0000, 0xb284, 0x0300, + 0x00c0, 0x35e6, 0x2021, 0x4a98, 0x0078, 0x35e8, 0x2021, 0x4a58, + 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x202a, + 0x0078, 0x2946, 0x7cd8, 0x7ddc, 0x7fd0, 0x1078, 0x34e8, 0x682b, + 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, 0x4135, 0xa08c, 0x00ff, + 0x6916, 0x6818, 0xd0fc, 0x0040, 0x3607, 0x7048, 0x681a, 0xa68c, + 0xdf00, 0x691e, 0x7067, 0x0000, 0x0078, 0x2946, 0x7000, 0xa005, + 0x00c0, 0x3614, 0x0078, 0x2946, 0xa006, 0x1078, 0x4326, 0x6817, + 0x0000, 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, + 0x6820, 0xa084, 0x00ff, 0x6822, 0x7000, 0x0079, 0x3627, 0x2946, + 0x3634, 0x3631, 0x3636, 0x3636, 0x3636, 0x362f, 0x362f, 0x1078, + 0x28ec, 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3bd2, 0x6008, 0xc0a4, + 0x600a, 0x0078, 0x3b85, 0x2300, 0x0079, 0x363e, 0x3641, 0x3643, + 0x369f, 0x1078, 0x28ec, 0xd6fc, 0x00c0, 0x3686, 0x7000, 0xa00d, + 0x0079, 0x364a, 0x2946, 0x3654, 0x3654, 0x3678, 0x3654, 0x3683, + 0x3652, 0x3652, 0x1078, 0x28ec, 0xa684, 0x0060, 0xa086, 0x0060, + 0x00c0, 0x3675, 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x681c, 0xc0ac, + 0x681e, 0xa186, 0x0002, 0x0040, 0x3667, 0x1078, 0x4326, 0x1078, + 0x45f7, 0x781b, 0x0076, 0x71d4, 0xd1b4, 0x00c0, 0x2942, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6ec, 0x0040, 0x365c, + 0x6818, 0xd0fc, 0x0040, 0x3683, 0x681b, 0x0015, 0xd6f4, 0x0040, + 0x3683, 0x681b, 0x0007, 0x1078, 0x40d5, 0x007c, 0xc6fc, 0x7e5a, + 0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8, 0x368f, 0x8000, 0xa084, + 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, + 0x6b94, 0x2200, 0xa303, 0x68ae, 0x781b, 0x0076, 0x007c, 0x1078, + 0x28ec, 0x2300, 0x0079, 0x36a4, 0x36a9, 0x36c5, 0x3719, 0x1078, + 0x28ec, 0x7000, 0x0079, 0x36ac, 0x36b4, 0x36b6, 0x36b6, 0x36b4, + 0x36b4, 0x36b4, 0x36b4, 0x36b4, 0x1078, 0x28ec, 0x1078, 0x45f7, + 0x681c, 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x00c0, 0x2942, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6fc, 0x00c0, 0x3709, + 0x7000, 0xa00d, 0x0079, 0x36cc, 0x2946, 0x36dc, 0x36d6, 0x3700, + 0x36dc, 0x3706, 0x36d4, 0x36d4, 0x1078, 0x28ec, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0xa086, 0x0060, + 0x00c0, 0x36fd, 0xa6b4, 0xbfbf, 0xc6ed, 0x7e5a, 0xa186, 0x0002, + 0x0040, 0x36ec, 0x1078, 0x4326, 0x1078, 0x45f7, 0x781b, 0x0076, + 0x681c, 0xc0b4, 0x681e, 0x71d4, 0xd1b4, 0x00c0, 0x2942, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6ec, 0x0040, 0x36e4, + 0x6818, 0xd0fc, 0x0040, 0x3706, 0x681b, 0x0007, 0x781b, 0x00f0, + 0x007c, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, + 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, 0x0076, + 0x007c, 0xd6dc, 0x0040, 0x3722, 0x782b, 0x3009, 0x781b, 0x0076, + 0x0078, 0x2942, 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, + 0x00c0, 0x3735, 0xa484, 0x0200, 0x0040, 0x372f, 0xc6f5, 0xc6dd, + 0x7e5a, 0x781b, 0x0076, 0x0078, 0x2942, 0x6820, 0xc095, 0x6822, + 0x1078, 0x4062, 0xc6dd, 0x1078, 0x3eae, 0x781b, 0x0075, 0x0078, + 0x2942, 0x2300, 0x0079, 0x3744, 0x3747, 0x3749, 0x374b, 0x1078, + 0x28ec, 0x0078, 0x3ea7, 0xd6d4, 0x00c0, 0x3771, 0x79e4, 0xd1ac, + 0x0040, 0x3759, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3759, 0x782b, + 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, + 0x79e4, 0xd1ac, 0x0040, 0x3769, 0x78ec, 0xa084, 0x0003, 0x00c0, + 0x376d, 0x2001, 0x0014, 0x0078, 0x3304, 0xa184, 0x0007, 0x0079, + 0x37a7, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, + 0x0040, 0x37a5, 0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, + 0x3798, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, 0x378b, 0x2009, + 0xfff7, 0x0078, 0x3791, 0xa386, 0x0003, 0x00c0, 0x3798, 0x2009, + 0xffef, 0x0c7e, 0x7058, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, + 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, + 0x3009, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40c9, 0x2fae, + 0x2fb8, 0x37b1, 0x37b7, 0x37af, 0x37af, 0x40c9, 0x40c9, 0x1078, + 0x28ec, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40cf, 0x6920, + 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40c9, 0x79e4, 0xa184, 0x0030, + 0x0040, 0x37c7, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x37f1, 0x7000, + 0xa086, 0x0004, 0x00c0, 0x37e1, 0x7064, 0xa086, 0x0002, 0x00c0, + 0x37d7, 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, 0x2e43, 0x7064, + 0xa086, 0x0006, 0x0040, 0x37d1, 0x7064, 0xa086, 0x0004, 0x0040, + 0x37d1, 0x7000, 0xa086, 0x0000, 0x0040, 0x2942, 0x6820, 0xd0ac, + 0x00c0, 0x37ed, 0x6818, 0xc0fd, 0x681a, 0x2001, 0x0014, 0x0078, + 0x3304, 0xa184, 0x0007, 0x0079, 0x37f5, 0x40c9, 0x40c9, 0x37fd, + 0x40c9, 0x4111, 0x4111, 0x40c9, 0x40c9, 0xd6bc, 0x0040, 0x383f, + 0x7184, 0x81ff, 0x0040, 0x383f, 0xa182, 0x000d, 0x00d0, 0x380c, + 0x7087, 0x0000, 0x0078, 0x3811, 0xa182, 0x000c, 0x7086, 0x2009, + 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e, 0x147e, 0x7088, + 0x8114, 0xa210, 0x728a, 0xa080, 0x000b, 0xad00, 0x2098, 0xb284, + 0x0300, 0x0040, 0x3833, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x382f, 0x20a1, 0x012b, 0x0078, 0x3835, 0x20a1, + 0x022b, 0x0078, 0x3835, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, + 0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, 0x40cf, 0xd6d4, + 0x00c0, 0x3893, 0x6820, 0xd084, 0x0040, 0x40cf, 0xa68c, 0x0060, + 0xa684, 0x0060, 0x0040, 0x3851, 0xa086, 0x0060, 0x00c0, 0x3851, + 0xc1f5, 0xc194, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, + 0x789b, 0x0061, 0x6818, 0xc0fd, 0x681a, 0x78aa, 0x8008, 0x810c, + 0x0040, 0x3beb, 0xa18c, 0x00f8, 0x00c0, 0x3beb, 0x157e, 0x137e, + 0x147e, 0x017e, 0x3208, 0xa18c, 0x0300, 0x0040, 0x387f, 0x007e, + 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x387b, 0x20a1, + 0x012b, 0x0078, 0x3881, 0x20a1, 0x022b, 0x0078, 0x3881, 0x20a1, + 0x012b, 0x017f, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, + 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0xc0fc, 0x8007, + 0x7882, 0x0078, 0x40cf, 0x6818, 0xd0fc, 0x0040, 0x3899, 0x681b, + 0x0008, 0x6820, 0xc0ad, 0x6822, 0x1078, 0x3eb6, 0x781b, 0x00e1, + 0x007c, 0x2300, 0x0079, 0x38a4, 0x38a9, 0x397b, 0x38a7, 0x1078, + 0x28ec, 0x7cd8, 0x7ddc, 0x7fd0, 0x82ff, 0x00c0, 0x38d1, 0x7200, + 0xa286, 0x0003, 0x0040, 0x32d2, 0x71d4, 0xd1b4, 0x0078, 0x38d4, + 0x0040, 0x38d4, 0x0d7e, 0x783b, 0x8800, 0x781b, 0x004c, 0x70bc, + 0xa06d, 0x68b4, 0xc0a5, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x0078, + 0x38d8, 0x7200, 0x0078, 0x38d8, 0x783b, 0x1800, 0x781b, 0x004a, + 0xa284, 0x000f, 0x0079, 0x38dc, 0x3966, 0x391a, 0x38e6, 0x3300, + 0x38e4, 0x3966, 0x38e4, 0x38e4, 0x1078, 0x28ec, 0x681c, 0xd0ec, + 0x0040, 0x38ed, 0x6008, 0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, + 0x6800, 0x6006, 0xa005, 0x00c0, 0x38f6, 0x6002, 0x6008, 0xc0d4, + 0x600a, 0x681c, 0xa084, 0x000e, 0x00c0, 0x390a, 0xb284, 0x0300, + 0x0040, 0x3906, 0x2009, 0x90c0, 0x0078, 0x390f, 0x2009, 0x91d0, + 0x0078, 0x390f, 0x7030, 0x68ba, 0x7140, 0x70cc, 0xa108, 0x2104, + 0x6802, 0x2d0a, 0x715e, 0xd6dc, 0x00c0, 0x391a, 0xc6fc, 0x6eb6, + 0x0078, 0x3966, 0x6eb6, 0xa684, 0x0060, 0x0040, 0x3966, 0xd6dc, + 0x00c0, 0x392d, 0xa684, 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, + 0x68aa, 0x1078, 0x4326, 0x0078, 0x3966, 0xd6ac, 0x0040, 0x3939, + 0xa006, 0x1078, 0x4326, 0x2408, 0x2510, 0x69aa, 0x6aa6, 0x0078, + 0x3949, 0x2408, 0x2510, 0x2700, 0x801b, 0x00c8, 0x3940, 0x8000, + 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x69aa, 0x6aa6, 0x1078, + 0x4326, 0xd6fc, 0x0040, 0x3966, 0xa684, 0x7fff, 0x68b6, 0x2510, + 0x2408, 0xd6ac, 0x00c0, 0x395e, 0x2700, 0x801b, 0x00c8, 0x3959, + 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, + 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, + 0x0030, 0x00c0, 0x2946, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, + 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, + 0x0009, 0x7046, 0x007c, 0xa586, 0x8800, 0x00c0, 0x3988, 0x7003, + 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x0078, 0x3ea7, 0x7047, 0x0000, 0xa282, 0x0006, 0x0050, 0x3992, + 0x1078, 0x28ec, 0x2300, 0x0079, 0x3995, 0x3998, 0x39cf, 0x3a01, + 0x2200, 0x0079, 0x399b, 0x39a1, 0x3ea7, 0x39a3, 0x39a1, 0x3a38, + 0x3a9b, 0x1078, 0x28ec, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, + 0x39ad, 0x2001, 0x91e0, 0x0078, 0x39af, 0x2001, 0x9212, 0x2068, + 0x704e, 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, + 0x39b4, 0x157f, 0xb284, 0x0300, 0x0040, 0x39c2, 0x6817, 0x0000, + 0x0078, 0x39c4, 0x6817, 0x8000, 0xad80, 0x0009, 0x7046, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x0078, 0x3e9d, 0x7000, + 0xa086, 0x0002, 0x00c0, 0x39e0, 0x1078, 0x3bd2, 0x0078, 0x39da, + 0x1078, 0x4326, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0078, 0x39e5, + 0x7000, 0xa086, 0x0003, 0x0040, 0x39d8, 0x7003, 0x0005, 0xb284, + 0x0300, 0x0040, 0x39ef, 0x2001, 0x91e0, 0x0078, 0x39f1, 0x2001, + 0x9212, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, 0x2200, 0x0079, + 0x39f9, 0x3ea7, 0x39ff, 0x39ff, 0x3a38, 0x39ff, 0x3ea7, 0x1078, + 0x28ec, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3a12, 0x1078, 0x3bd2, + 0x0078, 0x3a0c, 0x1078, 0x4326, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x0078, 0x3a17, 0x7000, 0xa086, 0x0003, 0x0040, 0x3a0a, 0x7003, + 0x0005, 0xb284, 0x0300, 0x0040, 0x3a21, 0x2001, 0x91e0, 0x0078, + 0x3a23, 0x2001, 0x9212, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, + 0x2200, 0x0079, 0x3a2b, 0x3a33, 0x3a31, 0x3a31, 0x3a33, 0x3a31, + 0x3a33, 0x1078, 0x28ec, 0x1078, 0x3ebe, 0x781b, 0x0075, 0x007c, + 0x7000, 0xa086, 0x0002, 0x00c0, 0x3a4a, 0x70d4, 0xc0b5, 0x70d6, + 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3a4f, 0x1078, 0x4326, + 0x0078, 0x3a4f, 0x7000, 0xa086, 0x0003, 0x0040, 0x3a46, 0x7003, + 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, + 0x001f, 0xa215, 0x2069, 0x90c0, 0xb284, 0x0300, 0x00c0, 0x3a63, + 0xc2fd, 0x2069, 0x91d0, 0x2d04, 0x2d08, 0x715e, 0xa06d, 0x0040, + 0x3a70, 0x6814, 0xa206, 0x0040, 0x3a90, 0x6800, 0x0078, 0x3a64, + 0x7003, 0x0005, 0xd2fc, 0x00c0, 0x3a79, 0x2001, 0x91e0, 0x0078, + 0x3a7b, 0x2001, 0x9212, 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, + 0x2003, 0x0000, 0x8000, 0x00f0, 0x3a80, 0x157f, 0xad80, 0x0009, + 0x7046, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, + 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x3b10, 0x1078, + 0x3eb6, 0x0078, 0x3b10, 0x7200, 0xa286, 0x0002, 0x00c0, 0x3aad, + 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, + 0x3ab1, 0x1078, 0x4326, 0x0078, 0x3ab1, 0xa286, 0x0003, 0x0040, + 0x3aa9, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, + 0x7ca8, 0xa484, 0x001f, 0xa215, 0xb284, 0x0300, 0x00c0, 0x3ac1, + 0xc2fd, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0x70cc, 0xa168, 0x2d04, + 0x2d08, 0x715e, 0xa06d, 0x0040, 0x3ad4, 0x6814, 0xa206, 0x0040, + 0x3afd, 0x6800, 0x0078, 0x3ac8, 0x7003, 0x0005, 0xb284, 0x0300, + 0x0040, 0x3ade, 0x2001, 0x91e0, 0x0078, 0x3ae0, 0x2001, 0x9212, + 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, + 0x00f0, 0x3ae5, 0x157f, 0xb284, 0x0300, 0x0040, 0x3af2, 0xc2fc, + 0x0078, 0x3af3, 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x6820, 0xa084, + 0x0c00, 0x0040, 0x3b10, 0xd0dc, 0x0040, 0x3b0a, 0x1078, 0x3eba, + 0x0078, 0x3b10, 0x1078, 0x3eb6, 0x707f, 0x0000, 0x0078, 0x3b10, + 0xa6ac, 0x0060, 0x0040, 0x3b4e, 0x6b98, 0x6c94, 0x69ac, 0x68b0, + 0xa105, 0x00c0, 0x3b33, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, + 0xb7ff, 0xa586, 0x0060, 0x0040, 0x3b4e, 0xc6ed, 0x7e5a, 0x2009, + 0x0076, 0xd69c, 0x0040, 0x3b2e, 0x2009, 0x0075, 0x791a, 0x1078, + 0x45f7, 0x0078, 0x3b57, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, + 0xa305, 0x0040, 0x3b4e, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, + 0xc6f4, 0x7e5a, 0x2011, 0x0076, 0xd69c, 0x0040, 0x3b49, 0x2011, + 0x0075, 0x7a1a, 0x1078, 0x462d, 0x0078, 0x3b57, 0x7e5a, 0x2009, + 0x0076, 0xd69c, 0x0040, 0x3b56, 0x2009, 0x0075, 0x791a, 0x68c0, + 0x705a, 0x2d00, 0x704e, 0x68c4, 0x2060, 0x71d4, 0xd1b4, 0x00c0, + 0x2942, 0x2300, 0xa405, 0x0040, 0x2942, 0x70a4, 0xa086, 0x0001, + 0x00c0, 0x2989, 0x007c, 0x6020, 0xa005, 0x0040, 0x3b79, 0x8001, + 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, 0x700f, 0x0100, 0x702c, + 0x6026, 0x007c, 0xa006, 0x1078, 0x4326, 0x6817, 0x0000, 0x681b, + 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, + 0x0079, 0x3b8a, 0x2946, 0x3b94, 0x3b94, 0x3bb1, 0x3b9c, 0x2946, + 0x3b92, 0x3b92, 0x1078, 0x28ec, 0x1078, 0x3bbc, 0x1078, 0x3bb5, + 0x1078, 0x202a, 0x0078, 0x2946, 0x7064, 0x7067, 0x0000, 0x7083, + 0x0000, 0x0079, 0x3ba3, 0x3bad, 0x3bad, 0x3bab, 0x3bab, 0x3bab, + 0x3bad, 0x3bab, 0x3bad, 0x0079, 0x2e5c, 0x7067, 0x0000, 0x0078, + 0x2946, 0x681b, 0x0000, 0x0078, 0x35ae, 0x6800, 0xa005, 0x00c0, + 0x3bba, 0x6002, 0x6006, 0x007c, 0x6410, 0x84ff, 0x0040, 0x3bce, + 0x2009, 0x4a02, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x00c0, + 0x3bce, 0x2021, 0x4a04, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xc0a4, + 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x3bd8, 0x8001, 0x601a, + 0x007c, 0x1078, 0x4131, 0x681b, 0x0018, 0x0078, 0x3c1a, 0x1078, + 0x4131, 0x681b, 0x0019, 0x0078, 0x3c1a, 0x1078, 0x4131, 0x681b, + 0x001a, 0x0078, 0x3c1a, 0x1078, 0x4131, 0x681b, 0x0003, 0x0078, + 0x3c1a, 0x7774, 0x1078, 0x3fe1, 0x7178, 0xa18c, 0x00ff, 0x3210, + 0xa294, 0x0300, 0x0040, 0x3c00, 0xa1e8, 0x8fc0, 0x0078, 0x3c02, + 0xa1e8, 0x90d0, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, 0x3c0a, + 0x0078, 0x2946, 0x6814, 0xc0fc, 0x7274, 0xc2fc, 0xa206, 0x0040, + 0x3c14, 0x6800, 0x0078, 0x3c03, 0x6800, 0x200a, 0x681b, 0x0005, + 0x707f, 0x0000, 0x1078, 0x3bbc, 0x6820, 0xd084, 0x00c0, 0x3c22, + 0x1078, 0x3bb5, 0x1078, 0x3bd2, 0x681f, 0x0000, 0x6823, 0x0020, + 0x1078, 0x202a, 0x0078, 0x2946, 0xa282, 0x0003, 0x00c0, 0x3e9d, + 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xc1bd, + 0x6922, 0xd1c4, 0x0040, 0x3c86, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, + 0x0040, 0x3c73, 0xa682, 0x000c, 0x0048, 0x3c4a, 0x0040, 0x3c4a, + 0x2031, 0x000c, 0x2500, 0xa086, 0x000a, 0x0040, 0x3c51, 0x852b, + 0x852b, 0x1078, 0x3f73, 0x0040, 0x3c59, 0x1078, 0x3d55, 0x0078, + 0x3c7c, 0x1078, 0x3f2e, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, + 0x6006, 0x1078, 0x3d8a, 0x0c7f, 0x6920, 0xc1c5, 0x6922, 0x7e58, + 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3c70, 0x781b, 0x0061, 0x007c, + 0x781b, 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, + 0x6006, 0x1078, 0x3d8a, 0x0c7f, 0x7e58, 0xd6d4, 0x00c0, 0x3c83, + 0x781b, 0x0064, 0x007c, 0x781b, 0x0076, 0x007c, 0x0c7e, 0x7058, + 0x2060, 0x6100, 0xd1e4, 0x0040, 0x3ccf, 0x6208, 0x8217, 0xa294, + 0x00ff, 0xa282, 0x000c, 0x0048, 0x3c99, 0x0040, 0x3c99, 0x2011, + 0x000c, 0x2600, 0xa202, 0x00c8, 0x3c9e, 0x2230, 0x6208, 0xa294, + 0x00ff, 0x2001, 0x4a05, 0x2004, 0xd0e4, 0x00c0, 0x3cb3, 0x78ec, + 0xd0e4, 0x0040, 0x3cb3, 0xa282, 0x000a, 0x00c8, 0x3cb9, 0x2011, + 0x000a, 0x0078, 0x3cb9, 0xa282, 0x000c, 0x00c8, 0x3cb9, 0x2011, + 0x000c, 0x2200, 0xa502, 0x00c8, 0x3cbe, 0x2228, 0x1078, 0x3f32, + 0x2500, 0xa086, 0x000a, 0x0040, 0x3cc7, 0x852b, 0x852b, 0x1078, + 0x3f73, 0x0040, 0x3ccf, 0x1078, 0x3d55, 0x0078, 0x3cd3, 0x1078, + 0x3f2e, 0x1078, 0x3d8a, 0x7858, 0xc095, 0x785a, 0x0c7f, 0x781b, + 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6000, 0xd0e4, 0x00c0, 0x3cf1, + 0x6010, 0xa084, 0x000f, 0x00c0, 0x3ceb, 0x6104, 0xa18c, 0xfff5, + 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, + 0x3d1c, 0x68a0, 0xd0cc, 0x00c0, 0x3ceb, 0x6208, 0xa294, 0x00ff, + 0x2001, 0x4a05, 0x2004, 0xd0e4, 0x00c0, 0x3d0a, 0x78ec, 0xd0e4, + 0x0040, 0x3d0a, 0xa282, 0x000a, 0x00c0, 0x3d0a, 0x2011, 0x000a, + 0x0078, 0x3d10, 0xa282, 0x000c, 0x00c8, 0x3d10, 0x2011, 0x000c, + 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, 0x0048, 0x3d1c, + 0x0040, 0x3d1c, 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, + 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, + 0x6822, 0x70d4, 0xd0b4, 0x0040, 0x3d38, 0xc0b4, 0x70d6, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x007c, 0x0c7e, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, + 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3d46, 0x78ab, 0x0001, + 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, + 0x6820, 0xc0c5, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7158, 0x2160, + 0x2018, 0xa08c, 0x0020, 0x0040, 0x3d5e, 0xc0ac, 0x2008, 0xa084, + 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, + 0xa084, 0xfff0, 0xa18c, 0x000f, 0xa105, 0xa39c, 0x0020, 0x0040, + 0x3d73, 0xa085, 0x4000, 0xc0fc, 0xd0b4, 0x00c0, 0x3d78, 0xc0fd, + 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, + 0xa084, 0x00ff, 0xa605, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, + 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x6018, 0x789a, 0x78a4, + 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, + 0x600c, 0xa084, 0x00ff, 0x600e, 0x0c7f, 0x007c, 0xa282, 0x0002, + 0x00c0, 0x3e9d, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0040, + 0x3dd9, 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, + 0x3e9d, 0x1078, 0x3e2a, 0x1078, 0x3d8a, 0xa980, 0x0001, 0x200c, + 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, 0x3dcf, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, + 0x3dcc, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, 0x7e58, + 0xd6d4, 0x00c0, 0x3dd6, 0x781b, 0x0064, 0x007c, 0x781b, 0x0076, + 0x007c, 0xa282, 0x0002, 0x00c8, 0x3de1, 0xa284, 0x0001, 0x0040, + 0x3dea, 0x7158, 0xa188, 0x0000, 0x210c, 0xd1ec, 0x00c0, 0x3dea, + 0x2011, 0x0000, 0x1078, 0x3f0f, 0x1078, 0x3e2a, 0x1078, 0x3d8a, + 0x7858, 0xc095, 0x785a, 0x781b, 0x0075, 0x007c, 0x0c7e, 0x027e, + 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x00c0, 0x3e0b, 0x6014, + 0xa084, 0x0040, 0x00c0, 0x3e09, 0xc1a4, 0x6106, 0xa006, 0x0078, + 0x3e27, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, + 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x3e23, + 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x6018, 0x8001, 0x601a, 0x6820, 0xa085, 0x0200, 0x6822, 0x027f, + 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x82ff, 0x0040, 0x3e32, + 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, + 0xffbf, 0xa205, 0xc0fc, 0xd0b4, 0x00c0, 0x3e3f, 0xc0fd, 0x78a6, + 0x6016, 0x788a, 0x6004, 0xc0a4, 0x6006, 0x0c7f, 0x007c, 0x007e, + 0x7000, 0xa086, 0x0003, 0x0040, 0x3e50, 0x007f, 0x0078, 0x3e53, + 0x007f, 0x0078, 0x3e9a, 0xd6ac, 0x0040, 0x3e9a, 0x7888, 0xa084, + 0x0040, 0x0040, 0x3e9a, 0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, + 0x3e62, 0x8000, 0xa005, 0x0040, 0x3e77, 0x831b, 0x00c8, 0x3e6b, + 0x8001, 0x0040, 0x3e97, 0xd6f4, 0x0040, 0x3e77, 0x78b8, 0x801b, + 0x00c8, 0x3e73, 0x8000, 0xa084, 0x003f, 0x00c0, 0x3e97, 0xc6f4, + 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x3e82, + 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x46e5, + 0x781b, 0x0073, 0xb284, 0x0300, 0x0040, 0x3e92, 0x2001, 0x0000, + 0x0078, 0x3e94, 0x2001, 0x0001, 0x1078, 0x4585, 0x007c, 0x781b, + 0x0073, 0x007c, 0x781b, 0x0076, 0x007c, 0x1078, 0x3ec2, 0x781b, + 0x0075, 0x007c, 0x1078, 0x3eae, 0x781b, 0x0075, 0x007c, 0x6827, + 0x0002, 0x1078, 0x3eb6, 0x781b, 0x0075, 0x007c, 0x2001, 0x0005, + 0x0078, 0x3ec4, 0x2001, 0x000c, 0x0078, 0x3ec4, 0x2001, 0x0006, + 0x0078, 0x3ec4, 0x2001, 0x000d, 0x0078, 0x3ec4, 0x2001, 0x0009, + 0x0078, 0x3ec4, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, + 0x7e5a, 0x70d4, 0xd0b4, 0x0040, 0x3eda, 0xc0b4, 0x70d6, 0x0c7e, + 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, + 0x601a, 0x0c7f, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, + 0x873b, 0x8703, 0x017e, 0xb28c, 0x0300, 0x0040, 0x3eeb, 0xa0e0, + 0x4ec0, 0x0078, 0x3eed, 0xa0e0, 0x4f40, 0x017f, 0xa7b8, 0x0020, + 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040, 0x3efd, 0xa184, 0xfff0, + 0x78a6, 0x6012, 0x6004, 0xc09d, 0x6006, 0x8738, 0x8738, 0x7f9a, + 0x79a4, 0xa184, 0x0040, 0x0040, 0x3f0d, 0xa184, 0xffbf, 0xc0fd, + 0x78a6, 0x6016, 0x6004, 0xc0a5, 0x6006, 0x077f, 0x007c, 0x789b, + 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, + 0x789b, 0x0060, 0x78ab, 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x3f2d, + 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x2031, 0x0000, + 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, + 0x78ab, 0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, + 0x70d4, 0xd0b4, 0x0040, 0x3f51, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, + 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0, 0x2021, 0x3fc6, + 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, + 0xfff0, 0xa106, 0x0040, 0x3f71, 0x8420, 0x2300, 0xa210, 0x00f0, + 0x3f66, 0x157f, 0x007c, 0x157e, 0x2001, 0x4a05, 0x2004, 0xd0e4, + 0x00c0, 0x3fa4, 0x2021, 0x3fd4, 0x20a9, 0x0009, 0x2011, 0x0028, + 0xa582, 0x0019, 0x0040, 0x3fba, 0x0048, 0x3fba, 0x8420, 0x95a9, + 0x2011, 0x0032, 0xa582, 0x0032, 0x0040, 0x3fba, 0x0048, 0x3fba, + 0x8420, 0x95a9, 0x2019, 0x000a, 0x2011, 0x0064, 0x2200, 0xa502, + 0x0040, 0x3fba, 0x0048, 0x3fba, 0x8420, 0x2300, 0xa210, 0x00f0, + 0x3f96, 0x157f, 0x0078, 0x3fb8, 0x2021, 0x3fc6, 0x2019, 0x0011, + 0x20a9, 0x000e, 0x2011, 0x0032, 0x2200, 0xa502, 0x0040, 0x3fba, + 0x0048, 0x3fba, 0x8420, 0x2300, 0xa210, 0x00f0, 0x3fac, 0x157f, + 0xa006, 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8, 0x3fc3, 0x7808, + 0xa085, 0x0070, 0x780a, 0x2404, 0xa005, 0x007c, 0x1209, 0x3002, + 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, + 0x7a06, 0x0c07, 0x0c07, 0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, + 0x6a06, 0x6c06, 0x7c07, 0x7e07, 0x0e00, 0x789b, 0x0010, 0xa046, + 0x007c, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0xd7fc, 0x0040, 0x3ff2, 0xa0e0, 0x6fc0, + 0x0078, 0x3ff4, 0xa0e0, 0x4fc0, 0x007c, 0x0e7e, 0x0f7e, 0xd084, + 0x0040, 0x4002, 0x2079, 0x0100, 0x2009, 0x4a80, 0x2071, 0x4a80, + 0x0078, 0x4014, 0x2009, 0x4a40, 0x007e, 0x2001, 0x4a04, 0x2004, + 0xd0ec, 0x007f, 0x0040, 0x4010, 0x2079, 0x0100, 0x0078, 0x4014, + 0x2079, 0x0200, 0x2071, 0x4a40, 0x2091, 0x8000, 0x2104, 0xa084, + 0x000f, 0x0079, 0x401b, 0x405d, 0x4025, 0x4025, 0x4025, 0x4025, + 0x4025, 0x4023, 0x4023, 0x1078, 0x28ec, 0x784b, 0x0004, 0x7848, + 0xa084, 0x0004, 0x00c0, 0x4027, 0x784b, 0x0008, 0x7848, 0xa084, + 0x0008, 0x00c0, 0x402e, 0x68b4, 0xc0f5, 0x68b6, 0x7858, 0xc0f5, + 0x785a, 0x7830, 0xd0bc, 0x00c0, 0x405d, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x4049, 0xb284, 0x0300, 0x0078, + 0x404b, 0xb284, 0x0400, 0x0040, 0x4051, 0x0018, 0x405d, 0x0078, + 0x4053, 0x0028, 0x405d, 0x681c, 0xd0ac, 0x00c0, 0x405b, 0x1078, + 0x40d5, 0x0078, 0x405d, 0x781b, 0x00f0, 0x2091, 0x8001, 0x0f7f, + 0x0e7f, 0x007c, 0x0c7e, 0x2001, 0x4a01, 0x2004, 0xd0ac, 0x00c0, + 0x40c7, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xb28c, 0x0300, 0x0040, 0x4078, 0xa0e0, 0x4ec0, 0x0078, 0x407a, + 0xa0e0, 0x4f40, 0x6004, 0xa084, 0x000a, 0x00c0, 0x40c7, 0x6108, + 0xa194, 0xff00, 0x0040, 0x40c7, 0xa18c, 0x00ff, 0x2001, 0x000a, + 0xa106, 0x0040, 0x40a6, 0x2001, 0x000c, 0xa106, 0x0040, 0x40aa, + 0x2001, 0x0012, 0xa106, 0x0040, 0x40ae, 0x2001, 0x0014, 0xa106, + 0x0040, 0x40b2, 0x2001, 0x0019, 0xa106, 0x0040, 0x40b6, 0x2001, + 0x0032, 0xa106, 0x0040, 0x40ba, 0x0078, 0x40be, 0x2009, 0x000c, + 0x0078, 0x40c0, 0x2009, 0x0012, 0x0078, 0x40c0, 0x2009, 0x0014, + 0x0078, 0x40c0, 0x2009, 0x0019, 0x0078, 0x40c0, 0x2009, 0x0020, + 0x0078, 0x40c0, 0x2009, 0x003f, 0x0078, 0x40c0, 0x2011, 0x0000, + 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, + 0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0075, 0x007c, 0x781b, + 0x0064, 0x007c, 0x781b, 0x0061, 0x007c, 0x2009, 0x4a19, 0x210c, + 0xa186, 0x0000, 0x0040, 0x40e7, 0xa186, 0x0001, 0x0040, 0x40ea, + 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, 0x781b, + 0x00e7, 0x007c, 0x701f, 0x000a, 0x007c, 0x2009, 0x4a19, 0x210c, + 0xa186, 0x0000, 0x0040, 0x4102, 0xa186, 0x0001, 0x0040, 0x40ff, + 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, 0x701f, + 0x000a, 0x007c, 0x781b, 0x00e6, 0x007c, 0x781b, 0x00f0, 0x007c, + 0x781b, 0x00ef, 0x007c, 0x781b, 0x00c0, 0x007c, 0x781b, 0x00bf, + 0x007c, 0x6818, 0xd0fc, 0x0040, 0x4117, 0x681b, 0x001d, 0x7067, + 0x0001, 0x781b, 0x0047, 0x007c, 0x7830, 0xa084, 0x00c0, 0x00c0, + 0x4130, 0x7808, 0xc08c, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, + 0x78ec, 0xa084, 0x0021, 0x0040, 0x4130, 0x7808, 0xc08d, 0x780a, + 0x007c, 0x7808, 0xc08d, 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, + 0x00c0, 0x4135, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x0040, 0x4144, + 0xb284, 0x0300, 0x0078, 0x4146, 0xb284, 0x0400, 0x0040, 0x414c, + 0x0098, 0x4150, 0x0078, 0x414e, 0x00a8, 0x4150, 0x78ac, 0x007c, + 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, + 0x78ec, 0xa084, 0x0021, 0x0040, 0x4173, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x4169, 0xb284, 0x0300, 0x0078, + 0x416b, 0xb284, 0x0400, 0x0040, 0x4171, 0x0098, 0x416d, 0x0078, + 0x4173, 0x00a8, 0x4171, 0x78ac, 0x007e, 0x7808, 0xa085, 0x0002, + 0x780a, 0x007f, 0x007c, 0xa784, 0x0001, 0x00c0, 0x360e, 0xa784, + 0x0070, 0x0040, 0x418b, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x2881, + 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x4198, 0x784b, + 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2946, 0x0078, 0x40c9, + 0xa784, 0x0004, 0x0040, 0x41c7, 0x78b8, 0xa084, 0x4001, 0x0040, + 0x41c7, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2946, + 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x41c7, 0x78c0, + 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00f0, 0x007c, 0x784b, + 0x0008, 0x6818, 0xd0fc, 0x0040, 0x41c4, 0x681b, 0x0015, 0xd6f4, + 0x0040, 0x41c4, 0x681b, 0x0007, 0x1078, 0x40d5, 0x007c, 0x681b, + 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833, + 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2f84, + 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x41e4, + 0xb284, 0x0300, 0x0078, 0x41e6, 0xb284, 0x0400, 0x0040, 0x41ec, + 0x0018, 0x2942, 0x0078, 0x41ee, 0x0028, 0x2942, 0x0078, 0x3ea2, + 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, + 0x0040, 0x41fe, 0xa080, 0x4f40, 0x0078, 0x4200, 0xa080, 0x4ec0, + 0x2060, 0x2048, 0x705a, 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, + 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x9906, 0x98f4, + 0x0014, 0x0014, 0x0080, 0x00f1, 0x0100, 0x0402, 0x2008, 0xf880, + 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0x2500, 0x0013, + 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0xa200, + 0x3806, 0x8839, 0x20c4, 0x0864, 0xa850, 0x3008, 0x28c1, 0x9d0d, + 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, + 0x883a, 0xa808, 0x28e2, 0x9cc2, 0xa8f3, 0x0864, 0xa83e, 0x300c, + 0xa801, 0x3008, 0x28e1, 0x9cc2, 0x2021, 0xa81b, 0xa205, 0x870c, + 0xd8de, 0x64a0, 0x6de0, 0x6fc0, 0x63a4, 0x6c80, 0x0212, 0xa205, + 0x883d, 0x9d25, 0x882b, 0x1814, 0x883b, 0x9d2b, 0x883b, 0x7027, + 0x85f2, 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa812, 0x883e, + 0xa810, 0x280c, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x9d25, + 0x1814, 0x9d2b, 0x883b, 0x7023, 0x8576, 0x8677, 0xa802, 0x7861, + 0x883e, 0x206b, 0x28c1, 0x9d0d, 0x2044, 0x2103, 0x20a2, 0x2081, + 0xa8c9, 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, 0x8000, 0x85a4, + 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, + 0x7161, 0x0014, 0x0704, 0x3008, 0x9cc2, 0x0014, 0xa202, 0x8000, + 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, 0x883f, 0x08e6, + 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, + 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, + 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, 0x8000, 0x284a, + 0x1011, 0xa8fc, 0x3008, 0x9d25, 0x8000, 0xa000, 0x2802, 0x1011, + 0xa8fd, 0x9d2b, 0xa887, 0x3008, 0x9d25, 0x283b, 0x1011, 0xa8fd, + 0xa209, 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, + 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, + 0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d17, + 0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, + 0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, + 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, + 0x0016, 0x7944, 0x8421, 0xa020, 0xa532, 0x84a1, 0x0016, 0x7944, + 0x8421, 0xa0df, 0x9532, 0x84a1, 0x0016, 0x0000, 0x127e, 0x70d4, + 0xa084, 0x4600, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205, + 0x00c0, 0x4342, 0x720c, 0x82ff, 0x0040, 0x433d, 0x8aff, 0x00c0, + 0x4342, 0x7200, 0xd284, 0x00c0, 0x4342, 0x7003, 0x0008, 0x127f, + 0x2000, 0x007c, 0x7000, 0xa084, 0x0003, 0x7002, 0xc69c, 0xd084, + 0x0040, 0x4374, 0x2001, 0x4a05, 0x2004, 0xd0ec, 0x00c0, 0x43a5, + 0xd0e4, 0x00c0, 0x435a, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0003, + 0x0040, 0x43a5, 0x0e7e, 0x2071, 0x0010, 0x2009, 0x0007, 0x7008, + 0xa084, 0x3000, 0x00c0, 0x435d, 0x8109, 0x00c0, 0x435f, 0x0e7f, + 0x2009, 0x0007, 0x7008, 0xa084, 0x3000, 0x00c0, 0x435a, 0x8109, + 0x00c0, 0x436a, 0x0078, 0x43a5, 0x7108, 0xd1fc, 0x0040, 0x437f, + 0x1078, 0x44ba, 0x8aff, 0x0040, 0x432c, 0x0078, 0x4374, 0x700c, + 0xa08c, 0x03ff, 0x0040, 0x43aa, 0x7004, 0xd084, 0x0040, 0x439c, + 0x7014, 0xa005, 0x00c0, 0x4398, 0x7010, 0x7310, 0xa306, 0x00c0, + 0x438c, 0x2300, 0xa005, 0x0040, 0x439c, 0xa102, 0x00c8, 0x4374, + 0x7007, 0x0010, 0x0078, 0x43a5, 0x8aff, 0x0040, 0x43aa, 0x1078, + 0x46a3, 0x00c0, 0x439f, 0x0040, 0x4374, 0x1078, 0x4443, 0x127f, + 0x2000, 0x007c, 0x7204, 0x7108, 0xc19c, 0x8103, 0x00c8, 0x43b9, + 0x1078, 0x44ba, 0x0078, 0x43aa, 0x7003, 0x0008, 0x127f, 0x2000, + 0x007c, 0xa205, 0x00c0, 0x43a5, 0x7003, 0x0008, 0x127f, 0x2000, + 0x007c, 0x6428, 0x84ff, 0x0040, 0x43ed, 0x2c70, 0x7004, 0xa0bc, + 0x000f, 0xa7b8, 0x43fd, 0x273c, 0x87fb, 0x00c0, 0x43db, 0x0048, + 0x43d3, 0x1078, 0x28ec, 0x609c, 0xa075, 0x0040, 0x43ed, 0x0078, + 0x43c6, 0x2039, 0x43f2, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, + 0xa529, 0x8421, 0x0040, 0x43ed, 0x8738, 0x2704, 0xa005, 0x00c0, + 0x43dc, 0x709c, 0xa075, 0x00c0, 0x43c6, 0x007c, 0x0000, 0x0005, + 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, + 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x43f2, 0x43ef, + 0x0000, 0x0000, 0x8000, 0x0000, 0x43f2, 0x0000, 0x43fa, 0x43f7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x43fa, 0x0000, 0x43f5, 0x43f5, + 0x0000, 0x0000, 0x8000, 0x0000, 0x43f5, 0x0000, 0x43fb, 0x43fb, + 0x0000, 0x0000, 0x0000, 0x0000, 0x43fb, 0x2079, 0x4a00, 0x2071, + 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0001, 0x7810, + 0xd0ec, 0x0040, 0x4431, 0x2009, 0x0001, 0x2071, 0x0020, 0x0078, + 0x4435, 0x2009, 0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, + 0x0002, 0x7003, 0x0000, 0x8109, 0x0040, 0x4442, 0x2071, 0x0020, + 0x0078, 0x4435, 0x007c, 0x7004, 0x8004, 0x00c8, 0x44a6, 0x7007, + 0x0012, 0x2019, 0x0000, 0x7108, 0x7008, 0xa106, 0x00c0, 0x444b, + 0xa184, 0x01e0, 0x0040, 0x4456, 0x1078, 0x28ec, 0x7810, 0xd0ec, + 0x0040, 0x4470, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0003, 0x00c0, + 0x4474, 0xa184, 0x4000, 0x0040, 0x4478, 0xa382, 0x0003, 0x00c8, + 0x4478, 0xa184, 0x0004, 0x0040, 0x444b, 0x8318, 0x0078, 0x444b, + 0x7814, 0xd0ec, 0x00c0, 0x4478, 0xa184, 0x4000, 0x00c0, 0x444b, + 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x4486, 0xa386, 0x0008, + 0x0040, 0x4491, 0xa386, 0x200c, 0x00c0, 0x444b, 0x7200, 0x8204, + 0x0048, 0x4491, 0x730c, 0xa384, 0x03ff, 0x0040, 0x4491, 0x1078, + 0x28ec, 0x7007, 0x0012, 0x7000, 0xd084, 0x00c0, 0x44a6, 0x7008, + 0xa084, 0x01e0, 0x00c0, 0x44a6, 0x7310, 0x7014, 0xa305, 0x0040, + 0x44a6, 0x710c, 0xa184, 0x03ff, 0x00c0, 0x4443, 0x7007, 0x0012, + 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x44aa, 0x7007, 0x0012, + 0x7108, 0x8103, 0x0048, 0x44ae, 0x7003, 0x0008, 0x007c, 0x7108, + 0x0078, 0x44ba, 0xa184, 0x01e0, 0x00c0, 0x44ee, 0x7108, 0xa184, + 0x01e0, 0x00c0, 0x44ee, 0xa184, 0x0007, 0x0079, 0x44c7, 0x44d1, + 0x44e1, 0x44cf, 0x44e1, 0x44cf, 0x4533, 0x44cf, 0x4531, 0x1078, + 0x28ec, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x00c0, + 0x44dc, 0x2049, 0x0000, 0x007c, 0x1078, 0x46a3, 0x00c0, 0x44dc, + 0x007c, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x0040, + 0x44ed, 0x1078, 0x46a3, 0x00c0, 0x44e9, 0x007c, 0x7007, 0x0012, + 0x7108, 0x00e0, 0x44f1, 0x2091, 0x6000, 0x00e0, 0x44f5, 0x2091, + 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, + 0x44fd, 0x7007, 0x0012, 0x7108, 0xd1fc, 0x00c0, 0x4501, 0x7003, + 0x0000, 0x7000, 0xa005, 0x00c0, 0x4515, 0x7004, 0xa005, 0x00c0, + 0x4515, 0x700c, 0xa005, 0x0040, 0x4517, 0x0078, 0x44f9, 0x2049, + 0x0000, 0xb284, 0x0100, 0x0040, 0x4521, 0x2001, 0x0000, 0x0078, + 0x4523, 0x2001, 0x0001, 0x1078, 0x3ff5, 0x6818, 0xa084, 0x8000, + 0x0040, 0x452c, 0x681b, 0x0002, 0x007c, 0x1078, 0x28ec, 0x1078, + 0x28ec, 0x1078, 0x4570, 0x7210, 0x7114, 0x700c, 0xa09c, 0x03ff, + 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x4570, 0x2704, + 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, + 0x2400, 0xa305, 0x0040, 0x4556, 0x00c8, 0x4556, 0x8412, 0x8210, + 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x453d, 0x2b60, 0x8a07, + 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x4562, 0xa7ba, 0x43f7, + 0x0078, 0x4564, 0xa7ba, 0x43ef, 0x007f, 0xa73d, 0x2c00, 0x6886, + 0x6f8a, 0x6c92, 0x6b8e, 0x7007, 0x0012, 0x1078, 0x4443, 0x007c, + 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x4584, 0x6000, 0xa064, + 0x00c0, 0x457b, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, 0x440d, + 0x203c, 0x87fb, 0x1040, 0x28ec, 0x007c, 0x127e, 0x0d7e, 0x70d4, + 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x6884, 0x2060, 0x6888, + 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, + 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x45a2, 0xa0b8, 0x43f7, + 0x0078, 0x45a4, 0xa0b8, 0x43ef, 0xb284, 0x0100, 0x0040, 0x45ab, + 0x7e20, 0x0078, 0x45ac, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0b4, + 0x0040, 0x45b3, 0xc685, 0x2400, 0xa305, 0x0040, 0x45dd, 0x2c58, + 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, + 0x701e, 0xa184, 0x0008, 0x0040, 0x45cd, 0x6010, 0xa081, 0x0000, + 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, + 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, + 0x2b60, 0x1078, 0x46c6, 0x0078, 0x45df, 0x1078, 0x46a3, 0x00c0, + 0x45dd, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, + 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xd094, + 0x00c0, 0x45ee, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, + 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7e20, + 0xb284, 0x0100, 0x00c0, 0x4605, 0x7e24, 0xa6b5, 0x000c, 0x681c, + 0xd0ac, 0x00c0, 0x4610, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, + 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x43fd, + 0x273c, 0x87fb, 0x00c0, 0x4626, 0x0048, 0x4620, 0x1078, 0x28ec, + 0x689c, 0xa065, 0x0040, 0x462a, 0x0078, 0x4613, 0x1078, 0x46a3, + 0x00c0, 0x4626, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, + 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x7e20, 0xb284, + 0x0100, 0x00c0, 0x463c, 0x7e24, 0x0d7f, 0x037f, 0x047f, 0xa6b5, + 0x000c, 0x681c, 0xd0b4, 0x0040, 0x464a, 0xc685, 0x7003, 0x0000, + 0x7007, 0x0004, 0x2049, 0x462d, 0x6828, 0xa055, 0x0040, 0x46a0, + 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x43fd, 0x273c, + 0x87fb, 0x00c0, 0x4666, 0x0048, 0x465f, 0x1078, 0x28ec, 0x709c, + 0xa075, 0x2060, 0x0040, 0x46a0, 0x0078, 0x4652, 0x2704, 0xae68, + 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, 0x467f, 0x8a51, 0x00c0, + 0x4673, 0x1078, 0x28ec, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4667, + 0x709c, 0xa075, 0x2060, 0x0040, 0x46a0, 0x0078, 0x4652, 0x8422, + 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, + 0x2300, 0xa11b, 0x00c8, 0x468e, 0x1078, 0x28ec, 0xb284, 0x0100, + 0x0040, 0x469c, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x00c0, 0x469c, + 0x2071, 0x0050, 0x0078, 0x469e, 0x2071, 0x0020, 0x0078, 0x45b3, + 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, + 0x00c0, 0x46ab, 0x007c, 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, + 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, 0xa084, 0x0008, + 0x0040, 0x46be, 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, 0x7004, + 0xa084, 0x0010, 0xc085, 0x7006, 0x2079, 0x4a00, 0x8a51, 0x0040, + 0x46e1, 0x8738, 0x2704, 0xa005, 0x00c0, 0x46dc, 0x609c, 0xa005, + 0x0040, 0x46e2, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x43fd, + 0x203c, 0x87fb, 0x1040, 0x28ec, 0x7008, 0xa084, 0x0003, 0xa086, + 0x0003, 0x007c, 0x2051, 0x0000, 0x007c, 0x127e, 0x007e, 0x0d7e, + 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x087f, 0x7108, + 0xa184, 0x0003, 0x00c0, 0x46fa, 0x6828, 0xa005, 0x0040, 0x470a, + 0x0078, 0x4342, 0x7108, 0xd1fc, 0x0040, 0x4702, 0x1078, 0x44ba, + 0x0078, 0x46ef, 0x7007, 0x0010, 0x7108, 0xd1fc, 0x0040, 0x4704, + 0x1078, 0x44ba, 0x7008, 0xa086, 0x0008, 0x00c0, 0x46ef, 0x7000, + 0xa005, 0x00c0, 0x46ef, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, + 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, + 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x2049, 0x471a, + 0xad80, 0x0011, 0x20a0, 0xb284, 0x0100, 0x0040, 0x473d, 0x2001, + 0x4a04, 0x2004, 0xd0ec, 0x0040, 0x4739, 0x2099, 0x0031, 0x0078, + 0x473f, 0x2099, 0x0032, 0x0078, 0x473f, 0x2099, 0x0031, 0x700c, + 0xa084, 0x03ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, + 0x0001, 0x0040, 0x474e, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, + 0x03ff, 0x0040, 0x475a, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x4755, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, + 0x137f, 0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x8000, 0x2091, + 0x6000, 0x78ac, 0xa005, 0x00c0, 0x477c, 0x7974, 0x70d0, 0xa106, + 0x00c0, 0x477c, 0x781c, 0xa005, 0x0040, 0x477c, 0x781f, 0x0000, + 0x0068, 0x477c, 0x2091, 0x4080, 0x7830, 0x8001, 0x7832, 0x00c0, + 0x4804, 0x7834, 0x7832, 0x7810, 0xd0ec, 0x00c0, 0x47fd, 0x2061, + 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x68d0, 0xa005, 0x0040, 0x4796, + 0x8001, 0x68d2, 0x00c0, 0x4796, 0x1078, 0x4998, 0x6800, 0xa084, + 0x000f, 0x0040, 0x47ab, 0xa086, 0x0001, 0x0040, 0x47ab, 0x6844, + 0xa00d, 0x0040, 0x47ab, 0x2104, 0xa005, 0x0040, 0x47ab, 0x8001, + 0x200a, 0x0040, 0x4909, 0x6814, 0xa005, 0x0040, 0x47d0, 0x8001, + 0x6816, 0x00c0, 0x47d0, 0x68a7, 0x0001, 0x0f7e, 0xd7fc, 0x00c0, + 0x47c5, 0x7810, 0xd0ec, 0x0040, 0x47c1, 0x2079, 0x0100, 0x0078, + 0x47c7, 0x2079, 0x0200, 0x0078, 0x47c7, 0x2079, 0x0100, 0x1078, + 0x4131, 0x0f7f, 0x6864, 0xa005, 0x0040, 0x47d0, 0x1078, 0x25de, + 0x6880, 0xa005, 0x0040, 0x47dd, 0x8001, 0x6882, 0x00c0, 0x47dd, + 0x6867, 0x0000, 0x68d4, 0xc0dd, 0x68d6, 0x68d4, 0xd0fc, 0x0040, + 0x47fa, 0xc0fc, 0x68d6, 0x20a9, 0x0200, 0x603c, 0xa005, 0x0040, + 0x47f6, 0x8001, 0x603e, 0x68d4, 0xc0fd, 0x68d6, 0x00c0, 0x47f6, + 0x6010, 0xa005, 0x0040, 0x47f6, 0x1078, 0x25de, 0xace0, 0x0010, + 0x00f0, 0x47e5, 0xd7fc, 0x0040, 0x4804, 0x2061, 0x4fc0, 0x2069, + 0x4a40, 0xc7fc, 0x0078, 0x478c, 0x1078, 0x4840, 0x7838, 0x8001, + 0x783a, 0x00c0, 0x4826, 0x783c, 0x783a, 0x2061, 0x4fc0, 0x2069, + 0x4a40, 0xc7fc, 0x680c, 0xa005, 0x0040, 0x4818, 0x1078, 0x487f, + 0xd7fc, 0x00c0, 0x4826, 0x7810, 0xd0ec, 0x00c0, 0x4826, 0x2061, + 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x0078, 0x4812, 0x7814, 0xd0e4, + 0x00c0, 0x482a, 0x7810, 0xd0cc, 0x0040, 0x483d, 0xd0ac, 0x00c0, + 0x4836, 0xd0a4, 0x0040, 0x483d, 0xc0ad, 0x7812, 0x2091, 0x8001, + 0x0068, 0x483c, 0x1078, 0x2368, 0x007c, 0x2091, 0x8001, 0x007c, + 0x7840, 0x8001, 0x7842, 0x00c0, 0x487e, 0x7844, 0x7842, 0x2091, + 0x8000, 0x2061, 0x4fc0, 0x2069, 0x4a40, 0xc7fc, 0x6810, 0xa005, + 0x00c0, 0x4854, 0x2001, 0x0101, 0x8001, 0x6812, 0xd7fc, 0x0040, + 0x485d, 0xa080, 0x90d0, 0x0078, 0x485f, 0xa080, 0x8fc0, 0x2040, + 0x2004, 0xa065, 0x0040, 0x4870, 0x6024, 0xa005, 0x0040, 0x486c, + 0x8001, 0x6026, 0x0040, 0x48ad, 0x6000, 0x2c40, 0x0078, 0x4861, + 0xd7fc, 0x00c0, 0x487e, 0x7810, 0xd0ec, 0x00c0, 0x487e, 0x2061, + 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x0078, 0x484e, 0x007c, 0x2009, + 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0040, 0x4899, 0x6024, + 0xa005, 0x0040, 0x488f, 0x8001, 0x6026, 0x0078, 0x4897, 0x6008, + 0xc09c, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0078, 0x4899, 0xa18d, + 0x0100, 0xace0, 0x0010, 0x00f0, 0x4883, 0xa184, 0x0001, 0x0040, + 0x48a8, 0xa18c, 0xfffe, 0x690e, 0x1078, 0x25de, 0x0078, 0x48a9, + 0x690e, 0x007c, 0x00c0, 0x48a9, 0x786c, 0x6800, 0xa005, 0x0040, + 0x48b5, 0x684c, 0xac06, 0x0040, 0x4909, 0x6864, 0xa005, 0x0040, + 0x48bd, 0x6027, 0x0001, 0x0078, 0x4906, 0x2c00, 0x687e, 0x601b, + 0x0006, 0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, + 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6f76, 0x1078, + 0x1e02, 0x6818, 0xa005, 0x0040, 0x48d7, 0x8001, 0x681a, 0x6808, + 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x00d0, + 0x48e3, 0x1078, 0x28ec, 0x6812, 0x00c0, 0x48e9, 0x7910, 0xc1a5, + 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x202a, + 0xd7fc, 0x00c0, 0x48f7, 0x2069, 0x4a40, 0x0078, 0x48f9, 0x2069, + 0x4a80, 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x00c0, 0x4903, + 0x697a, 0x2001, 0x0004, 0x2708, 0x1078, 0x25d1, 0x2091, 0x8001, + 0x007c, 0x0d7e, 0x694c, 0x2160, 0xd7fc, 0x00c0, 0x491b, 0x7810, + 0xd0ec, 0x0040, 0x4917, 0x2069, 0x0100, 0x0078, 0x491d, 0x2069, + 0x0200, 0x0078, 0x491d, 0x2069, 0x0100, 0x1078, 0x2881, 0x601b, + 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, + 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6830, + 0xd0b4, 0x0040, 0x494b, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, + 0xd094, 0x0040, 0x493d, 0x00f0, 0x4937, 0x684b, 0x0009, 0x20a9, + 0x0014, 0x6848, 0xd084, 0x0040, 0x4947, 0x00f0, 0x4941, 0x20a9, + 0x00fa, 0x00f0, 0x4949, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, + 0x0047, 0x0d7f, 0x6867, 0x0007, 0x2091, 0x8001, 0x007c, 0x2079, + 0x4a00, 0x1078, 0x498b, 0x1078, 0x4971, 0x1078, 0x497e, 0x2009, + 0x0002, 0x2069, 0x4a80, 0x680f, 0x0000, 0x6813, 0x0000, 0x6817, + 0x0000, 0x8109, 0x0040, 0x4970, 0x2069, 0x4a40, 0x0078, 0x4963, + 0x007c, 0x7810, 0xd0ec, 0x0040, 0x4979, 0x2019, 0x00cc, 0x0078, + 0x497b, 0x2019, 0x007b, 0x7b3a, 0x7b3e, 0x007c, 0x7814, 0xd0e4, + 0x00c0, 0x4986, 0x2019, 0x0040, 0x0078, 0x4988, 0x2019, 0x0026, + 0x7b42, 0x7b46, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x4993, 0x2019, + 0x3f94, 0x0078, 0x4995, 0x2019, 0x2624, 0x7b32, 0x7b36, 0x007c, + 0x6950, 0xa185, 0x0000, 0x0040, 0x49ad, 0x0c7e, 0x6ac0, 0x2264, + 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, 0xc0b5, 0x600a, 0x8210, + 0x8109, 0x00c0, 0x499f, 0x6952, 0x0c7f, 0x007c, 0x70ec, 0xd0dc, + 0x00c0, 0x49b7, 0xd0d4, 0x0040, 0x49d6, 0x0078, 0x49d9, 0x7810, + 0xd0ec, 0x0040, 0x49c2, 0xc0f5, 0x7812, 0xd0ec, 0x0040, 0x49dd, + 0x0078, 0x49d9, 0xae8e, 0x0100, 0x0040, 0x49ce, 0x7814, 0xc0f5, + 0x7816, 0xd0d4, 0x00c0, 0x49dd, 0x0078, 0x49d9, 0x7814, 0xc0fd, + 0x7816, 0xd0d4, 0x00c0, 0x49dd, 0x0078, 0x49d9, 0xd0e4, 0x0040, + 0x49df, 0x7804, 0xd08c, 0x0040, 0x49df, 0x681f, 0x000c, 0x70a0, + 0x70a2, 0x007c, 0x699a +}; +unsigned short ql12_risc_code_length01 = 0x39e3; + diff -Naur linux.2210/drivers/scsi/qla1280.c linux.2210.vw/drivers/scsi/qla1280.c --- linux.2210/drivers/scsi/qla1280.c Wed Dec 31 16:00:00 1969 +++ linux.2210.vw/drivers/scsi/qla1280.c Wed Jul 28 08:56:41 1999 @@ -0,0 +1,6514 @@ +/*************************************************************************** + * QLogic ISP1280 device driver for Linux 2.0.36 (redhat 5.2). + * + * COPYRIGHT (C) 1996-1999 QLOGIC CORPORATION + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + *****************************************************************************/ +/**************************************************************************** + Revision History: + Rev. 2.00 June 8, 1999 D Grigsby + Changes to support RedHat release 6.0 (kernel 2.2.5). + - Added SCSI exclusive access lock (io_request_lock) when accessing the adapter. + - Added changes for the new LINUX interface template. Some new error handling + routines have been added to the template, but for now we will use the old ones. + + - Initial Beta Release. +*****************************************************************************/ + + +#include /* for CONFIG_PCI */ +#include /* for KERNEL_VERSION */ +#ifdef MODULE +#include +#endif + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +# include +#endif +#include "sd.h" +#include "scsi.h" +#include "hosts.h" +#include "qla1280.h" +#include "qla1280host.h" +#include "isp_fw.h" /* ISP RISC code */ + +#include +#include /* for kmalloc() */ + + + +/* + * Compile time Options: + * 0 - Disable and 1 - Enable + */ +#define QLA1280_64BIT_SUPPORT 0 /* 64-bit Support */ +#define QL1280_TARGET_MODE_SUPPORT 0 /* Target mode support */ +#define WATCHDOGTIMER 0 +#define MEMORY_MAPPED_IO 0 +#define DEBUG_QLA1280_INTR 0 +#define USE_NVRAM_DEFAULTS 0 +#define DEBUG_PRINT_NVRAM 0 +#define LOADING_RISC_ACTIVITY 0 +#define AUTO_ESCALATE_RESET 0 /* Automatically escalate resets */ +#define AUTO_ESCALATE_ABORT 0 /* Automatically escalate aborts */ +#define STOP_ON_ERROR 0 /* Stop on aborts and resets */ +#define STOP_ON_RESET 0 +#define STOP_ON_ABORT 0 + +#define DEBUG_QLA1280 0 /* Debugging */ + +/* + * These macros to assist programming + */ + +#define BZERO(ptr, amt) memset(ptr, 0, amt) +#define BCOPY(src, dst, amt) memcpy(dst, src, amt) +#define KMALLOC(siz) kmalloc((siz), GFP_ATOMIC) +#define KMFREE(ip,siz) kfree((ip)) +#define SYS_DELAY(x) udelay(x);barrier() +#define QLA1280_DELAY(sec) mdelay(sec * 1000) +#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a)) +#if QLA1280_64BIT_SUPPORT +#define VIRT_TO_BUS_LOW(a) (unsigned int)(0xffffffff & virt_to_bus((void *)(a))) +#define VIRT_TO_BUS_HIGH(a) (unsigned int)(0xffffffff & (virt_to_bus((void *)(a))>>32)) +#endif /* QLA1280_64BIT_SUPPORT */ + +#define STATIC + +#define NVRAM_DELAY() udelay(500) /* 2 microsecond delay */ + +#if 0 /* XXX BH */ +/* + * Linux - SCSI Driver Interface Function Prototypes. + */ +int qla1280_proc_info ( char *, char **, off_t, int, int, int); +const char * qla1280_info(struct Scsi_Host *host); +int qla1280_detect(Scsi_Host_Template *); +int qla1280_release(struct Scsi_Host *); +const char * qla1280_info(struct Scsi_Host *); +int qla1280_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int qla1280_abort(Scsi_Cmnd *); +int qla1280_reset(Scsi_Cmnd *, unsigned int); +int qla1280_biosparam(Disk *, kdev_t, int[]); +void qla1280_intr_handler(int, void *, struct pt_regs *); +void qla1280_setup(char *s, int *dummy); +#endif +STATIC void qla1280_device_queue_depth(scsi_qla_host_t *, Scsi_Device *); + +/* + * QLogic Driver Support Function Prototypes. + */ +STATIC void qla1280_done(scsi_qla_host_t *, srb_t **, srb_t **); +STATIC void qla1280_next(scsi_qla_host_t *, scsi_lu_t *, uint8_t); +STATIC void qla1280_putq_t(scsi_lu_t *, srb_t *); +STATIC void qla1280_done_q_put(srb_t *, srb_t **, srb_t **); +STATIC void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *); +#ifdef QLA1280_UNUSED +static void qla1280_dump_regs(struct Scsi_Host *host); +#endif +#if STOP_ON_ERROR +static void qla1280_panic(char *, struct Scsi_Host *host); +#endif +void qla1280_print_scsi_cmd(Scsi_Cmnd *cmd); +STATIC void qla1280_abort_queue_single(scsi_qla_host_t *,uint32_t,uint32_t,uint32_t,uint32_t); + +STATIC int qla1280_return_status( sts_entry_t *sts, Scsi_Cmnd *cp); +STATIC void qla1280_removeq(scsi_lu_t *q, srb_t *sp); +STATIC void qla1280_mem_free(scsi_qla_host_t *ha); +void qla1280_do_dpc(void *p); +#ifdef QLA1280_UNUSED +static void qla1280_set_flags(char * s); +#endif +static char *qla1280_get_token(char *, char *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +STATIC inline void mdelay(int); +#endif + +/* + * QLogic ISP1280 Hardware Support Function Prototypes. + */ +STATIC uint8_t qla1280_initialize_adapter(struct scsi_qla_host *ha); +STATIC uint8_t qla1280_enable_tgt(scsi_qla_host_t *, uint8_t); +STATIC uint8_t qla1280_isp_firmware(scsi_qla_host_t *); +STATIC uint8_t qla1280_pci_config(scsi_qla_host_t *); +STATIC uint8_t qla1280_chip_diag(scsi_qla_host_t *); +STATIC uint8_t qla1280_setup_chip(scsi_qla_host_t *); +STATIC uint8_t qla1280_init_rings(scsi_qla_host_t *); +STATIC uint8_t qla1280_nvram_config(scsi_qla_host_t *); +STATIC uint8_t qla1280_mailbox_command(scsi_qla_host_t *, uint8_t, uint16_t *); +STATIC uint8_t qla1280_bus_reset(scsi_qla_host_t *, uint8_t); +STATIC uint8_t qla1280_device_reset(scsi_qla_host_t *, uint8_t, uint32_t); +STATIC uint8_t qla1280_abort_device(scsi_qla_host_t *, uint8_t, uint32_t, uint32_t); +STATIC uint8_t qla1280_abort_command(scsi_qla_host_t *, srb_t *), +#if QLA1280_64BIT_SUPPORT + qla1280_64bit_start_scsi(scsi_qla_host_t *, srb_t *), +#endif + qla1280_32bit_start_scsi(scsi_qla_host_t *, srb_t *), + qla1280_abort_isp(scsi_qla_host_t *); +STATIC void qla1280_nv_write(scsi_qla_host_t *, uint16_t), + qla1280_nv_delay(scsi_qla_host_t *), + qla1280_poll(scsi_qla_host_t *), + qla1280_reset_adapter(scsi_qla_host_t *), + qla1280_marker(scsi_qla_host_t *, uint8_t, uint32_t, uint32_t, uint8_t), + qla1280_isp_cmd(scsi_qla_host_t *), + qla1280_isr(scsi_qla_host_t *, srb_t **, srb_t **), + qla1280_rst_aen(scsi_qla_host_t *), + qla1280_status_entry(scsi_qla_host_t *, sts_entry_t *, srb_t **, + srb_t **), + qla1280_error_entry(scsi_qla_host_t *, response_t *, srb_t **, + srb_t **), + qla1280_restart_queues(scsi_qla_host_t *), + qla1280_abort_queues(scsi_qla_host_t *); +STATIC uint16_t qla1280_get_nvram_word(scsi_qla_host_t *, uint32_t), + qla1280_nvram_request(scsi_qla_host_t *, uint32_t), + qla1280_debounce_register(volatile uint16_t *); +STATIC request_t *qla1280_req_pkt(scsi_qla_host_t *); +int qla1280_check_for_dead_scsi_bus(scsi_qla_host_t *ha, srb_t *sp); + +#if QL1280_TARGET_MODE_SUPPORT + qla1280_enable_lun(scsi_qla_host_t *, uint8_t, uint32_t), + qla1280_notify_ack(scsi_qla_host_t *, notify_entry_t *), + qla1280_immed_notify(scsi_qla_host_t *, notify_entry_t *), + qla1280_accept_io(scsi_qla_host_t *, ctio_ret_entry_t *), +#if QLA1280_64BIT_SUPPORT + qla1280_64bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, + paddr32_t *), +#endif + qla1280_32bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, + paddr32_t *), + qla1280_atio_entry(scsi_qla_host_t *, atio_entry_t *), + qla1280_notify_entry(scsi_qla_host_t *, notify_entry_t *), + +#endif /* QLA1280_TARGET_MODE_SUPPORT */ + +#ifdef QL_DEBUG_ROUTINES +/* + * Driver Debug Function Prototypes. + */ +STATIC uint8_t qla1280_getbyte(uint8_t *); +STATIC uint16_t qla1280_getword(uint16_t *); +STATIC uint32_t qla1280_getdword(uint32_t *); +STATIC void qla1280_putbyte(uint8_t *, uint8_t), + qla1280_putword(uint16_t *, uint16_t), + qla1280_putdword(uint32_t *, uint32_t), + qla1280_print(caddr_t), + qla1280_output_number(uint32_t, uint8_t), + qla1280_putc(uint8_t), + qla1280_dump_buffer(caddr_t, uint32_t); + +char debug_buff[80]; +#if DEBUG_QLA1280 +STATIC uint8_t ql_debug_print = 1; +#else +STATIC uint8_t ql_debug_print = 0; +#endif +#endif + +/* + * insmod needs to find the variable and make it point to something + */ +#ifdef MODULE +static char *options = NULL; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18) + +/* insmod qla1280 options=verbose" */ +MODULE_PARM(options, "s"); +#endif +/* + * Just in case someone uses commas to separate items on the insmod + * command line, we define a dummy buffer here to avoid having insmod + * write wild stuff into our code segment + */ +static char dummy_buffer[60] = "Please don't add commas in your insmod command!!\n"; + +#endif + +#if defined(__386__) +# define QLA1280_BIOSPARAM qla1280_biosparam +#else +# define QLA1280_BIOSPARAM NULL +#endif + +/* + * Scsi_Host_template (see hosts.h) + * Device driver Interfaces to mid-level SCSI driver. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +/* This interface is now obsolete !!! */ +#define QLA1280_LINUX_TEMPLATE { \ + next: NULL, \ + usage_count: NULL, \ + proc_dir: NULL, \ + proc_info: NULL, \ + name: "Qlogic ISP 1280", \ + detect: qla1280_detect, \ + release: qla1280_release, \ + info: qla1280_info, \ + command: NULL, \ + queuecommand: qla1280_queuecommand, \ + abort: qla1280_abort, \ + reset: qla1280_reset, \ + slave_attach: NULL, \ + bios_param: QLA1280_BIOSPARAM, \ + can_queue: 255, /* MAX_OUTSTANDING_COMMANDS */ \ + this_id: -1, /* scsi id of host adapter */ \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 3, /* max commands per lun */ \ + present: 0, /* number of 1280s present */ \ + unchecked_isa_dma: 0, /* no memeory DMA restrictions */ \ + use_clustering: ENABLE_CLUSTERING \ +} +#else + +#if 0 /* XXX BH */ +#define QLA1280_LINUX_TEMPLATE { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: qla1280_proc_info, \ + name: "Qlogic ISP 1280\1080", \ + detect: qla1280_detect, \ + release: qla1280_release, \ + info: qla1280_info, \ + ioctl: NULL, \ + command: NULL, \ + queuecommand: qla1280_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: qla1280_abort, \ + reset: qla1280_reset, \ + slave_attach: NULL, \ + bios_param: QLA1280_BIOSPARAM, \ + can_queue: 255, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: SG_ALL, /* max scatter-gather cmds */\ + cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0, \ + emulated: 0 \ +} +#endif +#endif + + +/* + * Our directory Entry in /proc/scsi for the user to + * access the driver. + */ + +/* Need to add in proc_fs.h PROC_SCSI_QL1280 */ +#define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP + +struct proc_dir_entry proc_scsi_qla1280 = { + PROC_SCSI_QL1280, 7, "qla1280", + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +/* We use the Scsi_Pointer structure that's included with each command + * SCSI_Cmnd as a scratchpad for our SRB. + * + * SCp will always point to the SRB structure (defined in qla1280.h). + * It is define as follows: + * - SCp.ptr -- > pointer back to the cmd + * - SCp.this_residual --> used as forward pointer to next srb + * - SCp.buffer --> used as backward pointer to next srb + * - SCp.buffers_residual --> used as flags field + * - SCp.have_data_in --> not used + * - SCp.sent_command --> not used + * - SCp.phase --> not used + */ + +#define CMD_SP(Cmnd) (&(Cmnd)->SCp) +#define CMD_XFRLEN(Cmnd) (Cmnd)->request_bufflen +#define CMD_CDBLEN(Cmnd) (Cmnd)->cmd_len +#define CMD_CDBP(Cmnd) (Cmnd)->cmnd +#define CMD_SNSP(Cmnd) (Cmnd)->sense_buffer +#define CMD_SNSLEN(Cmnd) (sizeof (Cmnd)->sense_buffer) +#define CMD_RESULT(Cmnd) ((Cmnd)->result) +#define CMD_HANDLE(Cmnd) ((Cmnd)->host_scribble) + +/*****************************************/ +/* ISP Boards supported by this driver */ +/*****************************************/ +#define QLA1280_VENDOR_ID 0x1077 +#define QLA1080_DEVICE_ID 0x1080 +#define QLA1240_DEVICE_ID 0x1240 +#define QLA1280_DEVICE_ID 0x1280 +#define NUM_OF_ISP_DEVICES 4 + +#define QLA1280_VERSION " 1.20-Beta" +typedef struct _qlaboards +{ + unsigned char bdName[9]; + unsigned long device_id; + int numPorts; +} qla_boards_t; + +struct _qlaboards QLBoardTbl[NUM_OF_ISP_DEVICES] = +{ + /* Name , Board PCI Device ID, Number of ports */ + {"QLA1080 ", QLA1080_DEVICE_ID, 1}, + {"QLA1240 ", QLA1240_DEVICE_ID, 2}, + {"QLA1280 ", QLA1280_DEVICE_ID, 2}, + {" ", 0, 0} +}; + +static unsigned long qla1280_verbose = 1L; +static scsi_qla_host_t *qla1280_hostlist = NULL; +static int qla1280_buffer_size = 0; +static char *qla1280_buffer = NULL; + +#ifdef QL_DEBUG_LEVEL_3 +#define ENTER(x) sprintf(debug_buff,"qla1280 : Entering %s()\n\r", x); \ + qla1280_print(debug_buff); +#define LEAVE(x) sprintf(debug_buff,"qla1280 : Leaving %s()\n\r", x); \ + qla1280_print(debug_buff); +#define ENTER_INTR(x) sprintf(debug_buff,"qla1280 : Entering %s()\n\r", x); \ + qla1280_print(debug_buff); +#define LEAVE_INTR(x) sprintf(debug_buff,"qla1280 : Leaving %s()\n\r", x); \ + qla1280_print(debug_buff); +#define DEBUG3(x) x +#else +#define ENTER(x) +#define LEAVE(x) +#define ENTER_INTR(x) +#define LEAVE_INTR(x) +#define DEBUG3(x) +#endif + +#if DEBUG_QLA1280 +#define COMTRACE(x) +/* #define COMTRACE(x) qla1280_putc(x); */ +#define DEBUG(x) x +#else +#define DEBUG(x) +#define COMTRACE(x) +#endif + +#ifdef QL_DEBUG_LEVEL_2 +#define DEBUG2(x) x +#else +#define DEBUG2(x) +#endif + +#define OFFSET(w) (((uint32_t) &w) & 0xFFFF) /* 256 byte offsets */ + +#define SCSI_BUS_32(scp) ((scp)->channel) +#define SCSI_TCN_32(scp) ((scp)->target) +#define SCSI_LUN_32(scp) ((scp)->lun) + +/****************************************************************************/ +/* LINUX - Loadable Module Functions. */ +/****************************************************************************/ + + +/************************************************************************* + * qla1280_set_info + * + * Description: + * Set parameters for the driver from the /proc filesystem. + * + * Returns: + *************************************************************************/ +int +qla1280_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) +{ + return (-ENOSYS); /* Currently this is a no-op */ +} + +/************************************************************************* + * qla1280_proc_info + * + * Description: + * Return information to handle /proc support for the driver. + * + * buffer - ptrs to a page buffer + * + * Returns: + *************************************************************************/ +#define PROC_BUF (&qla1280_buffer[size]) +#define LUN_ID (targ_lun>>(MAX_T_BITS+MAX_L_BITS)),((targ_lun>>MAX_L_BITS)&0xf), targ_lun&0x7 +int +qla1280_proc_info ( char *buffer, char **start, off_t offset, int length, + int hostno, int inout) +{ + struct Scsi_Host *host; + scsi_qla_host_t *ha; + int size = 0; + int targ_lun; + scsi_lu_t *up; + int no_devices; + + printk("Entering proc_info 0x%x,0x%lx,0x%x,0x%x\n",(int)buffer,offset,length,hostno); + host = NULL; + /* find the host they want to look at */ + for(ha=qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno; ha=ha->next) + ; + + if (!ha) + { + size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if (size > length) + { + return (size); + } + else + { + return (length); + } + } + + host = ha->host; + if (inout == TRUE) /* Has data been written to the file? */ + { + return (qla1280_set_info(buffer, length, host)); + } + + /* compute number of active devices */ + no_devices = 0; + for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++) + { + if( (up = ha->dev[targ_lun]) == NULL ) + continue; + no_devices++; + } + /* size = 112 * no_devices; */ + size = 4096; + /* round up to the next page */ + + /* + * if our old buffer is the right size use it otherwise + * allocate a new one. + */ + if (qla1280_buffer_size != size) + { + /* deallocate this buffer and get a new one */ + if (qla1280_buffer != NULL) + { + kfree(qla1280_buffer); + qla1280_buffer_size = 0; + } + qla1280_buffer = kmalloc(size, GFP_KERNEL); + } + if (qla1280_buffer == NULL) + { + size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n", + __LINE__); + return size; + } + qla1280_buffer_size = size; + + size = 0; + size += sprintf(PROC_BUF, "Qlogic 1280/1080 SCSI driver version: "); /* 43 bytes */ + size += sprintf(PROC_BUF, "%5s, ", QLA1280_VERSION); /* 5 */ + size += sprintf(PROC_BUF, "Qlogic Firmware version: "); /* 25 */ + size += sprintf(PROC_BUF, "%2d.%2d.%2d",ql12_firmware_version[0], /* 8 */ + ql12_firmware_version[1], + ql12_firmware_version[2]); + size += sprintf(PROC_BUF, "\n"); /* 1 */ + + size += sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", QLBoardTbl[ha->devnum].bdName); + size += sprintf(PROC_BUF, "Request Queue = 0x%lx, Response Queue = 0x%lx\n", + ha->request_dma, + ha->response_dma); + size += sprintf(PROC_BUF, "Request Queue count= 0x%x, Response Queue count= 0x%x\n", + REQUEST_ENTRY_CNT, + RESPONSE_ENTRY_CNT); + size += sprintf(PROC_BUF,"Number of pending commands = 0x%lx\n", ha->actthreads); + size += sprintf(PROC_BUF,"Number of queued commands = 0x%lx\n", ha->qthreads); + size += sprintf(PROC_BUF,"Number of free request entries = %d\n",ha->req_q_cnt); + size += sprintf(PROC_BUF, "\n"); /* 1 */ + + size += sprintf(PROC_BUF, "Attached devices:\n"); + /* scan for all equipment stats */ + for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++) + { + if( (up = ha->dev[targ_lun]) == NULL ) + continue; + if( up->io_cnt == 0 ) + { + size += sprintf(PROC_BUF,"(%2d:%2d:%2d) No stats\n",LUN_ID); + continue; + } + /* total reads since boot */ + /* total writes since boot */ + /* total requests since boot */ + size += sprintf(PROC_BUF, "Total requests %ld,",up->io_cnt); + /* current number of pending requests */ + size += sprintf(PROC_BUF, "(%2d:%2d:%2d) pending requests %d,",LUN_ID,up->q_outcnt); + /* avg response time */ + size += sprintf(PROC_BUF, "Avg response time %ld%%,",(up->resp_time/up->io_cnt)*100); + + /* avg active time */ + size += sprintf(PROC_BUF, "Avg active time %ld%%\n",(up->act_time/up->io_cnt)*100); + } + + if (size >= qla1280_buffer_size) + { + printk(KERN_WARNING "qla1280: Overflow buffer in qla1280_proc.c\n"); + } + + if (offset > size - 1) + { + kfree(qla1280_buffer); + qla1280_buffer = NULL; + qla1280_buffer_size = length = 0; + *start = NULL; + } + else + { + *start = &qla1280_buffer[offset]; /* Start of wanted data */ + if (size - offset < length) + { + length = size - offset; + } + } + + return (length); +} + + +/************************************************************************** + * qla1280_detect + * This routine will probe for Qlogic 1280 SCSI host adapters. + * It returns the number of host adapters of a particular + * type that were found. It also initialize all data necessary for + * the driver. It is passed-in the host number, so that it + * knows where its first entry is in the scsi_hosts[] array. + * + * Input: + * template - pointer to SCSI template + * + * Returns: + * num - number of host adapters found. + **************************************************************************/ +int +qla1280_detect(Scsi_Host_Template *template) +{ + int num_hosts = 0; + struct Scsi_Host *host; + scsi_qla_host_t *ha, *cur_ha; + struct _qlaboards *bdp; + int i, index, j; + unsigned int piobase; + unsigned char pci_bus, pci_devfn, pci_irq; + config_reg_t *cfgp = 0; + device_reg_t *reg; + char *cp; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + struct pci_dev *pdev = NULL; +#endif + + ENTER("qla1280_detect"); + +#ifdef CHECKSRBSIZE + if (sizeof(srb_t) > sizeof(Scsi_Pointer) ) + { + printk("Redefine SRB - its too big"); + return 0; + } +#endif + +#ifdef MODULE + /* + * If we are called as a module, the qla1280 pointer may not be null + * and it would point to our bootup string, just like on the lilo + * command line. IF not NULL, then process this config string with + * qla1280_setup + * + * Boot time Options + * To add options at boot time add a line to your lilo.conf file like: + * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" + * which will result in the first four devices on the first two + * controllers being set to a tagged queue depth of 32. + */ + if(options) + qla1280_setup(options, NULL); + if(dummy_buffer[0] != 'P') + printk(KERN_WARNING "qla1280: Please read the file /usr/src/linux/drivers" + "/scsi/README.qla1280\n" + "qla1280: to see the proper way to specify options to the qla1280 " + "module\n" + "qla1280: Specifically, don't use any commas when passing arguments to\n" + "qla1280: insmod or else it might trash certain memory areas.\n"); +#endif + + if ((int) pcibios_present()) + { + bdp = &QLBoardTbl[0]; + qla1280_hostlist = NULL; + template->proc_dir = &proc_scsi_qla1280; + for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) + { + /* Try and find each different type of adapter we support */ + index = 0; + while (!(pcibios_find_device(QLA1280_VENDOR_ID, + bdp->device_id, + index++, &pci_bus, &pci_devfn)) ) + { /* found a adapter */ + host = scsi_register(template, sizeof(scsi_qla_host_t)); + ha = (scsi_qla_host_t *) host->hostdata; + for( j =0, cp = (char *)ha; j < sizeof(scsi_qla_host_t); j++) + *cp = 0; + /* Sanitize the information from PCI BIOS. */ +#if 0 + pcibios_read_config_byte(pci_bus, pci_devfn, OFFSET(cfgp->interrupt_line), &pci_irq); +#else + pdev = pci_find_slot(pci_bus, pci_devfn); + pci_irq = pdev->irq; +#endif + pcibios_read_config_dword(pci_bus, pci_devfn, OFFSET(cfgp->base_port), &piobase); + ha->pci_bus = pci_bus; + ha->pci_device_fn = pci_devfn; + ha->devnum = i; + + host->io_port = (unsigned int) piobase; + host->io_port &= PCI_BASE_ADDRESS_IO_MASK; + host->irq = pci_irq; + ha->request_ring = &ha->req[0]; + ha->request_dma = VIRT_TO_BUS(&ha->req[0]); + ha->response_ring = &ha->res[0]; + ha->response_dma = VIRT_TO_BUS(&ha->res[0]); + ha->ports = bdp->numPorts; + if( qla1280_verbose ) + { + printk("(scsi): Found a %s @ bus %2d, device %2d, irq %2d, iobase 0x%lx\n", + bdp->bdName,pci_bus, (pci_devfn & 0xf8) >> 3, host->irq,host->io_port); + printk("(scsi): Initializing Adapter; Please wait ...\n"); + } + + ha->iobase = (device_reg_t *) host->io_port; + ha->host = host; + ha->host_no = host->host_no; + + /* load the F/W, read paramaters, and init the H/W */ + if (qla1280_initialize_adapter(ha)) + { + + printk(KERN_INFO "qla1280: Failed to initialized adapter\n"); + qla1280_mem_free(ha); + scsi_unregister(host); + continue; + } + host->can_queue = 0xfffff; /* unlimited */ + host->cmd_per_lun = 1; + host->select_queue_depths = qla1280_select_queue_depth; + host->n_io_port = 0xFF; + host->base = (unsigned char *) ha->mmpbase; + host->max_id = MAX_TARGETS; + host->max_channel = bdp->numPorts-1; + host->max_lun = MAX_LUNS-1; + ha->instance = num_hosts; + host->unique_id = ha->instance; + ha->next = NULL; + + /* set our host ID (need to do something about our two IDs) */ + host->this_id = ha->bus_settings[0].id; + + /* Register the IRQ with Linux (sharable) */ + if ( request_irq(host->irq, qla1280_intr_handler, SA_INTERRUPT| SA_SHIRQ, "qla1280", ha)) + { + printk("qla1280 : Failed to reserved interrupt %d already in use\n", host->irq); + qla1280_mem_free(ha); + scsi_unregister(host); + continue; + } + + /* Register the I/O space with Linux */ + if (check_region(host->io_port, 0xff)) + { + printk("qla1280 : Failed to reserved i/o region 0x%04lx-0x%04lx already in use\n", + host->io_port, host->io_port + 0xff); + free_irq(host->irq, NULL); + qla1280_mem_free(ha); + scsi_unregister(host); + continue; + } + + request_region(host->io_port, 0xff, "qla1280"); + + reg = ha->iobase; + /* Disable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, 0); + + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); + + /* Enable chip interrupts. */ + WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC); + /* Insert new entry into the list of adapters */ + ha->next = NULL; + if( qla1280_hostlist == NULL ) + { + cur_ha = qla1280_hostlist = ha; + } + else + { + cur_ha = qla1280_hostlist; + while( cur_ha->next != NULL ) + cur_ha = cur_ha->next; + cur_ha->next = ha; + } + num_hosts++; + } /* end of WHILE */ + } /* end of FOR */ + } /* end of IF */ + + LEAVE("qla1280_detect"); + return num_hosts; +} + + +/************************************************************************** + * qla1280_release + * Free the passed in Scsi_Host memory structures prior to unloading the + * module. + **************************************************************************/ +int +qla1280_release(struct Scsi_Host *host) +{ + scsi_qla_host_t *ha = (scsi_qla_host_t *) host->hostdata; + + ENTER("qla1280_release"); + + if( !ha->flags.online ) + return(0); + + /* turn-off interrupts on the card */ + WRT_REG_WORD(&ha->iobase->ictrl, 0); + + /* Detach interrupts */ + if(host->irq) + free_irq(host->irq, ha); + + /* release io space registers */ + if( host->io_port ) + release_region(host->io_port, 0xff); + +#if MEMORY_MAPPED_IO + if(ha->mmpbase) + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) + vfree((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK)); +#else + iounmap((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK)); +#endif + } +#endif /* MEMORY_MAPPED_IO */ + qla1280_mem_free(ha); + + ENTER("qla1280_release"); + return(0); +} + +/************************************************************************** + * qla1280_info + * Return a string describing the driver. + **************************************************************************/ +const char * +qla1280_info(struct Scsi_Host *host) +{ + static char qla1280_buffer[125]; + char *bp; + scsi_qla_host_t *ha; + qla_boards_t *bdp; + + bp = &qla1280_buffer[0]; + ha = (scsi_qla_host_t *)host->hostdata; + bdp = &QLBoardTbl[ha->devnum]; + memset(bp, 0, sizeof(qla1280_buffer)); + sprintf(bp, + "QLogic %sPCI to SCSI Host Adapter: bus %d device %d irq %d\n" + " Version: %s, Firmware version: %s", + (char *)&bdp->bdName[0], ha->pci_bus, (ha->pci_device_fn & 0xf8) >> 3, host->irq, + QLA1280_VERSION, + QL12_FW_VERSION_STRING); + return(bp); +} + +/************************************************************************** + * qla1200_queuecommand + * Queue a command to the controller. + * + * 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). Unfortunely, it sometimes calls the scheduler in interrupt + * context which is a big NO! NO!. + **************************************************************************/ +int +qla1280_queuecommand(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) +{ + scsi_qla_host_t *ha; + srb_t *sp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + struct Scsi_Host *host; + uint32_t b, t, l; + scsi_lu_t *q; + u_long handle; + + ENTER("qla1280_queuecommand"); + COMTRACE('C') + + host = cmd->host; + ha = (scsi_qla_host_t *) host->hostdata; + + /* send command to adapter */ + sp = (srb_t *) CMD_SP(cmd); + sp->cmd = cmd; + cmd->scsi_done = fn; + if (cmd->flags == 0) /* new command */ + { + sp->flags = 0; + } + + +#if DEBUG_QLA1280 + DEBUG3(qla1280_print_scsi_cmd(cmd)); +#endif /* DEBUG_QLA1280 */ + + /* Generate LU queue on bus, target, LUN */ + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + if((q = LU_Q(ha, b, t, l)) == NULL ) + { + DRIVER_LOCK + if( (q = (scsi_lu_t *)KMALLOC(sizeof(struct scsi_lu))) ) + { + LU_Q(ha, b, t, l) = q; + BZERO(q,sizeof(struct scsi_lu)); + DEBUG(sprintf(debug_buff,"Allocate new device queue 0x%x\n",q)); + DEBUG(qla1280_print(debug_buff)); + DRIVER_UNLOCK + } + else + { + CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16); + qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); + queue_task(&ha->run_qla_bh,&tq_scheduler); + ha->flags.dpc_sched = TRUE; + DRIVER_UNLOCK + return(0); + } + } + + handle = MAX_OUTSTANDING_COMMANDS+1; + CMD_HANDLE(cmd) = (unsigned char *)handle; + + sp->r_start = jiffies; /* bookkeeping information */ + ha->qthreads++; + qla1280_putq_t(q,sp); + + DEBUG(sprintf(debug_buff,"qla1280: queueing SP=(0x%x), handle=(0x%x)\n\r",sp,handle)); + DEBUG(qla1280_print(debug_buff)); + /* we can take an unlimited number of SG elements */ + host->sg_tablesize = SG_ALL; + + + /* kick off a command */ + DRIVER_LOCK + if (q->q_outcnt == 0) + qla1280_restart_queues(ha); + DRIVER_UNLOCK + + LEAVE("qla1280_queuecommand"); + return (0); +} + +/************************************************************************** + * qla1200_abort + * Abort the speciifed SCSI command(s). + **************************************************************************/ +int +qla1280_abort(Scsi_Cmnd *cmd) +{ + scsi_qla_host_t *ha; + srb_t *sp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + struct Scsi_Host *host; + uint32_t b, t, l; + scsi_lu_t *q; + int return_status = SCSI_ABORT_SUCCESS; + int found = 0; + int i; + u_long handle; + u_short data; + + ENTER("qla1280_abort"); + COMTRACE('A') + ha = (scsi_qla_host_t *) cmd->host->hostdata; + host = cmd->host; + DRIVER_LOCK + + sp = (srb_t *) CMD_SP(cmd); + handle = (u_long) CMD_HANDLE(cmd); + if (qla1280_verbose) + printk("scsi(%d): ABORT Command=0x%x, handle=0x%lx\n",(int)ha->host_no,(int)cmd,handle); + + /* Check for pending interrupts. */ + if( handle == 0L ) + { + COMTRACE('a') + /* we never got this command */ + printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); + DRIVER_UNLOCK + return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */ + } + data = qla1280_debounce_register(&ha->iobase->istatus); + if( !(ha->flags.in_isr) && (data & RISC_INT) ) + { + /* put any pending command in done queue */ + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + + handle = (u_long) CMD_HANDLE(cmd); + + /* Generate LU queue on bus, target, LUN */ + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + if((q = LU_Q(ha, b, t, l)) == NULL ) + { + COMTRACE('a') + /* No lun queue -- command must not be active */ + DRIVER_UNLOCK + printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the specified device\n",(int)b,(int)t,(int)l); + return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */ + } + +#if AUTO_ESCALATE_ABORT + if ( (sp->flags & SRB_ABORTED) ) + { + DRIVER_UNLOCK + DEBUG(qla1280_print("qla1280_abort: Abort escalayted - returning SCSI_ABORT_SNOOZE.\n\r")); + return(SCSI_ABORT_SNOOZE); + } +#endif + + if ( (sp->flags & SRB_ABORT_PENDING) ) + { + COMTRACE('a') + DRIVER_UNLOCK + if( qla1280_verbose ) + printk("scsi(): Command has a pending abort message - ABORT_PENDING.\n"); + DEBUG(qla1280_print("qla1280: Command has a pending abort message - ABORT_PENDING.\n\r")); + return(SCSI_ABORT_PENDING); + } + +#if STOP_ON_ABORT + printk("Scsi layer issued a ABORT command= 0x%x\n",(int)cmd); + DEBUG2(qla1280_print_scsi_cmd(cmd)); +#endif + + ha->flags.in_abort = TRUE; + /* + * Normally, would would need to search our queue for the specified command + * but; since our sp contains the cmd ptr, we can just remove it from our + * LUN queue. + */ + if( !(sp->flags&SRB_SENT) ) + { + found++; + if( qla1280_verbose ) + printk("scsi(): Command returned from queue aborted.\n"); + DEBUG(qla1280_print("qla1280: Command returned from queue aborted.\n\r")); + /* Remove srb from SCSI LU queue. */ + qla1280_removeq(q, sp); + sp->flags |= SRB_ABORTED; + CMD_RESULT(cmd) = DID_ABORT << 16; + qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); + return_status = SCSI_ABORT_SUCCESS; + } + else + { /* find the command in our active list */ + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) + { + if( sp == ha->outstanding_cmds[i] ) + { + found++; + DEBUG(qla1280_print("qla1280: RISC aborting command.\n\r")); + qla1280_abort_command(ha,sp); + return_status = SCSI_ABORT_PENDING; + break; + } + } + } + +#if STOP_ON_ABORT + qla1280_panic("qla1280_abort",ha->host); +#endif + if ( found == 0 ) + return_status = SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ + + DEBUG(sprintf(debug_buff, "qla1280_abort: Aborted status returned = 0x%x.\n\r",return_status)); + DEBUG(qla1280_print(debug_buff)); + + if( ha->done_q_first ) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + if ( found ) + { + qla1280_restart_queues(ha); + } + ha->flags.in_abort = FALSE; + DRIVER_UNLOCK + + LEAVE("qla1280_abort"); + COMTRACE('a') + return(return_status); +} + +/************************************************************************** + * qla1200_reset + * The reset function will reset the SCSI bus and abort any executing + * commands. + * + * Input: + * cmd = Linux SCSI command packet of the command that cause the + * bus reset. + * flags = SCSI bus reset option flags (see scsi.h) + * + * Returns: + * DID_RESET in cmd.host_byte of aborted command(s) + * + * Note: + * Resetting the bus always succeeds - is has to, otherwise the + * kernel will panic! Try a surgical technique - sending a BUS + * DEVICE RESET message - on the offending target before pulling + * the SCSI bus reset line. + **************************************************************************/ +int +qla1280_reset(Scsi_Cmnd *cmd, unsigned int flags) +{ + scsi_qla_host_t *ha; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + uint32_t b, t, l; + srb_t *sp; + typedef enum + { + ABORT_DEVICE = 1, + DEVICE_RESET = 2, + BUS_RESET = 3, + ADAPTER_RESET= 4, + RESET_DELAYED= 5, + FAIL = 6 + } action_t; + action_t action = ADAPTER_RESET; + u_short data; + scsi_lu_t *q; + int result; + + + ENTER("qla1280_reset"); + COMTRACE('R') + if (qla1280_verbose) + printk("scsi(): Resetting Cmnd=0x%x, Handle=0x%lx, flags=0x%x\n",(int)cmd,(long)CMD_HANDLE(cmd),flags); + if ( cmd == NULL ) + { + printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " + "pointer, failing.\n"); + return(SCSI_RESET_SNOOZE); + } + ha = (scsi_qla_host_t *) cmd->host->hostdata; + sp = (srb_t *) CMD_SP(cmd); + +#if STOP_ON_RESET + qla1280_panic("qla1280_reset",ha->host); +#endif + + DRIVER_LOCK + /* Check for pending interrupts. */ + data = qla1280_debounce_register(&ha->iobase->istatus); + if( !(ha->flags.in_isr) && (data & RISC_INT) ) + { + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + DRIVER_UNLOCK + + /* + * Determine the suggested action that the mid-level driver wants + * us to perform. + */ + if( CMD_HANDLE(cmd) == (unsigned char *) 0 ) + { + /* + * if mid-level driver called reset with a orphan SCSI_Cmnd + * (i.e. a command that's not pending ), so perform the + * function specified. + */ + if( (flags & SCSI_RESET_SUGGEST_HOST_RESET) ) + action = ADAPTER_RESET; + else + action = BUS_RESET; + } + else + { /* + * Mid-level driver has called reset with this SCSI_Cmnd and + * its pending. + */ + if( flags & SCSI_RESET_SUGGEST_HOST_RESET ) + action = ADAPTER_RESET; + else if( flags & SCSI_RESET_SUGGEST_BUS_RESET ) + action = BUS_RESET; + else + action = DEVICE_RESET; + } + + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + q = LU_Q(ha, b, t, l); + +#if AUTO_ESCALATE_RESET + if ( (action & DEVICE_RESET) && (q->q_flag & QLA1280_QRESET) ) + { + printk(KERN_INFO "qla1280(%d): Bus device reset already sent to " "device, escalating.\n", (int)ha->host_no); + action = BUS_RESET; + } + if ( (action & DEVICE_RESET) && (sp->flags & SRB_ABORT_PENDING) ) + { + printk(KERN_INFO "qla1280(%d):Have already attempted to reach " "device with abort device\n", (int)ha->host_no); + printk(KERN_INFO "qla1280(%d):message, will escalate to BUS " "RESET.\n",(int) ha->host_no); + action = BUS_RESET; + } +#endif + + /* + * By this point, we want to already know what we are going to do, + * so we only need to perform the course of action. + */ + DRIVER_LOCK + result = SCSI_RESET_ERROR; + switch (action) + { + case FAIL: + break; + + case RESET_DELAYED: + result = SCSI_RESET_PENDING; + break; + + case ABORT_DEVICE: + ha->flags.in_reset = TRUE; + if (qla1280_verbose) + printk(KERN_INFO "scsi(%d:%d:%d:%d): Queueing abort device command.\n", (int)ha->host_no,(int)b,(int)t,(int)l); + qla1280_abort_queue_single(ha,b,t,l,DID_ABORT); + if( qla1280_abort_device(ha, b, t, l) == 0) + result = SCSI_RESET_PENDING; + break; + + case DEVICE_RESET: + if (qla1280_verbose) + printk(KERN_INFO "scsi(%d:%d:%d:%d): Queueing device reset command.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + ha->flags.in_reset = TRUE; + for (l = 0; l < MAX_LUNS; l++) + qla1280_abort_queue_single(ha,b,t,l,DID_ABORT); + if( qla1280_device_reset(ha, b, t) == 0 ) + result = SCSI_RESET_PENDING; + q->q_flag |= QLA1280_QRESET; + break; + + case BUS_RESET: + if (qla1280_verbose) + printk(KERN_INFO "qla1280(%d:%d:%d:%d): Issuing BUS DEVICE RESET.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + ha->flags.in_reset = TRUE; + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + qla1280_abort_queue_single(ha,b,t,l,DID_RESET); + qla1280_bus_reset(ha, b); + /* + * The bus reset routine returns all the outstanding commands back + * with "DID_RESET" in the status field after a short delay + * by the firmware. If the mid-level time out the SCSI reset before + * our delay we may need to ignore it. + */ + /* result = SCSI_RESET_PENDING | SCSI_RESET_BUS_RESET; */ + result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + mdelay(4 * 1000); barrier(); + if( flags & SCSI_RESET_SYNCHRONOUS ) + { + CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16); + (*(cmd)->scsi_done)(cmd); + } + /* ha->reset_start = jiffies; */ + break; + + case ADAPTER_RESET: + default: + if (qla1280_verbose) + { + printk(KERN_INFO "scsi(%d:%d:%d:%d): Issued an ADAPTER RESET.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + printk(KERN_INFO "scsi(%d:%d:%d:%d): I/O processing will continue automatically.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + } + ha->flags.reset_active = TRUE; + /* + * We restarted all of the commands automatically, so the mid-level code can expect + * completions momentitarily. + */ + if( qla1280_abort_isp(ha) == 0 ) + result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; + + ha->flags.reset_active = FALSE; + } + + if( ha->done_q_first ) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + qla1280_restart_queues(ha); + ha->flags.in_reset = FALSE; + +DRIVER_UNLOCK + DEBUG(printk("RESET returning %d\n", result)); + + COMTRACE('r') + LEAVE("qla1280_reset"); + return( result ); +} + +/************************************************************************** + * qla1200_biosparam + * Return the disk geometry for the given SCSI device. + **************************************************************************/ +int +qla1280_biosparam(Disk *disk, kdev_t dev, int geom[]) +{ + int heads, sectors, cylinders; + + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + if (cylinders > 1024) + { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + /* if (cylinders > 1023) + cylinders = 1023; */ + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return (0); +} +/************************************************************************** + * qla1280_intr_handler + * Handles the H/W interrupt + **************************************************************************/ +void qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + scsi_qla_host_t *ha; + u_short data; + device_reg_t *reg; + + ENTER_INTR("qla1280_intr_handler"); + COMTRACE('I') + ha = (scsi_qla_host_t *) dev_id; + if(!ha) + { + printk(KERN_INFO "scsi(): Interrupt with NULL host ptr\n"); + COMTRACE('X') + return; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) + spin_lock_irqsave(&io_request_lock, cpu_flags); + if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags)) + { + COMTRACE('X') + return; + } + ha->isr_count++; + reg = ha->iobase; + /* disable our interrupt. */ + WRT_REG_WORD(®->ictrl, 0); + data = qla1280_debounce_register(®->istatus); + /* Check for pending interrupts. */ + if ( !(data & RISC_INT) ) + { + /* spurious interrupts can happen legally */ + DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no)); + COMTRACE('X') + } + else + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + if (ha->done_q_first) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + clear_bit(QLA1280_IN_ISR_BIT, &ha->flags); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) */ + + if( test_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags) ) + { + COMTRACE('X') + printk(KERN_INFO "scsi(%d): Already in interrupt - returning \n", (int)ha->host_no); + return; + } + set_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags); + ha->isr_count++; + reg = ha->iobase; + /* disable our interrupt. */ + WRT_REG_WORD(®->ictrl, 0); + + data = qla1280_debounce_register(®->istatus); + /* Check for pending interrupts. */ + if ( !(data & RISC_INT) ) + { + /* spurious interrupts can happen legally */ + DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no)); + COMTRACE('X') + } + else + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + /* if no work to do then call the SCSI mid-level right away */ + if( ha->done_q_first ) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + /* Schedule the DPC routine */ + if (ha->flags.isp_abort_needed || ha->flags.reset_marker || + ha->done_q_first ) + { + ha->run_qla_bh.data = (void *) ha; + ha->run_qla_bh.routine = qla1280_do_dpc; + + COMTRACE('P') + queue_task_irq(&ha->run_qla_bh,&tq_scheduler); + ha->flags.dpc_sched = TRUE; + } + clear_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags); +#endif + /* enable our interrupt. */ + WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC); + + COMTRACE('i') + LEAVE_INTR("qla1280_intr_handler"); +} + +/************************************************************************** + * qla1280_do_dpc + * + * Description: + * This routine is a task that is schedule by the interrupt handler + * to perform the background processing for interrupts. We put it + * on a task queue that is consumed whenever the scheduler runs; that's + * so you can do anything (i.e. put the process to sleep etc). In fact, the + * mid-level tries to sleep when it reaches the driver threshold + * "host->can_queue". This can cause a panic if we were in our interrupt + * code . + **************************************************************************/ +void qla1280_do_dpc(void *p) +{ + scsi_qla_host_t *ha = (scsi_qla_host_t *) p; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + + COMTRACE('p') +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + spin_lock_irqsave(&io_request_lock, cpu_flags); +#endif + if (ha->flags.isp_abort_needed) + qla1280_abort_isp(ha); + + if (ha->flags.reset_marker) + qla1280_rst_aen(ha); + + if (ha->done_q_first) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + ha->flags.dpc_sched = FALSE; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +#endif +} + +/************************************************************************** + * qla1280_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). + **************************************************************************/ +STATIC void qla1280_device_queue_depth(scsi_qla_host_t *p, Scsi_Device *device) +{ + int default_depth = 3; + int bus = device->channel; + int target = device->id; + + device->queue_depth = default_depth; + + if (device->tagged_supported && + (p->bus_settings[bus].qtag_enables & (BIT_0 << target)) ) + { + device->tagged_queue = 1; + device->current_tag = 0; + device->queue_depth = p->bus_settings[bus].hiwat; + /* device->queue_depth = 20; */ + printk(KERN_INFO "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue depth %d.\n", + (int)p->host_no, device->channel, device->id, + device->lun, device->queue_depth); + } + +} + +/************************************************************************** + * qla1280_select_queue_depth + * + * Sets the queue depth for each SCSI device hanging off the input + * host adapter. We use a queue depth of 2 for devices that do not + * support tagged queueing. + **************************************************************************/ +STATIC void +qla1280_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) +{ + Scsi_Device *device; + scsi_qla_host_t *p = (scsi_qla_host_t *) host->hostdata; + + ENTER("qla1280_select_queue_depth"); + for (device = scsi_devs; device != NULL; device = device->next) + { + if (device->host == host) + qla1280_device_queue_depth(p, device); + } + LEAVE("qla1280_select_queue_depth"); +} + +/*--------------------------** +** Driver Support Routines ** +**--------------------------*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +/* + * mdelay + * Delay in milliseconds + * + * Input: + * milliseconds = delay + */ +STATIC inline void mdelay(int milliseconds) +{ + int i; + + for(i=0; is_next)) + *done_q_last = NULL; + else + (*done_q_first)->s_prev = NULL; + cmd = sp->cmd; + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + q = LU_Q(ha, b, t, l); + + /* Decrement outstanding commands on device. */ + if (q->q_outcnt) + q->q_outcnt--; + if (q->q_outcnt < ha->bus_settings[b].hiwat) + { + q->q_flag &= ~QLA1280_QBUSY; + } + + q->resp_time += jiffies - sp->r_start; /* Lun bookkeeping information */ + q->act_time += jiffies - sp->u_start; + q->io_cnt++; + if( sp->dir & BIT_5 ) + q->r_cnt++; + else + q->w_cnt++; + + switch ( (CMD_RESULT(cmd)>>16)) + { + case DID_RESET: + q->q_flag &= ~QLA1280_QRESET; + /* Issue marker command. */ + qla1280_marker(ha, b, t, 0, MK_SYNC_ID); + break; + case DID_ABORT: + sp->flags &= ~SRB_ABORT_PENDING; + sp->flags |= SRB_ABORTED; + if (sp->flags & SRB_TIMEOUT) + CMD_RESULT(sp->cmd)= DID_TIME_OUT << 16; + break; + default: + break; + } + + /* Call the mid-level driver interrupt handler */ + CMD_HANDLE(sp->cmd) = (unsigned char *) 0; + ha->actthreads--; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + sti(); + (*(cmd)->scsi_done)(cmd); + cli(); +#else + (*(cmd)->scsi_done)(cmd); +#endif + qla1280_next(ha, q, b); + } + DRIVER_UNLOCK + + + COMTRACE('d') + LEAVE("qla1280_done"); +} + +/* + * Translates a ISP error to a Linux SCSI error + */ +STATIC int qla1280_return_status( sts_entry_t *sts, Scsi_Cmnd *cp) +{ + int host_status = DID_ERROR; +#if DEBUG_QLA1280_INTR + 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 /* DEBUG_QLA1280_INTR */ + + ENTER("qla1280_return_status"); + +#if DEBUG_QLA1280_INTR + /* + DEBUG(printk("qla1280_return_status: compl status = 0x%04x\n", sts->comp_status)); + */ +#endif + switch(sts->comp_status) + { + case CS_COMPLETE: + host_status = DID_OK; + break; + case CS_INCOMPLETE: + if (!(sts->state_flags & SF_GOT_BUS)) + host_status = DID_NO_CONNECT; + else if (!(sts->state_flags & SF_GOT_TARGET)) + host_status = DID_BAD_TARGET; + else if (!(sts->state_flags & SF_SENT_CDB)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_STATUS)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_SENSE)) + host_status = DID_ERROR; + break; + case CS_RESET: + host_status = DID_RESET; + break; + case CS_ABORTED: + host_status = DID_ABORT; + break; + case CS_TIMEOUT: + host_status = DID_TIME_OUT; + break; + case CS_DATA_OVERRUN: +#ifdef QL_DEBUG_LEVEL_2 + printk("Data overrun 0x%x\n",(int)sts->residual_length); + qla1280_print( + "\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)sts, + RESPONSE_ENTRY_SIZE); +#endif + host_status = DID_ERROR; + break; + case CS_DATA_UNDERRUN: + if ( (CMD_XFRLEN(cp) - sts->residual_length) < cp->underflow) + { + printk("scsi: Underflow detected - retrying command.\n"); + host_status = DID_ERROR; + } + else + host_status = DID_OK; + break; + default: + host_status = DID_ERROR; + break; + } + +#if DEBUG_QLA1280_INTR + sprintf(debug_buff, "qla1280 ISP status: host status (%s) scsi status %x\n\r", reason[host_status], sts->scsi_status); + qla1280_print(debug_buff); +#endif + + LEAVE("qla1280_return_status"); + + return (sts->scsi_status & 0xff) | (host_status << 16); +} + +/* + * qla1280_done_q_put + * Place SRB command on done queue. + * + * Input: + * sp = srb pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + */ +STATIC void +qla1280_done_q_put(srb_t *sp, srb_t **done_q_first, srb_t **done_q_last) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_put_done_q"); +#endif + /* Place block on done queue */ + DRIVER_LOCK + sp->s_next = NULL; + sp->s_prev = *done_q_last; + if (!*done_q_first) + *done_q_first = sp; + else + (*done_q_last)->s_next = sp; + *done_q_last = sp; + + DRIVER_UNLOCK +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_put_done_q"); +#endif +} + +/* + * qla1280_next + * Retrieve and process next job in the queue. + * + * Input: + * ha = adapter block pointer. + * q = SCSI LU pointer. + * b = SCSI bus number. + * SCSI_LU_Q lock must be already obtained and no other locks. + * + * Output: + * Releases SCSI_LU_Q upon exit. + */ +STATIC void +qla1280_next(scsi_qla_host_t *ha, scsi_lu_t *q, uint8_t b) +{ + srb_t *sp; + uint32_t cnt; + uint8_t status; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + + ENTER("qla1280_next"); + + DRIVER_LOCK + while ( ((sp = q->q_first) != NULL) && /* we have a queue pending */ + !(q->q_flag & QLA1280_QBUSY) && /* device not busy */ + !ha->flags.abort_isp_active && /* not resetting the adapter */ + !(q->q_flag & QLA1280_QSUSP) ) /* device not suspended */ + { + /* Remove srb from SCSI LU queue. */ + qla1280_removeq(q, sp); + + DEBUG(sprintf(debug_buff,"starting request 0x%x<-(0x%x)\n\r",q,sp)); + DEBUG(qla1280_print(debug_buff)); + { + /* Set busy flag if reached high water mark. */ + q->q_outcnt++; + if (q->q_outcnt >= ha->bus_settings[b].hiwat) + q->q_flag |= QLA1280_QBUSY; + +#if QLA1280_64BIT_SUPPORT + if (ha->flags.enable_64bit_addressing) + status = qla1280_64bit_start_scsi(ha, sp); + else +#endif + status = qla1280_32bit_start_scsi(ha, sp); + + if (status) /* if couldn't start the request */ + { + if (q->q_outcnt == 1) + { + /* Release SCSI LU queue specific lock */ + QLA1280_SCSILU_UNLOCK(q); + + /* Wait for 30 sec for command to be accepted. */ + for (cnt = 6000000; cnt; cnt--) + { +#if QLA1280_64BIT_SUPPORT + if (ha->flags.enable_64bit_addressing) + status = qla1280_64bit_start_scsi(ha, sp); + else +#endif + status = qla1280_32bit_start_scsi(ha, sp); + + if (!status) + { + break; + } + + /* Go check for pending interrupts. */ + qla1280_poll(ha); + + SYS_DELAY(5); /* 10 */ + } + if (!cnt) + { + /* Set timeout status */ + CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16; + +#if WATCHDOGTIMER + /* Remove command from watchdog queue. */ + if (sp->flags & SRB_WATCHDOG) + qla1280_timeout_remove(ha, sp); +#endif + COMTRACE('M') + CMD_HANDLE(sp->cmd) = (unsigned char *) 0; + + /* Call the mid-level driver interrupt handler */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + sti(); + (*(sp->cmd)->scsi_done)(sp->cmd); + cli(); +#else + (*(sp->cmd)->scsi_done)(sp->cmd); +#endif + + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + + if (q->q_outcnt) + q->q_outcnt--; + } + else + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + } + else + { /* Place request back on top of device queue. */ + qla1280_putq_t(q, sp); + + if (q->q_outcnt) + q->q_outcnt--; + if (q->q_outcnt < ha->bus_settings[b].hiwat) + q->q_flag &= ~QLA1280_QBUSY; + break; + } + } + } + } + DRIVER_UNLOCK + + /* Release SCSI LU queue specific lock */ + QLA1280_SCSILU_UNLOCK(q); + + LEAVE("qla1280_next"); +} + +/* + * qla1280_putq_t + * Add the standard SCB job to the top of standard SCB commands. + * + * Input: + * q = SCSI LU pointer. + * sp = srb pointer. + * SCSI_LU_Q lock must be already obtained. + */ +STATIC void +qla1280_putq_t(scsi_lu_t *q, srb_t *sp) +{ + srb_t *srb_p; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_putq_t"); +#endif + DRIVER_LOCK + DEBUG(sprintf(debug_buff,"Adding to device 0x%x<-(0x%x)\n\r",q,sp)); + DEBUG(qla1280_print(debug_buff)); + sp->s_next = NULL; + if (!q->q_first) /* If queue empty */ + { + sp->s_prev = NULL; + q->q_first = sp; + q->q_last = sp; + } + else + { + srb_p = q->q_first; + while (srb_p ) + srb_p = srb_p->s_next; + + if (srb_p) + { + sp->s_prev = srb_p->s_prev; + if (srb_p->s_prev) + srb_p->s_prev->s_next = sp; + else + q->q_first = sp; + srb_p->s_prev = sp; + sp->s_next = srb_p; + } + else + { + sp->s_prev = q->q_last; + q->q_last->s_next = sp; + q->q_last = sp; + } + } + + DRIVER_UNLOCK +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_putq_t"); +#endif +} + +/* + * qla1280_removeq + * Function used to remove a command block from the + * LU queue. + * + * Input: + * q = SCSI LU pointer. + * sp = srb pointer. + * SCSI_LU_Q lock must be already obtained. + */ +STATIC void +qla1280_removeq(scsi_lu_t *q, srb_t *sp) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + DEBUG(sprintf(debug_buff,"Removing from device_q (0x%x)->(0x%x)\n\r",q,sp)); + DEBUG(qla1280_print(debug_buff)); + DRIVER_LOCK + if (sp->s_prev) + { + if ((sp->s_prev->s_next = sp->s_next) != NULL) + sp->s_next->s_prev = sp->s_prev; + else + q->q_last = sp->s_prev; + } + else if (!(q->q_first = sp->s_next)) + q->q_last = NULL; + else + q->q_first->s_prev = NULL; + DRIVER_UNLOCK +} + +/* + * qlc1280_mem_free + * Frees adapter allocated memory. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_mem_free(scsi_qla_host_t *ha) +{ + scsi_lu_t *q; + uint32_t b, t, l; + + ENTER("qlc1280_mem_free"); + if (ha) + { + /* Free device queues. */ + for (b = 0; b < MAX_BUSES; b++) + { + q = LU_Q(ha, b, ha->bus_settings[b].id, 0); + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + if (LU_Q(ha, b, t, l) != NULL && LU_Q(ha, b, t, l) != q) + KMFREE(LU_Q(ha, b, t, l),sizeof(struct scsi_lu)); + KMFREE(q, sizeof(struct scsi_lu)); + } + for( b =0; b < MAX_EQ; b++ ) + ha->dev[b] = (scsi_lu_t *)NULL; + } + + LEAVE("qlc1280_mem_free"); +} + + + + +/****************************************************************************/ +/* QLogic ISP1280 Hardware Support Functions. */ +/****************************************************************************/ + +/* + * qla1280_initialize_adapter + * Initialize board. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_initialize_adapter(scsi_qla_host_t *ha) +{ + device_reg_t *reg; + uint8_t status; + /* uint8_t cnt; */ + uint8_t b; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_initialize_adapter"); +#endif + + /* Clear adapter flags. */ + ha->flags.online = FALSE; + ha->flags.isp_abort_needed = FALSE; + ha->flags.disable_host_adapter = FALSE; + ha->flags.reset_active = FALSE; + ha->flags.abort_isp_active = FALSE; + ha->flags.watchdog_enabled = FALSE; + + DEBUG(printk("Configure PCI space for adapter...\n")); + if (!(status = qla1280_pci_config(ha))) + { + reg = ha->iobase; + + /* Disable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, 0); + + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); + + /* If firmware needs to be loaded */ + if (qla1280_verbose) + printk("scsi(%d): Determining if RISC is loaded...\n",(int)ha->host_no); + if (qla1280_isp_firmware(ha)) + { + if (qla1280_verbose) + printk("scsi(%d): Verifying chip...\n",(int)ha->host_no); + if (!(status = qla1280_chip_diag(ha))) + { + status = qla1280_setup_chip(ha); + } + } + + if (!status) + { + /* Setup adapter based on NVRAM parameters. */ + if (qla1280_verbose) + printk("scsi(%d): Configure NVRAM parameters...\n",(int)ha->host_no); + qla1280_nvram_config(ha); + + if (!ha->flags.disable_host_adapter && + !qla1280_init_rings(ha)) + { + /* Issue SCSI reset. */ + for (b = 0; b < ha->ports; b++) + if (!ha->bus_settings[b].disable_scsi_reset) + { + /* dg 03/13 if we can't reset twice then bus is dead */ + if( qla1280_bus_reset(ha, b) ) + if( qla1280_bus_reset(ha, b) ) + { + ha->bus_settings[b].scsi_bus_dead = TRUE; + } + } + + do + { + /* Issue marker command. */ + ha->flags.reset_marker = FALSE; + for (b = 0; b < ha->ports; b++) + { + ha->bus_settings[b].reset_marker = FALSE; + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + } + }while (ha->flags.reset_marker); + + ha->flags.online = TRUE; + + /* Enable host adapter target mode. */ + for (b = 0; b < ha->ports; b++) + { + if (!(status = qla1280_enable_tgt(ha, b))) + { + /* for (cnt = 0; cnt < MAX_LUNS; cnt++) + { + qla1280_enable_lun(ha, b, cnt); + qla1280_poll(ha); + }*/ + } + else + break; + } + } + else + status = 1; + } + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_initialize_adapter: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_initialize_adapter"); +#endif + return(status); +} + +/* + * qla1280_enable_tgt + * Enable target mode. + * + * Input: + * ha = adapter block pointer. + * b = SCSI bus number. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_enable_tgt(scsi_qla_host_t *ha, uint8_t b) +{ + uint8_t status = 0; + /* uint16_t mb[MAILBOX_REGISTER_COUNT]; */ + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_enable_tgt: entered\n\r"); +#endif + + /* Enable target mode. */ + /* + mb[0] = MBC_ENABLE_TARGET_MODE; + mb[1] = BIT_15; + mb[2] = (uint16_t)(b << 15); + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_enable_tgt: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_enable_tgt: exiting normally\n\r"); +#endif + return(status); +} + +/* + * ISP Firmware Test + * Checks if present version of RISC firmware is older than + * driver firmware. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = firmware does not need to be loaded. + */ +STATIC uint8_t +qla1280_isp_firmware(scsi_qla_host_t *ha) +{ + nvram_t *nv = (nvram_t *)ha->response_ring; + uint16_t *wptr; + uint8_t chksum; + uint8_t cnt; + uint8_t status = 0; /* dg 2/27 always loads RISC */ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + ENTER("qla1280_isp_firmware"); + + /* Verify valid NVRAM checksum. */ + wptr = (uint16_t *)ha->response_ring; + DEBUG(printk("qla1280_isp_firmware: Reading NVRAM\n")); + chksum = 0; + for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) + { + *wptr = qla1280_get_nvram_word(ha, cnt); + /* + *wptr = (u_short) qla1280_read_nvram_word(ha->host, (u_short) cnt); + */ + chksum += (uint8_t)*wptr; + chksum += (uint8_t)(*wptr >> 8); + wptr++; + } + DEBUG(printk("qla1280_isp_firmware: Completed Reading NVRAM\n")); + +#if defined(QL_DEBUG_LEVEL_3) + sprintf(debug_buff,"qla1280_isp_firmware: NVRAM Magic ID= %c %c %c\n\r",(char *) nv->id[0],nv->id[1],nv->id[2]); + qla1280_print(debug_buff); +#endif + + /* Bad NVRAM data, load RISC code. */ + if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || + nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) + { + printk(KERN_INFO "qla1280_isp_firmware: Bad checksum or magic number or version in NVRAM.\n"); + ha->flags.disable_risc_code_load = FALSE; + } + else + ha->flags.disable_risc_code_load = nv->cntr_flags_1.disable_loading_risc_code; + + if (ha->flags.disable_risc_code_load) + { +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_isp_firmware: Telling RISC to verify checksum of loaded BIOS code.\n\r"); +#endif + /* Verify checksum of loaded RISC code. */ + mb[0] = MBC_VERIFY_CHECKSUM; + mb[1] = ql12_risc_code_addr01; + if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]))) + { + /* Start firmware execution. */ +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_isp_firmware: Startng F/W execution.\n\r"); +#endif + mb[0] = MBC_EXECUTE_FIRMWARE; + mb[1] = ql12_risc_code_addr01; + qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } + else + printk(KERN_INFO "qla1280: RISC checksum failed.\n"); + } + else + { + DEBUG(printk("qla1280: NVRAM configured to load RISC load.\n")); + status = 1; + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print( + "qla1280_isp_firmware: **** Load RISC code ****\n\r"); +#endif + LEAVE("qla1280_isp_firmware"); + return(status); +} + +/* + * PCI configuration + * Setup device PCI configuration registers. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_pci_config(scsi_qla_host_t *ha) +{ + uint8_t status = 1; + uint32_t command; +#if MEMORY_MAPPED_IO + uint32_t page_offset, base; + uint32_t mmapbase; +#endif + config_reg_t *creg = 0; + uint16_t buf_wd; + + ENTER("qla1280_pci_config"); + + /* Get command register. */ + if (pcibios_read_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL) + { + command = buf_wd; + /* + * Set Bus Master Enable, Memory Address Space Enable and + * reset any error bits. + */ + buf_wd &= ~0x7; +#if MEMORY_MAPPED_IO + DEBUG(printk("qla1280: MEMORY MAPPED IO is enabled.\n")); + buf_wd |= BIT_2 + BIT_1 + BIT_0; +#else + buf_wd |= BIT_2 + BIT_0; +#endif + if( pcibios_write_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->command), buf_wd) ) + { + printk(KERN_WARNING "qla1280: Could not write config word.\n"); + } + /* Get expansion ROM address. */ + if (pcibios_read_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->expansion_rom), &buf_wd) == PCIBIOS_SUCCESSFUL) + { + /* Reset expansion ROM address decode enable. */ + buf_wd &= ~BIT_0; + if (pcibios_write_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->expansion_rom), buf_wd) == PCIBIOS_SUCCESSFUL) + { +#if MEMORY_MAPPED_IO + /* Get memory mapped I/O address. */ + pcibios_read_config_dword(ha->pci_bus, ha->pci_device_fn,OFFSET(cfgp->mem_base_addr), &mmapbase); + mmapbase &= PCI_BASE_ADDRESS_MEM_MASK; + + /* Find proper memory chunk for memory map I/O reg. */ + base = mmapbase & PAGE_MASK; + page_offset = mmapbase - base; + /* Get virtual address for I/O registers. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + ha->mmpbase = ioremap_nocache(base, page_offset + 256); +#else + ha->mmpbase = vremap(base,page_offset + 256); +#endif + if( ha->mmpbase ) + { + ha->mmpbase += page_offset; + /* ha->iobase = ha->mmpbase; */ + status = 0; + } +#else /* MEMORY_MAPPED_IO */ + status = 0; +#endif /* MEMORY_MAPPED_IO */ + } + } + } + + LEAVE("qla1280_pci_config"); + return(status); +} + +/* + * Chip diagnostics + * Test chip for proper operation. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_chip_diag(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + uint16_t data; + uint32_t cnt; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + sprintf(debug_buff, "qla1280_chip_diag: testing device at 0x%x \n\r",®->id_l); + qla1280_print(debug_buff); +#endif + + /* Soft reset chip and wait for it to finish. */ + WRT_REG_WORD(®->ictrl, ISP_RESET); + data = qla1280_debounce_register(®->ictrl); + for (cnt = 6000000; cnt && data & ISP_RESET; cnt--) + { + SYS_DELAY(5); + data = RD_REG_WORD(®->ictrl); + } + if (cnt) + { + /* Reset register not cleared by chip reset. */ +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_chip_diag: reset register cleared by chip reset\n\r"); +#endif + WRT_REG_WORD(®->cfg_1, 0); + + /* Reset RISC and disable BIOS which + allows RISC to execute out of RAM. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); + data = qla1280_debounce_register(®->mailbox0); + for (cnt = 6000000; cnt && data == MBS_BUSY; cnt--) + { + SYS_DELAY(5); + data = RD_REG_WORD(®->mailbox0); + } + + if (cnt) + { + /* Check product ID of chip */ +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_chip_diag: Checking product ID of chip\n\r"); +#endif + if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || + (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && + RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || + RD_REG_WORD(®->mailbox3) != PROD_ID_3 || + RD_REG_WORD(®->mailbox4) != PROD_ID_4) + { + printk(KERN_INFO "qla1280: Wrong product ID = 0x%x,0x%x,0x%x,0x%x\n", + RD_REG_WORD(®->mailbox1), + RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3), + RD_REG_WORD(®->mailbox4) ); + status = 1; + } + else + { + DEBUG(printk("qla1280_chip_diag: Checking mailboxes of chip\n")); + /* Wrap Incoming Mailboxes Test. */ + mb[0] = MBC_MAILBOX_REGISTER_TEST; + mb[1] = 0xAAAA; + mb[2] = 0x5555; + mb[3] = 0xAA55; + mb[4] = 0x55AA; + mb[5] = 0xA5A5; + mb[6] = 0x5A5A; + mb[7] = 0x2525; + if (!(status = qla1280_mailbox_command(ha, + (BIT_7|BIT_6|BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0), + &mb[0]))) + { + if (mb[1] != 0xAAAA || mb[2] != 0x5555 || + mb[3] != 0xAA55 || mb[4] != 0x55AA) + status = 1; + if (mb[5] != 0xA5A5 || mb[6] != 0x5A5A || + mb[7] != 0x2525) + status = 1; + if( status == 1 ) + printk(KERN_INFO "qla1280: Failed mailbox check\n"); + } + } + } + else + status = 1; + } + else + status = 1; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_chip_diag: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_chip_diag: exiting normally\n\r"); +#endif + return(status); +} + +/* + * Setup chip + * Load and start RISC firmware. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_setup_chip(scsi_qla_host_t *ha) +{ + uint8_t status = 0; + uint16_t risc_address; + uint16_t *risc_code_address; + long risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT]; +#ifdef QLA1280_UNUSED + int i; +#endif + uint16_t cnt; + int num; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_setup_chip"); +#endif + + /* Load RISC code. */ + risc_address = ql12_risc_code_addr01; + risc_code_address = &ql12_risc_code01[0]; + risc_code_size = ql12_risc_code_length01; + + DEBUG(printk("qla1280: DMAing RISC code (%d) words.\n",(int)risc_code_size)); + DEBUG(sprintf(debug_buff,"qla1280_setup_chip: Loading RISC code size =(%d).\n\r",risc_code_size);) + DEBUG(qla1280_print(debug_buff)); + num =0; + while (risc_code_size > 0 && !status) + { + cnt = 2000 >> 1; + + if ( cnt > risc_code_size ) + cnt = risc_code_size; + + DEBUG(sprintf(debug_buff,"qla1280_setup_chip: loading risc @ =(0x%x),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);) + DEBUG(qla1280_print(debug_buff)); + BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1)); + mb[0] = MBC_LOAD_RAM; + mb[1] = risc_address; + mb[3] = (uint16_t) (ha->request_dma & 0xffff); + mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff; + mb[4] = cnt; + if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0])) ) + { + printk("Failed to load partial segment of f/w\n"); + break; + } + + risc_address += cnt; + risc_code_size = risc_code_size - cnt; + risc_code_address = risc_code_address + cnt; + num++; + } +#ifdef QLA1280_UNUSED + DEBUG(ql_debug_print = 0;) + { + for (i = 0; i < ql12_risc_code_length01; i++) + { + mb[0] = 0x4; + mb[1] = ql12_risc_code_addr01 + i; + mb[2] = ql12_risc_code01[i]; + + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, + &mb[0]); + if (status) + { + printk("qla1280 : firmware load failure\n"); + break; + } + + mb[0] = 0x5; + mb[1] = ql12_risc_code_addr01 + i; + mb[2] = 0; + + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, + &mb[0]); + if (status) + { + printk("qla1280 : firmware dump failure\n"); + break; + } + if( mb[2] != ql12_risc_code01[i] ) + printk("qla1280 : firmware compare error @ (0x%x)\n",ql12_risc_code_addr01+i); + } + } + DEBUG(ql_debug_print = 1;) +#endif + + /* Verify checksum of loaded RISC code. */ + if (!status) + { + DEBUG(printk("qla1280_setup_chip: Verifying checksum of loaded RISC code.\n");) + mb[0] = MBC_VERIFY_CHECKSUM; + mb[1] = ql12_risc_code_addr01; + if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]))) + { + /* Start firmware execution. */ + DEBUG(qla1280_print("qla1280_setup_chip: start firmware running.\n\r");) + mb[0] = MBC_EXECUTE_FIRMWARE; + mb[1] = ql12_risc_code_addr01; + qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } +#if defined(QL_DEBUG_LEVEL_2) + else + qla1280_print("qla1280_setup_chip: Failed checksum.\n"); +#endif + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_setup_chip: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_setup_chip"); +#endif + return(status); +} + +/* + * Initialize rings + * + * Input: + * ha = adapter block pointer. + * ha->request_ring = request ring virtual address + * ha->response_ring = response ring virtual address + * ha->request_dma = request ring physical address + * ha->response_dma = response ring physical address + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_init_rings(scsi_qla_host_t *ha) +{ + uint8_t status = 0; + uint16_t cnt; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_init_rings"); +#endif + /* Clear outstanding commands array. */ + for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) + ha->outstanding_cmds[cnt] = 0; + + /* Initialize request queue. */ + ha->request_ring_ptr = ha->request_ring; + ha->req_ring_index = 0; + ha->req_q_cnt = REQUEST_ENTRY_CNT; + mb[0] = MBC_INIT_REQUEST_QUEUE; + mb[1] = REQUEST_ENTRY_CNT; + mb[3] = (uint16_t)ha->request_dma; + mb[2] = (uint16_t)(ha->request_dma >> 16); + mb[4] = 0; + mb[7] = 0; + mb[6] = 0; + if (!(status = qla1280_mailbox_command(ha, + BIT_7|BIT_6|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]))) + { + /* Initialize response queue. */ + ha->response_ring_ptr = ha->response_ring; + ha->rsp_ring_index = 0; + mb[0] = MBC_INIT_RESPONSE_QUEUE; + mb[1] = RESPONSE_ENTRY_CNT; + mb[3] = (uint16_t)ha->response_dma; + mb[2] = (uint16_t)(ha->response_dma >> 16); + mb[5] = 0; + mb[7] = 0; + mb[6] = 0; + status = qla1280_mailbox_command(ha, + BIT_7|BIT_6|BIT_5|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_init_rings: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_init_rings"); +#endif + return(status); +} + +/* + * NVRAM configuration. + * + * Input: + * ha = adapter block pointer. + * ha->request_ring = request ring virtual address + * + * Output: + * host adapters parameters in host adapter block + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_nvram_config(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + nvram_t *nv = (nvram_t *)ha->response_ring; + uint8_t status = 0; + uint32_t b, t, l; + uint16_t *wptr; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint8_t cnt; + uint8_t chksum; + +#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4) + uint8_t saved_print_status = ql_debug_print; +#endif + ENTER("qla1280_nvram_config"); +#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4) + ql_debug_print = FALSE; +#endif + + /* Verify valid NVRAM checksum. */ +#if USE_NVRAM_DEFAULTS + chksum = 1; +#else + wptr = (uint16_t *)ha->response_ring; + chksum = 0; + for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) + { + *wptr = qla1280_get_nvram_word(ha, cnt); + chksum += (uint8_t)*wptr; + chksum += (uint8_t)(*wptr >> 8); + wptr++; + } +#endif + + + /* Bad NVRAM data, set defaults parameters. */ + if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || + nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) + { +#if USE_NVRAM_DEFAULTS + DEBUG(printk("Using defaults for NVRAM\n")); +#else + DEBUG(printk("Using defaults for NVRAM: \n")); + DEBUG(printk("checksum=0x%x, Id=%c, version=0x%x\n",chksum,nv->id[0],nv->version)); +#if defined(QL_DEBUG_LEVEL_3) + /* ql_debug_print = 1; + qla1280_dump_buffer((caddr_t)ha->response_ring, REQUEST_ENTRY_SIZE); + ql_debug_print = 0; */ +#endif + wptr = (uint16_t *)ha->response_ring; + for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) + *wptr++ = 0; +#endif + + + /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ + nv->firmware_feature.w = BIT_0; + nv->termination.f.scsi_bus_0_control = 3; + nv->termination.f.scsi_bus_1_control = 3; + nv->termination.f.auto_term_support = 1; + + for (b = 0; b < MAX_BUSES; b++) + { + nv->bus[b].config_1.initiator_id = 7; + nv->bus[b].bus_reset_delay = 5; + nv->bus[b].config_2.async_data_setup_time = 9; + nv->bus[b].config_2.req_ack_active_negation = 1; + nv->bus[b].config_2.data_line_active_negation = 1; + nv->bus[b].selection_timeout = 250; + nv->bus[b].max_queue_depth = 256; + + for (t = 0; t < MAX_TARGETS; t++) + { + nv->bus[b].target[t].parameter.f.auto_request_sense = 1; + nv->bus[b].target[t].parameter.f.disconnect_allowed = 1; + nv->bus[b].target[t].parameter.f.tag_queuing = 1; + nv->bus[b].target[t].flags.device_enable = 1; + } + } + +#if USE_NVRAM_DEFAULTS + status = 0; +#else + status = 1; +#endif + } + else + { + /* Always force AUTO sense for LINUX SCSI */ + for (b = 0; b < MAX_BUSES; b++) + for (t = 0; t < MAX_TARGETS; t++) + { + nv->bus[b].target[t].parameter.f.auto_request_sense = 1; + } + } +#if DEBUG_PRINT_NVRAM + ql_debug_print = 1; + sprintf(debug_buff,"qla1280 : initiator scsi id bus[0]=%d\n\r", + nv->bus[0].config_1.initiator_id); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : initiator scsi id bus[1]=%d\n\r", + nv->bus[1].config_1.initiator_id); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : bus reset delay[0]=%d\n\r", + nv->bus[0].bus_reset_delay); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : bus reset delay[1]=%d\n\r", + nv->bus[1].bus_reset_delay); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : retry count[0]=%d\n\r", + nv->bus[0].retry_count); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : retry delay[0]=%d\n\r", + nv->bus[0].retry_delay); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : retry count[1]=%d\n\r", + nv->bus[1].retry_count); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : retry delay[1]=%d\n\r", + nv->bus[1].retry_delay); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : async data setup time[0]=%d\n\r", + nv->bus[0].config_2.async_data_setup_time); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : async data setup time[1]=%d\n\r", + nv->bus[1].config_2.async_data_setup_time); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : req/ack active negation[0]=%d\n\r", + nv->bus[0].config_2.req_ack_active_negation); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : req/ack active negation[1]=%d\n\r", + nv->bus[1].config_2.req_ack_active_negation); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : data line active negation[0]=%d\n\r", + nv->bus[0].config_2.data_line_active_negation); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : data line active negation[1]=%d\n\r", + nv->bus[1].config_2.data_line_active_negation); + qla1280_print(debug_buff); + + + sprintf(debug_buff,"qla1280 : disable loading risc code=%d\n\r", + nv->cntr_flags_1.disable_loading_risc_code); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : enable 64bit addressing=%d\n\r", + nv->cntr_flags_1.enable_64bit_addressing); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : selection timeout limit[0]=%d\n\r", + nv->bus[0].selection_timeout); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : selection timeout limit[1]=%d\n\r", + nv->bus[1].selection_timeout); + + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : max queue depth[0]=%d\n\r", + nv->bus[0].max_queue_depth); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : max queue depth[1]=%d\n\r", + nv->bus[1].max_queue_depth); + qla1280_print(debug_buff); +#endif + + DEBUG(ql_debug_print = 0;) + + /* Disable RISC load of firmware. */ + ha->flags.disable_risc_code_load = + nv->cntr_flags_1.disable_loading_risc_code; + /* Enable 64bit addressing. */ + ha->flags.enable_64bit_addressing = + nv->cntr_flags_1.enable_64bit_addressing; + + /* Set ISP hardware DMA burst */ + mb[0] = nv->isp_config.c; + WRT_REG_WORD(®->cfg_1, mb[0]); + + /* Set SCSI termination. */ + WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); + mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); + WRT_REG_WORD(®->gpio_data, mb[0]); + + /* ISP parameter word. */ + mb[0] = MBC_SET_SYSTEM_PARAMETER; + mb[1] = nv->isp_parameter; + status |= qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Firmware feature word. */ + mb[0] = MBC_SET_FIRMWARE_FEATURES; + mb[1] = nv->firmware_feature.w & (BIT_1|BIT_0); + status |= qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Retry count and delay. */ + mb[0] = MBC_SET_RETRY_COUNT; + mb[1] = nv->bus[0].retry_count; + mb[2] = nv->bus[0].retry_delay; + mb[6] = nv->bus[1].retry_count; + mb[7] = nv->bus[1].retry_delay; + status |= qla1280_mailbox_command(ha, BIT_7|BIT_6|BIT_2|BIT_1|BIT_0, &mb[0]); + + /* ASYNC data setup time. */ + mb[0] = MBC_SET_ASYNC_DATA_SETUP; + mb[1] = nv->bus[0].config_2.async_data_setup_time; + mb[2] = nv->bus[1].config_2.async_data_setup_time; + status |= qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Active negation states. */ + mb[0] = MBC_SET_ACTIVE_NEGATION; + mb[1] = 0; + if (nv->bus[0].config_2.req_ack_active_negation) + mb[1] |= BIT_5; + if (nv->bus[0].config_2.data_line_active_negation) + mb[1] |= BIT_4; + mb[2] = 0; + if (nv->bus[1].config_2.req_ack_active_negation) + mb[2] |= BIT_5; + if (nv->bus[1].config_2.data_line_active_negation) + mb[2] |= BIT_4; + status |= qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Selection timeout. */ + mb[0] = MBC_SET_SELECTION_TIMEOUT; + mb[1] = nv->bus[0].selection_timeout; + mb[2] = nv->bus[1].selection_timeout; + status |= qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + for (b = 0; b < ha->ports; b++) + { + /* SCSI Reset Disable. */ + ha->bus_settings[b].disable_scsi_reset = nv->bus[b].config_1.scsi_reset_disable; + + /* Initiator ID. */ + ha->bus_settings[b].id = nv->bus[b].config_1.initiator_id; + mb[0] = MBC_SET_INITIATOR_ID; + mb[1] = b ? ha->bus_settings[b].id | BIT_7 : ha->bus_settings[b].id; + status |= qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Reset Delay. */ + ha->bus_settings[b].bus_reset_delay = nv->bus[b].bus_reset_delay; + + /* Command queue depth per device. */ + ha->bus_settings[b].hiwat = nv->bus[b].max_queue_depth - 1; + + /* Set target parameters. */ + for (t = 0; t < MAX_TARGETS; t++) + { + /* Set Target Parameters. */ + mb[0] = MBC_SET_TARGET_PARAMETERS; + mb[1] = (uint16_t)(b ? t | BIT_7 :t); + mb[1] <<= 8; + mb[2] = nv->bus[b].target[t].parameter.c << 8; + mb[2] |= TP_AUTO_REQUEST_SENSE; + mb[2] &= ~TP_STOP_QUEUE; + mb[3] = nv->bus[b].target[t].flags.sync_offset << 8; + mb[3] |= nv->bus[b].target[t].sync_period; + status |= qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + + /* Save Tag queuing enable flag. */ + mb[0] = BIT_0 << t; + if (nv->bus[b].target[t].parameter.f.tag_queuing) + ha->bus_settings[b].qtag_enables |= mb[0]; + + /* Save Device enable flag. */ + if (nv->bus[b].target[t].flags.device_enable) + ha->bus_settings[b].device_enables |= mb[0]; + + /* Save LUN disable flag. */ + if (nv->bus[b].target[t].flags.lun_disable) + ha->bus_settings[b].lun_disables |= mb[0]; + + /* Set Device Queue Parameters. */ + for (l = 0; l < MAX_LUNS; l++) + { + mb[0] = MBC_SET_DEVICE_QUEUE; + mb[1] = (uint16_t)(b ? t | BIT_7 :t); + mb[1] = mb[1] << 8 | l; + mb[2] = nv->bus[b].max_queue_depth; + mb[3] = nv->bus[b].target[t].execution_throttle; + status |= qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + } + } + } + DEBUG(ql_debug_print = 0;) + +#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4) + ql_debug_print = saved_print_status; +#endif + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + DEBUG(if (status)) + DEBUG(qla1280_print("qla1280_nvram_config: **** FAILED ****\n\r");) +#endif + LEAVE("qla1280_nvram_config"); + return(status); +} + +/* + * Get NVRAM data word + * Calculates word position in NVRAM and calls request routine to + * get the word from NVRAM. + * + * Input: + * ha = adapter block pointer. + * address = NVRAM word address. + * + * Returns: + * data word. + */ +STATIC uint16_t +qla1280_get_nvram_word(scsi_qla_host_t *ha, uint32_t address) +{ + uint32_t nv_cmd; + uint16_t data; + +#ifdef QL_DEBUG_ROUTINES + uint8_t saved_print_status = ql_debug_print; +#endif +#ifdef QL_DEBUG_LEVEL_4 + ENTER("qla1280_get_nvram_word"); +#endif + + nv_cmd = address << 16; + nv_cmd |= NV_READ_OP; + +#ifdef QL_DEBUG_ROUTINES + ql_debug_print = FALSE; +#endif + data = qla1280_nvram_request(ha, nv_cmd); +#ifdef QL_DEBUG_ROUTINES + ql_debug_print = saved_print_status; +#endif + +#ifdef QL_DEBUG_LEVEL_4 + qla1280_print("qla1280_get_nvram_word: exiting normally NVRAM data = "); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); +#endif + return(data); +} + +/* + * NVRAM request + * Sends read command to NVRAM and gets data from NVRAM. + * + * Input: + * ha = adapter block pointer. + * nv_cmd = Bit 26 = start bit + * Bit 25, 24 = opcode + * Bit 23-16 = address + * Bit 15-0 = write data + * + * Returns: + * data word. + */ +STATIC uint16_t +qla1280_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) + qla1280_nv_write(ha, NV_DATA_OUT); + else + qla1280_nv_write(ha, 0); + nv_cmd <<= 1; + } + + /* Read data from NVRAM. */ + + for (cnt = 0; cnt < 16; cnt++) + { + WRT_REG_WORD(®->nvram, NV_SELECT+NV_CLOCK); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + data <<= 1; + reg_data = RD_REG_WORD(®->nvram); + if (reg_data & NV_DATA_IN) + data |= BIT_0; + WRT_REG_WORD(®->nvram, NV_SELECT); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + } + + /* Deselect chip. */ + + WRT_REG_WORD(®->nvram, NV_DESELECT); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + + return(data); +} + +STATIC void +qla1280_nv_write(scsi_qla_host_t *ha, uint16_t data) +{ + device_reg_t *reg = ha->iobase; + + WRT_REG_WORD(®->nvram, data | NV_SELECT); + NVRAM_DELAY(); + /* qla1280_nv_delay(ha); */ + WRT_REG_WORD(®->nvram, data | NV_SELECT | NV_CLOCK); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + WRT_REG_WORD(®->nvram, data | NV_SELECT); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); +} + +STATIC void +qla1280_nv_delay(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + int cnt = NV_DELAY_COUNT; + uint16_t data = 0; + + while (cnt--) + data |= RD_REG_WORD(®->nvram); +} + +/* + * Mailbox Command + * Issue mailbox command and waits for completion. + * + * Input: + * ha = adapter block pointer. + * mr = mailbox registers to load. + * mb = data pointer for mailbox registers. + * + * Output: + * mb[MAILBOX_REGISTER_COUNT] = returned mailbox data. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_mailbox_command(scsi_qla_host_t *ha, uint8_t mr, uint16_t *mb) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + uint32_t cnt; + uint16_t *optr, *iptr; + uint16_t data; + srb_t *done_q_first = 0; + srb_t *done_q_last = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_mailbox_command"); +#endif + + /* Acquire interrupt specific lock */ + QLA1280_INTR_LOCK(ha); + DRIVER_LOCK + ha->flags.mbox_busy = TRUE; + + /* Load mailbox registers. */ + optr = (uint16_t *)®->mailbox0; + iptr = mb; + for (cnt = 0; cnt < MAILBOX_REGISTER_COUNT; cnt++) + { + if (mr & BIT_0) + { + WRT_REG_WORD(optr, (*iptr)); + } + + mr >>= 1; + optr++; + iptr++; + } + /* Issue set host interrupt command. */ + ha->flags.mbox_int = FALSE; + WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT); + data = qla1280_debounce_register(®->istatus); + + /* Wait for 30 seconds for command to finish. */ + for (cnt = 30000000; cnt > 0 && !ha->flags.mbox_int; cnt--) + { + /* Check for pending interrupts. */ + if (data & RISC_INT) + { + qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + } + SYS_DELAY(1); + data = RD_REG_WORD(®->istatus); + } + + /* Check for mailbox command timeout. */ + if ( !cnt ) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_mailbox_command: **** Command Timeout, mailbox0 = "); + qla1280_output_number((uint32_t)mb[0], 16); + qla1280_print(" ****\n\r"); +#endif + ha->flags.isp_abort_needed = TRUE; + status = 1; + } + else if (ha->mailbox_out[0] != MBS_CMD_CMP) + status = 1; + + /* Load return mailbox registers. */ + optr = mb; + iptr = (uint16_t *)&ha->mailbox_out[0]; + mr = MAILBOX_REGISTER_COUNT; + while (mr--) + *optr++ = *iptr++; + + /* Go check for any response interrupts pending. */ + ha->flags.mbox_busy = FALSE; + qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + + /* Release interrupt specific lock */ + QLA1280_INTR_UNLOCK(ha); + DRIVER_UNLOCK + + if (ha->flags.isp_abort_needed) + qla1280_abort_isp(ha); + + if (ha->flags.reset_marker) + qla1280_rst_aen(ha); + + if (done_q_first) + qla1280_done(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + { + qla1280_print("qla1280_mailbox_command: **** FAILED, mailbox0 = "); + qla1280_output_number((uint32_t)mb[0], 16); + qla1280_print(" ****\n\r"); + } +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_mailbox_command"); +#endif + return(status); +} + +/* + * qla1280_poll + * Polls ISP for interrupts. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_poll(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + uint16_t data; + srb_t *done_q_first = 0; + srb_t *done_q_last = 0; + +#ifdef QL_DEBUG_LEVEL_3 + /* ENTER("qla1280_poll"); */ +#endif + + /* Acquire interrupt specific lock */ + QLA1280_INTR_LOCK(ha); + + /* Check for pending interrupts. */ + data = RD_REG_WORD(®->istatus); + if (data & RISC_INT) + qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + + /* Release interrupt specific lock */ + QLA1280_INTR_UNLOCK(ha); + + if (!ha->flags.mbox_busy) + { + if (ha->flags.isp_abort_needed) + qla1280_abort_isp(ha); + if (ha->flags.reset_marker) + qla1280_rst_aen(ha); + } + + if (done_q_first) + qla1280_done(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + +#ifdef QL_DEBUG_LEVEL_3 + /* LEAVE("qla1280_poll"); */ +#endif +} + +/* + * qla1280_bus_reset + * Issue SCSI bus reset. + * + * Input: + * ha = adapter block pointer. + * b = SCSI bus number. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_bus_reset(scsi_qla_host_t *ha, uint8_t b) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_bus_reset: entered\n\r"); +#endif + if( qla1280_verbose ) + { + printk("scsi(%d): Resetting SCSI BUS (%d)\n",(int)ha->host_no,b); + } + + mb[0] = MBC_BUS_RESET; + mb[1] = ha->bus_settings[b].bus_reset_delay; + mb[2] = (uint16_t)b; + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + if (status) + { + if (ha->bus_settings[b].failed_reset_count > 2) /* dg - 03/13/99 */ + ha->bus_settings[b].scsi_bus_dead = TRUE; + ha->bus_settings[b].failed_reset_count++; + } + else + { + QLA1280_DELAY(4); + ha->bus_settings[b].scsi_bus_dead = FALSE; /* dg - 03/13/99 */ + ha->bus_settings[b].failed_reset_count = 0; + /* Issue marker command. */ + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + } +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_bus_reset: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_bus_reset: exiting normally\n\r"); +#endif + return(status); +} + +/* + * qla1280_device_reset + * Issue bus device reset message to the target. + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS number. + * t = SCSI ID. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_device_reset(scsi_qla_host_t *ha, uint8_t b, uint32_t t) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_device_reset"); +#endif + + mb[0] = MBC_ABORT_TARGET; + mb[1] = (b ? (t | BIT_7) : t) << 8; + mb[2] = 1; + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Issue marker command. */ + qla1280_marker(ha, b, t, 0, MK_SYNC_ID); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_device_reset: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_device_reset"); +#endif + return(status); +} + +/* + * qla1280_abort_device + * Issue an abort message to the device + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS. + * t = SCSI ID. + * l = SCSI LUN. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_abort_device(scsi_qla_host_t *ha, uint8_t b, uint32_t t, uint32_t l) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_abort_device"); +#endif + + mb[0] = MBC_ABORT_DEVICE; + mb[1] = (b ? t | BIT_7 : t) << 8 | l; + status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Issue marker command. */ + qla1280_marker(ha, b, t, l, MK_SYNC_ID_LUN); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_abort_device: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_abort_device"); +#endif + return(status); +} + +/* + * qla1280_abort_command + * Abort command aborts a specified IOCB. + * + * Input: + * ha = adapter block pointer. + * sp = SB structure pointer. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_abort_command(scsi_qla_host_t *ha, srb_t *sp) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint32_t b, t, l; + uint32_t handle; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_abort_command"); +#endif + + /* Locate handle number. */ + for (handle = 0; handle < MAX_OUTSTANDING_COMMANDS; handle++) + if (ha->outstanding_cmds[handle] == sp) + break; + + b = SCSI_BUS_32(sp->cmd); + t = SCSI_TCN_32(sp->cmd); + l = SCSI_LUN_32(sp->cmd); + + mb[0] = MBC_ABORT_COMMAND; + mb[1] = (b ? t | BIT_7 : t) << 8 | l; + mb[2] = handle >> 16; + mb[3] = (uint16_t)handle; + status = qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_abort_command: **** FAILED ****\n\r"); +#endif + sp->flags |= SRB_ABORT_PENDING; + + LEAVE("qla1280_abort_command"); + return(status); +} + +/* + * qla1280_reset_adapter + * Reset adapter. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_reset_adapter(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_reset_adapter"); +#endif + + /* Disable ISP chip */ + ha->flags.online = FALSE; + WRT_REG_WORD(®->ictrl, ISP_RESET); + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_reset_adapter"); +#endif +} + +/* + * Issue marker command. + * Function issues marker IOCB. + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS number + * t = SCSI ID + * l = SCSI LUN + * type = marker modifier + */ +STATIC void +qla1280_marker(scsi_qla_host_t *ha, uint8_t b, uint32_t t, uint32_t l, uint8_t type) +{ + mrk_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_marker"); +#endif + + /* Get request packet. */ + if ( (pkt = (mrk_entry_t *)qla1280_req_pkt(ha)) ) + { + pkt->entry_type = MARKER_TYPE; + pkt->lun = (uint8_t)l; + pkt->target = (uint8_t)(b ? (t | BIT_7) : t); + pkt->modifier = type; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_marker"); +#endif +} + +#if QLA1280_64BIT_SUPPORT +/* + * qla1280_64bit_start_scsi + * The start SCSI is responsible for building request packets on + * request ring and modifying ISP input pointer. + * + * Input: + * ha = adapter block pointer. + * sp = SB structure pointer. + * + * Returns: + * 0 = success, was able to issue command. + */ +STATIC uint8_t +qla1280_64bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + Scsi_Cmnd *cmd = sp->cmd; + uint32_t cnt; + cmd_entry_t *pkt; + uint16_t req_cnt; + uint16_t seg_cnt; + struct scatterlist *sg = (struct scatterlist *) NULL; + paddr32_t *addr32p; + caddr_t data_ptr; + uint32_t *dword_ptr; + uint32_t timeout; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_64bit_start_scsi:"); +#endif + + if( qla1280_check_for_dead_scsi_bus(ha, sp) ) + { + return(0); + } + + /* Calculate number of entries and segments required. */ + seg_cnt = 0; + req_cnt = 1; + if (cmd->use_sg) + { + seg_cnt = cmd->use_sg; + sg = (struct scatterlist *) cmd->request_buffer; + + if (seg_cnt > 2) + { + req_cnt += (uint16_t)(seg_cnt - 2) / 5; + if ((uint16_t)(seg_cnt - 2) % 5) + req_cnt++; + } + } + else if (cmd->request_bufflen) /* If data transfer. */ + { + DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen)); + seg_cnt = 1; + } + + /* Acquire ring specific lock */ + QLA1280_RING_LOCK(ha); + + if ((uint16_t)(req_cnt + 2) >= ha->req_q_cnt) + { + /* Calculate number of free request entries. */ + cnt = RD_REG_WORD(®->mailbox4); + 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 ((uint16_t)(req_cnt + 2) < ha->req_q_cnt) + { + /* Check for room in outstanding command list. */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && + ha->outstanding_cmds[cnt] != 0; cnt++) + ; + + if (cnt < MAX_OUTSTANDING_COMMANDS) + { + ha->outstanding_cmds[cnt] = sp; + ha->req_q_cnt -= req_cnt; + CMD_HANDLE(sp->cmd) = (unsigned char *) cnt; + + /* + * Build command packet. + */ + pkt = ha->request_ring_ptr; + + pkt->entry_type = COMMAND_A64_TYPE; + pkt->entry_count = (uint8_t)req_cnt; + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->handle = (uint32_t)cnt; + + /* Zero out remaining portion of packet. */ + dword_ptr = (uint32_t *)pkt + 2; + for (cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Set ISP command timeout. */ + pkt->timeout = (uint16_t)30; + + /* Set device target ID and LUN */ + pkt->lun = SCSI_LUN_32(cmd); + pkt->target = SCSI_BUS_32(cmd) ? + (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); + + /* Enable simple tag queuing if device supports it. */ + if (cmd->device->tagged_queue ) + pkt->control_flags |= BIT_3; + + /* Load SCSI command packet. */ + pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd); + data_ptr = (uint8_t *) &(CMD_CDBP(cmd)); + for (cnt = 0; cnt < pkt->cdb_len; cnt++) + pkt->scsi_cdb[cnt] = *data_ptr++; + + /* + * Load data segments. + */ + if (seg_cnt) /* If data transfer. */ + { + /* Set transfer direction. */ + if ( (cmd->data_cmnd[0] == WRITE_6) ) + pkt->control_flags |= BIT_6; + else + pkt->control_flags |= (BIT_5|BIT_6); + + sp->dir = pkt->control_flags & (BIT_5|BIT_6); + + /* Set total data segment count. */ + pkt->dseg_count = seg_cnt; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *)&pkt->dseg_0_address; + + if (cmd->use_sg) /* If scatter gather */ + { + /* Load command entry data segments. */ + for (cnt = 0; cnt < 2 && seg_cnt; cnt++, seg_cnt--) + { + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS_LOW(sg->address)); + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address)); + *dword_ptr++ = sg->length; + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_64bit_start_scsi: Scatter/gather command packet data - "); + qla1280_print("b"); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla1280_print("t"); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print("d"); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + /* + * Build continuation packets. + */ + while (seg_cnt > 0) + { + /* 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++; + + 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; + + /* Load packet defaults. */ + ((cont_a64_entry_t *)pkt)->entry_type = + CONTINUE_A64_TYPE; + ((cont_a64_entry_t *)pkt)->entry_count = 1; + ((cont_a64_entry_t *)pkt)->sys_define = (uint8_t) + ha->req_ring_index; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *) + &((cont_a64_entry_t *)pkt)->dseg_0_address; + + /* Load continuation entry data segments. */ + for (cnt = 0; cnt < 5 && seg_cnt; cnt++, seg_cnt--) + { + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS_LOW(sg->address)); + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address)); + *dword_ptr++ = sg->length; + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_64bit_start_scsi: continuation packet data - c"); + qla1280_print("b"); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + + qla1280_print("t"); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print("d"); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } + else /* No scatter gather data transfer */ + { + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS_LOW(cmd->request_buffer)); + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS_HIGH(cmd->request_buffer)); + *dword_ptr = (uint32_t) cmd->request_bufflen; +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_64bit_start_scsi: No scatter/gather command packet data - c"); + qla1280_print("b"); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla1280_print("t"); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print("d"); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } +#ifdef QL_DEBUG_LEVEL_5 + else /* No data transfer */ + { + *dword_ptr++ = (uint32_t) 0; + *dword_ptr++ = (uint32_t) 0; + *dword_ptr = (uint32_t) 0; + qla1280_print( + "qla1280_64bit_start_scsi: No data, command packet data - c"); + qla1280_print("b"); + qla1280_output_number((uint32_t)SDI_BUS_32(cmd), 10); + qla1280_print("t"); + qla1280_output_number((uint32_t)SDI_TCN_32(cmd), 10); + qla1280_print("d"); + qla1280_output_number((uint32_t)SDI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); + } +#endif + /* 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(®->mailbox4, ha->req_ring_index); + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_64bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r"); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); +#endif + } + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_64bit_start_scsi: in-ptr="); + qla1280_output_number((uint32_t)ha->req_ring_index, 16); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); + qla1280_print(" req_cnt="); + qla1280_output_number((uint32_t)req_cnt, 16); + qla1280_print("\n\r"); +#endif + } + + /* Release ring specific lock */ + QLA1280_RING_UNLOCK(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_64bit_start_scsi: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_64bit_start_scsi: exiting normally\n\r"); +#endif + return(status); +} +#endif /* QLA1280_64BIT_SUPPORT */ + +/* + * qla1280_32bit_start_scsi + * The start SCSI is responsible for building request packets on + * request ring and modifying ISP input pointer. + * + * The Qlogic firmware interface allows every queue slot to have a SCSI + * command and up to 4 scatter/gather (SG) entries. If we need more + * than 4 SG entries, then continuation entries are used that can + * hold another 7 entries each. The start routine determines if there + * is eought empty slots then build the combination of requests to + * fulfill the OS request. + * + * Input: + * ha = adapter block pointer. + * sp = SCSI Request Block structure pointer. + * + * Returns: + * 0 = success, was able to issue command. + */ +STATIC uint8_t +qla1280_32bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + Scsi_Cmnd *cmd = sp->cmd; + uint32_t cnt; + cmd_entry_t *pkt; + uint16_t req_cnt; + uint16_t seg_cnt; + struct scatterlist *sg = (struct scatterlist *) NULL; + uint8_t *data_ptr; + uint32_t *dword_ptr; + + ENTER("qla1280_32bit_start_scsi"); + + + if( qla1280_check_for_dead_scsi_bus(ha, sp) ) + { + return(0); + } + + /* Calculate number of entries and segments required. */ + req_cnt = 1; + if (cmd->use_sg) + { + /* + * We must build an SG list in adapter format, as the kernel's SG list + * cannot be used directly because of data field size (__alpha__) + * differences and the kernel SG list uses virtual addresses where + * we need physical addresses. + */ + seg_cnt = cmd->use_sg; + sg = (struct scatterlist *) cmd->request_buffer; + /* + * if greater than four sg entries then we need to allocate + * continuation entries + */ + if (seg_cnt > 4) + { + req_cnt += (uint16_t)(seg_cnt - 4) / 7; + if ((uint16_t)(seg_cnt - 4) % 7) + req_cnt++; + } + DEBUG(sprintf(debug_buff,"S/G for data transfer -num segs(%d), req blk cnt(%d)\n\r",seg_cnt,req_cnt)); + DEBUG(qla1280_print(debug_buff)); + } + else if (cmd->request_bufflen) /* If data transfer. */ + { + DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen)); + seg_cnt = 1; + } + else + { + DEBUG(printk("No data transfer \n")); + seg_cnt = 0; + } + + /* Acquire ring specific lock */ + QLA1280_RING_LOCK(ha); + + if ((uint16_t)(req_cnt + 2) >= ha->req_q_cnt) + { + /* Calculate number of free request entries. */ + cnt = RD_REG_WORD(®->mailbox4); + 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); + } + + DEBUG(sprintf(debug_buff,"Number of free entries = (%d)\n\r",ha->req_q_cnt)); + DEBUG(qla1280_print(debug_buff)); + /* If room for request in request ring. */ + if ((uint16_t)(req_cnt + 2) < ha->req_q_cnt) + { + /* Check for empty slot in outstanding command list. */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && + (ha->outstanding_cmds[cnt] != 0); cnt++) + ; + + if (cnt < MAX_OUTSTANDING_COMMANDS) + { + CMD_HANDLE(sp->cmd) = (unsigned char *) cnt; + ha->outstanding_cmds[cnt] = sp; + ha->req_q_cnt -= req_cnt; + + /* + * Build command packet. + */ + pkt = (cmd_entry_t *)ha->request_ring_ptr; + + pkt->entry_type = COMMAND_TYPE; + pkt->entry_count = (uint8_t)req_cnt; + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->handle = (uint32_t)cnt; + + /* Zero out remaining portion of packet. */ + dword_ptr = (uint32_t *)pkt + 2; + for (cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Set ISP command timeout. */ + pkt->timeout = (uint16_t)30; + + /* Set device target ID and LUN */ + pkt->lun = SCSI_LUN_32(cmd); + pkt->target = SCSI_BUS_32(cmd) ? + (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); + + /* Enable simple tag queuing if device supports it. */ + if (cmd->device->tagged_queue ) + pkt->control_flags |= BIT_3; + + /* Load SCSI command packet. */ + pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd); + data_ptr = (uint8_t *) &(CMD_CDBP(cmd)); + for (cnt = 0; cnt < pkt->cdb_len; cnt++) + pkt->scsi_cdb[cnt] = *data_ptr++; + DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0])); + /* + * Load data segments. + */ + if (seg_cnt) + { + DEBUG(printk("loading data segments..\n")); + /* Set transfer direction (READ and WRITE) */ + /* Linux doesn't tell us */ + + /* + * 3/10 dg - Normally, we should need this check with our F/W + * but because of a small issue with it we do. + * + * For block devices, cmd->request.cmd has the operation + * For character devices, this isn't always set properly, so + * we need to check data_cmnd[0]. This catches the conditions + * for st.c, but not sg. Generic commands are pass down to us. + */ + if ( (cmd->data_cmnd[0] == WRITE_6) ) + pkt->control_flags |= BIT_6; + else + pkt->control_flags |= (BIT_5|BIT_6); + + sp->dir = pkt->control_flags & (BIT_5|BIT_6); + + /* Set total data segment count. */ + pkt->dseg_count = seg_cnt; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *)&pkt->dseg_0_address; + + if (cmd->use_sg) /* If scatter gather */ + { + DEBUG(qla1280_print("Building S/G data segments..\n\r")); + DEBUG(qla1280_dump_buffer((caddr_t)sg, 4*16 )); + /* Load command entry data segments. */ + for (cnt = 0; cnt < 4 && seg_cnt; cnt++, seg_cnt--) + { + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(sg->address)); + *dword_ptr++ = sg->length; + DEBUG(sprintf(debug_buff,"SG Segment ap=0x%x, len=0x%x\n\r",sg->address,sg->length)); + DEBUG(qla1280_print(debug_buff)); + sg++; + } + /* + * Build continuation packets. + */ + while (seg_cnt > 0) + { + /* 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++; + + pkt = (cmd_entry_t *)ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for (cnt = 0;cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Load packet defaults. */ + ((cont_entry_t *)pkt)->entry_type = + CONTINUE_TYPE; + ((cont_entry_t *)pkt)->entry_count = 1; + + ((cont_entry_t *)pkt)->sys_define = (uint8_t) + ha->req_ring_index; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *) + &((cont_entry_t *)pkt)->dseg_0_address; + + /* Load continuation entry data segments. */ + for (cnt = 0; cnt < 7 && seg_cnt; cnt++, seg_cnt--) + { + *dword_ptr++ = (u_int) cpu_to_le32(VIRT_TO_BUS(sg->address)); + *dword_ptr++ = sg->length; + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_32bit_start_scsi: continuation packet data - scsi("); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla1280_print(":"); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print(":"); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print(")\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } + else /* No scatter gather data transfer */ + { + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer)); + *dword_ptr = (uint32_t) cmd->request_bufflen; + DEBUG(printk("Single Segment ap=0x%x, len=0x%x\n",cmd->request_buffer,cmd->request_bufflen)); + } + } + else /* No data transfer */ + { + *dword_ptr++ = (uint32_t) 0; + *dword_ptr = (uint32_t) 0; +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_32bit_start_scsi: No data, command packet data - "); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_32bit_start_scsi: First IOCB block:\n\r"); + qla1280_dump_buffer((caddr_t)ha->request_ring_ptr, REQUEST_ENTRY_SIZE); +#endif + /* 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. */ + DEBUG(qla1280_print("qla1280_32bit_start_scsi: Wakeup RISC for pending command\n\r")); + ha->qthreads--; + sp->u_start = jiffies; + sp->flags |= SRB_SENT; + ha->actthreads++; + /* qla1280_output_number((uint32_t)ha->actthreads++, 16); */ + WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r"); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); + qla1280_print("\n\r"); +#endif + } + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + /* qla1280_print("qla1280_32bit_start_scsi: in-ptr="); + qla1280_output_number((uint32_t)ha->req_ring_index, 16); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); + qla1280_print(" req_cnt="); + qla1280_output_number((uint32_t)req_cnt, 16); + qla1280_print("\n\r"); */ +#endif + } + + /* Release ring specific lock */ + QLA1280_RING_UNLOCK(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + /* if (status) + qla1280_print("qla1280_32bit_start_scsi: **** FAILED ****\n\r"); */ +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_32bit_start_scsi"); +#endif + return(status); +} + +/* + * qla1280_req_pkt + * Function is responsible for locking ring and + * getting a zeroed out request packet. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = failed to get slot. + */ +STATIC request_t * +qla1280_req_pkt(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + request_t *pkt = 0; + uint16_t cnt; + uint32_t *dword_ptr; + uint32_t timer; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_req_pkt"); +#endif + + /* Wait for 30 seconds for slot. */ + for (timer = 15000000; timer; timer--) + { + /* Acquire ring specific lock */ + QLA1280_RING_LOCK(ha); + + if (ha->req_q_cnt > 0) + { + /* Calculate number of free request entries. */ + cnt = RD_REG_WORD(®->mailbox4); + 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); + } + + /* Found empty request ring slot? */ + if (ha->req_q_cnt > 0) + { + 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 */ + QLA1280_RING_UNLOCK(ha); + + SYS_DELAY(2); /* 10 */ + + /* Check for pending interrupts. */ + qla1280_poll(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_req_pkt: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_req_pkt: exiting normally\n\r"); +#endif + return(pkt); +} + +/* + * qla1280_isp_cmd + * Function is responsible for modifying ISP input pointer. + * Releases ring lock. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_isp_cmd(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_isp_cmd"); +#endif + +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isp_cmd: IOCB data:\n\r"); + qla1280_dump_buffer((caddr_t)ha->request_ring_ptr, REQUEST_ENTRY_SIZE); +#endif + + /* 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(®->mailbox4, ha->req_ring_index); + + /* Release ring specific lock */ + QLA1280_RING_UNLOCK(ha); + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_isp_cmd"); +#endif +} + +/* + * qla1280_enable_lun + * Issue enable LUN entry IOCB. + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS number. + * l = LUN number. + */ +STATIC void +qla1280_enable_lun(scsi_qla_host_t *ha, uint8_t b, uint32_t l) +{ + elun_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_enable_lun: entered\n\r"); +#endif + + /* Get request packet. */ + /* + if (pkt = (elun_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = ENABLE_LUN_TYPE; + pkt->lun = (uint16_t)(b ? l | BIT_15 : l); + pkt->command_count = 32; + pkt->immed_notify_count = 1; + pkt->group_6_length = MAX_CMDSZ; + pkt->group_7_length = MAX_CMDSZ; + pkt->timeout = 0x30; + + qla1280_isp_cmd(ha); + } + */ + pkt = (elun_entry_t *)1; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_enable_lun: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_enable_lun: exiting normally\n\r"); +#endif +} + +#if QL1280_TARGET_MODE_SUPPORT +/****************************************************************************/ +/* Target Mode Support Functions. */ +/****************************************************************************/ + +/* + * qla1280_notify_ack + * Issue notify acknowledge IOCB. + * If sequence ID is zero, acknowledgement of + * SCSI bus reset or bus device reset is assumed. + * + * Input: + * ha = adapter block pointer. + * inotify = immediate notify entry pointer. + */ +STATIC void +qla1280_notify_ack(scsi_qla_host_t *ha, notify_entry_t *inotify) +{ + nack_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_notify_ack: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (nack_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = NOTIFY_ACK_TYPE; + pkt->lun = inotify->lun; + pkt->initiator_id = inotify->initiator_id; + pkt->target_id = inotify->target_id; + if (inotify->seq_id == 0) + pkt->event = BIT_7; + else + pkt->seq_id = inotify->seq_id; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_notify_ack: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_notify_ack: exiting normally\n\r"); +#endif +} + +/* + * qla1280_immed_notify + * Issue immediate notify IOCB for LUN 0. + * + * Input: + * ha = adapter block pointer. + * inotify = immediate notify entry pointer. + */ +STATIC void +qla1280_immed_notify(scsi_qla_host_t *ha, notify_entry_t *inotify) +{ + notify_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_immed_notify: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (notify_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = IMMED_NOTIFY_TYPE; + pkt->lun = inotify->lun; + pkt->initiator_id = inotify->initiator_id; + pkt->target_id = inotify->target_id; + pkt->status = 1; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_immed_notify: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_immed_notify: exiting normally\n\r"); +#endif +} + +/* + * qla1280_accept_io + * Issue accept target I/O IOCB for LUN 0. + * + * Input: + * ha = adapter block pointer. + * ctio = ctio returned entry pointer. + */ +STATIC void +qla1280_accept_io(scsi_qla_host_t *ha, ctio_ret_entry_t *ctio) +{ + atio_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_accept_io: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (atio_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = ACCEPT_TGT_IO_TYPE; + pkt->lun = ctio->lun; + pkt->initiator_id = ctio->initiator_id; + pkt->target_id = ctio->target_id; + pkt->tag_value = ctio->tag_value; + pkt->status = 1; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_accept_io: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_accept_io: exiting normally\n\r"); +#endif +} + +/* + * qla1280_64bit_continue_io + * Issue continue target I/O IOCB. + * + * Input: + * ha = adapter block pointer. + * atio = atio pointer. + * len = total bytecount. + * addr = physical address pointer. + */ +STATIC void +qla1280_64bit_continue_io(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len, + paddr32_t *addr) +{ + ctio_a64_entry_t *pkt; + uint32_t *dword_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_64bit_continue_io: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (ctio_a64_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = CTIO_A64_TYPE; + pkt->lun = atio->lun; + pkt->initiator_id = atio->initiator_id; + pkt->target_id = atio->target_id; + pkt->option_flags = atio->option_flags; + pkt->tag_value = atio->tag_value; + pkt->scsi_status = atio->scsi_status; + + if (len) + { + pkt->dseg_count = 1; + pkt->transfer_length = len; + pkt->dseg_0_length = len; + dword_ptr = (uint32_t *)addr; + pkt->dseg_0_address[0] = *dword_ptr++; + pkt->dseg_0_address[1] = *dword_ptr; + } + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_64bit_continue_io: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_64bit_continue_io: exiting normally\n\r"); +#endif +} + +/* + * qla1280_32bit_continue_io + * Issue continue target I/O IOCB. + * + * Input: + * ha = adapter block pointer. + * atio = atio pointer. + * len = total bytecount. + * addr = physical address pointer. + */ +STATIC void +qla1280_32bit_continue_io(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len, + paddr32_t *addr) +{ + ctio_entry_t *pkt; + uint32_t *dword_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_32bit_continue_io: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (ctio_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = CONTINUE_TGT_IO_TYPE; + pkt->lun = atio->lun; + pkt->initiator_id = atio->initiator_id; + pkt->target_id = atio->target_id; + pkt->option_flags = atio->option_flags; + pkt->tag_value = atio->tag_value; + pkt->scsi_status = atio->scsi_status; + + if (len) + { + pkt->dseg_count = 1; + pkt->transfer_length = len; + pkt->dseg_0_length = len; + dword_ptr = (uint32_t *)addr; + pkt->dseg_0_address = *dword_ptr; + } + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_32bit_continue_io: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_32bit_continue_io: exiting normally\n\r"); +#endif +} +#endif /* QL1280_TARGET_MODE_SUPPORT */ + +/****************************************************************************/ +/* Interrupt Service Routine. */ +/****************************************************************************/ + +/**************************************************************************** + * qla1280_isr + * Calls I/O done on command completion. + * + * Input: + * ha = adapter block pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + * INTR_LOCK must be already obtained. + ****************************************************************************/ +STATIC void +qla1280_isr(scsi_qla_host_t *ha, srb_t **done_q_first, srb_t **done_q_last) +{ + device_reg_t *reg = ha->iobase; + response_t *pkt; + srb_t *sp; + uint16_t mailbox[MAILBOX_REGISTER_COUNT]; + uint16_t *wptr; + uint32_t index; + + ENTER("qla1280_isr"); + + + /* Save mailbox register 5 */ + mailbox[5] = RD_REG_WORD(®->mailbox5); + + /* Check for mailbox interrupt. */ + + mailbox[0] = RD_REG_WORD(®->semaphore); + if (mailbox[0] & BIT_0) + { + /* Get mailbox data. */ + + wptr = &mailbox[0]; + *wptr++ = RD_REG_WORD(®->mailbox0); + *wptr++ = RD_REG_WORD(®->mailbox1); + *wptr = RD_REG_WORD(®->mailbox2); + if (mailbox[0] != MBA_SCSI_COMPLETION) + { + wptr++; + *wptr++ = RD_REG_WORD(®->mailbox3); + *wptr++ = RD_REG_WORD(®->mailbox4); + wptr++; + *wptr++ = RD_REG_WORD(®->mailbox6); + *wptr = RD_REG_WORD(®->mailbox7); + } + + /* Release mailbox registers. */ + + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isr: mailbox interrupt mailbox[0] = "); + qla1280_output_number((uint32_t)mailbox[0], 16); + qla1280_print("\n\r"); +#endif + + /* Handle asynchronous event */ + + switch (mailbox[0]) + { + case MBA_SCSI_COMPLETION: /* Response completion */ +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isr: mailbox response completion\n\r"); +#endif + if (ha->flags.online) + { + /* Get outstanding command index. */ + index = (uint32_t)(mailbox[2] << 16 | mailbox[1]); + + /* Validate handle. */ + if (index < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[index]; + else + sp = 0; + + if (sp) + { + /* Free outstanding command slot. */ + ha->outstanding_cmds[index] = 0; + + /* Save ISP completion status */ + CMD_RESULT(sp->cmd) = 0; + + /* Place block on done queue */ + sp->s_next = NULL; + sp->s_prev = *done_q_last; + if (!*done_q_first) + *done_q_first = sp; + else + (*done_q_last)->s_next = sp; + *done_q_last = sp; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP invalid handle\n\r"); +#endif + printk(KERN_WARNING "qla1280: ISP invalid handle"); + ha->flags.isp_abort_needed = TRUE; + } + } + break; + case MBA_BUS_RESET: /* SCSI Bus Reset */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: asynchronous BUS_RESET\n\r"); +#endif + ha->flags.reset_marker = TRUE; + index = mailbox[6] & BIT_0; + ha->bus_settings[index].reset_marker = TRUE; + break; + case MBA_SYSTEM_ERR: /* System Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP System Error - mbx1="); + qla1280_output_number((uint32_t)mailbox[1], 16); + qla1280_print(", mbx2="); + qla1280_output_number((uint32_t)mailbox[2], 16); + qla1280_print(", mbx3="); + qla1280_output_number((uint32_t)mailbox[3], 16); + qla1280_print("\n\r"); +#endif + printk(KERN_WARNING + "qla1280: ISP System Error - mbx1=%xh, mbx2=%xh, mbx3=%xh\n", + mailbox[1], mailbox[2], mailbox[3]); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP Request Transfer Error\n\r"); +#endif + printk(KERN_WARNING "qla1280: ISP Request Transfer Error\n"); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP Response Transfer Error\n\r"); +#endif + printk(KERN_WARNING "qla1280: ISP Response Transfer Error\n"); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: asynchronous WAKEUP_THRES\n\r"); +#endif + break; + case MBA_TIMEOUT_RESET: /* Execution Timeout Reset */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: asynchronous TIMEOUT_RESET\n\r"); +#endif + break; + case MBA_DEVICE_RESET: /* Bus Device Reset */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_isr: asynchronous BUS_DEVICE_RESET\n\r"); +#endif + ha->flags.reset_marker = TRUE; + index = mailbox[6] & BIT_0; + ha->bus_settings[index].reset_marker = TRUE; + break; + case MBA_BUS_MODE_CHANGE: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_isr: asynchronous BUS_MODE_CHANGE\n\r"); +#endif + break; + default: + if (mailbox[0] < MBA_ASYNC_EVENT) + { + wptr = &mailbox[0]; + ha->mailbox_out[0] = *wptr++; + ha->mailbox_out[1] = *wptr++; + ha->mailbox_out[2] = *wptr++; + ha->mailbox_out[3] = *wptr++; + ha->mailbox_out[4] = *wptr++; + ha->mailbox_out[5] = *wptr++; + ha->mailbox_out[6] = *wptr++; + ha->mailbox_out[7] = *wptr; + ha->flags.mbox_int = TRUE; + } + break; + } + } + else + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + + /* + * Response ring + */ + if (ha->flags.online && !ha->flags.mbox_busy) + { + if (mailbox[5] < RESPONSE_ENTRY_CNT) + { + while (ha->rsp_ring_index != mailbox[5]) + { + pkt = ha->response_ring_ptr; + +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isr: ha->rsp_ring_index = "); + qla1280_output_number((uint32_t)ha->rsp_ring_index, 16); + qla1280_print(" mailbox[5] = "); + qla1280_output_number((uint32_t)mailbox[5], 16); + qla1280_print("\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)pkt, RESPONSE_ENTRY_SIZE); +#endif + +#if defined(QL_DEBUG_LEVEL_2) && !defined(QL_DEBUG_LEVEL_5) + if (pkt->entry_type == STATUS_TYPE) + { + if ((uint8_t)(pkt->scsi_status) || pkt->comp_status || + pkt->entry_status) + { + DEBUG(qla1280_print("qla1280_isr: ha->rsp_ring_index = ");) + DEBUG(qla1280_output_number((uint32_t)ha->rsp_ring_index, + 16);) + DEBUG(qla1280_print(" mailbox[5] = ");) + DEBUG(qla1280_output_number((uint32_t)mailbox[5], 16);) + DEBUG(qla1280_print( "\n\r comp_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->comp_status,16);) + DEBUG(qla1280_print( ", ");) + DEBUG(qla1280_print( " scsi_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->scsi_status,16);) + DEBUG(qla1280_print( "\n\r");) + /* qla1280_print( + "\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)pkt, + RESPONSE_ENTRY_SIZE); */ + } + } + else + { + qla1280_print("qla1280_isr: ha->rsp_ring_index = "); + qla1280_output_number((uint32_t)ha->rsp_ring_index, 16); + qla1280_print(" mailbox[5] = "); + qla1280_output_number((uint32_t)mailbox[5], 16); + qla1280_print( + "\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)pkt, RESPONSE_ENTRY_SIZE); + } +#endif + if (pkt->entry_type == STATUS_TYPE || pkt->entry_status) + { + if (pkt->entry_type == STATUS_TYPE) + qla1280_status_entry(ha, (sts_entry_t *)pkt, + done_q_first, done_q_last); + else + qla1280_error_entry(ha, pkt, + done_q_first, done_q_last); + + /* Adjust ring index. */ + ha->rsp_ring_index++; + if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) + { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } + else + ha->response_ring_ptr++; + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + } +#if QLA1280_TARGET_MODE_SUPPORT + else + { + pkt = &response_entry; + + /* Copy packet. */ + dptr1 = (uint32_t *)ha->response_ring_ptr; + dptr2 = (uint32_t *)pkt; + for (index = 0; index < RESPONSE_ENTRY_SIZE/4; index++) + *dptr2++ = *dptr1++; + + /* Adjust ring index. */ + ha->rsp_ring_index++; + if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) + { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } + else + ha->response_ring_ptr++; + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + + /* Release interrupt specific lock */ + QLA1280_INTR_UNLOCK(ha); + + switch (pkt->entry_type) + { + case ACCEPT_TGT_IO_TYPE: + qla1280_atio_entry(ha, (atio_entry_t *)pkt); + break; + case IMMED_NOTIFY_TYPE: + qla1280_notify_entry(ha, (notify_entry_t *)pkt); + break; + case CTIO_RET_TYPE: + qla1280_accept_io(ha, (ctio_ret_entry_t *)pkt); + break; + default: + break; + } + + /* Acquire interrupt specific lock */ + QLA1280_INTR_LOCK(ha); + } +#endif + } + } + else + { + ha->flags.isp_abort_needed = TRUE; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: Response pointer Error\n"); +#endif + } + } + + LEAVE("qla1280_isr"); +} + +/* + * qla1280_rst_aen + * Processes asynchronous reset. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_rst_aen(scsi_qla_host_t *ha) +{ +#if QL1280_TARGET_MODE_SUPPORT + notify_entry_t nentry; +#endif + uint8_t b; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_rst_aen"); +#endif + + if (ha->flags.online && !ha->flags.reset_active && + !ha->flags.abort_isp_active) + { + ha->flags.reset_active = TRUE; + while (ha->flags.reset_marker) + { + /* Issue marker command. */ + ha->flags.reset_marker = FALSE; + for (b = 0; b < ha->ports && !ha->flags.reset_marker; b++) + { + if (ha->bus_settings[b].reset_marker) + { + ha->bus_settings[b].reset_marker = FALSE; + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + + if (!ha->flags.reset_marker) + { +#if QL1280_TARGET_MODE_SUPPORT + /* Issue notify acknowledgement command. */ + bzero((caddr_t)&nentry, sizeof(notify_entry_t)); + + nentry.initiator_id = nentry.target_id = b ? + ha->bus_settings[b].id | BIT_7 : + ha->bus_settings[b].id; + qla1280_notify_entry(ha, &nentry); +#endif + + /* Asynchronous event notification */ + } + } + } + } + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_rst_aen"); +#endif +} + +#if QL1280_TARGET_MODE_SUPPORT +/* + * qla1280_atio_entry + * Processes received ISP accept target I/O entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + */ +STATIC void +qla1280_atio_entry(scsi_qla_host_t *ha, atio_entry_t *pkt) +{ + uint64_t *a64; + uint64_t *end_a64; + paddr32_t phy_addr[2]; + paddr32_t end_addr[2]; + uint32_t len; + uint32_t offset; + uint8_t t; + uint8_t *sense_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: entered\n\r"); +#endif + + t = pkt->initiator_id; + sense_ptr = ha->tsense + t * TARGET_SENSE_SIZE; + a64 = (uint64_t *)&phy_addr[0]; + end_a64 = (uint64_t *)&end_addr[0]; + + switch (pkt->status & ~BIT_7) + { + case 7: /* Path invalid */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_atio_entry: Path invalid\n\r"); +#endif + break; + case 0x14: /* Target Bus Phase Sequence Failure */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print( + "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r"); +#endif + if (pkt->status & BIT_7) + { + BCOPY((caddr_t)&pkt->sense_data, sense_ptr,TARGET_SENSE_SIZE); + } + else + { + bzero(sense_ptr, TARGET_SENSE_SIZE); + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_HARDERR; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_SELFAIL; + } + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | (uint32_t)OF_NO_DATA; + if (ha->flags.enable_64bit_addressing) + qla1280_64bit_continue_io(ha, pkt, 0, 0); + else + qla1280_32bit_continue_io(ha, pkt, 0, 0); + break; + case 0x16: /* Requested Capability Not Available */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print( + "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r"); +#endif + break; + case 0x17: /* Bus Device Reset Message Received */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print( + "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r"); +#endif + break; + case 0x3D: /* CDB Received */ + + /* Check for invalid LUN */ + if (pkt->lun && pkt->cdb[0] != SS_INQUIR && + pkt->cdb[0] != SS_REQSEN) + pkt->cdb[0] = SS_TEST; + + switch (pkt->cdb[0]) + { + case SS_TEST: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SS_TEST\n\r"); +#endif + bzero(sense_ptr, TARGET_SENSE_SIZE); + len = 0; + if (pkt->lun == 0) + pkt->scsi_status = S_GOOD; + else + { + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_INVLUN; + pkt->scsi_status = S_CKCON; + } + + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + case SS_REQSEN: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SS_REQSEN\n\r"); +#endif + phy_addr[0] = ha->tsense_dma; + phy_addr[1] = 0; + *a64 += t * TARGET_SENSE_SIZE; + if (pkt->cdb[4] > TARGET_SENSE_SIZE) + len = TARGET_SENSE_SIZE; + else + len = pkt->cdb[4]; + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + break; + case SS_INQUIR: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SS_INQUIR\n\r"); +#endif + bzero(sense_ptr, TARGET_SENSE_SIZE); + phy_addr[0] = ha->tbuf_dma; + phy_addr[1] = 0; + *a64 += TARGET_INQ_OFFSET; + + if (pkt->lun == 0) + { + ha->tbuf->inq.id_type = ID_PROCESOR; + ha->tbuf->inq.id_pqual = ID_QOK; + } + else + { + ha->tbuf->inq.id_type = ID_NODEV; + ha->tbuf->inq.id_pqual = ID_QNOLU; + } + + if (pkt->cdb[4] > sizeof(struct ident)) + len = sizeof(struct ident); + else + len = pkt->cdb[4]; + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + break; + case SM_WRDB: + bzero(sense_ptr, TARGET_SENSE_SIZE); + offset = pkt->cdb[5]; + offset |= pkt->cdb[4] << 8; + offset |= pkt->cdb[3] << 16; + len = pkt->cdb[8]; + len |= pkt->cdb[7] << 8; + len |= pkt->cdb[6] << 16; + end_addr[0] = phy_addr[0] = ha->tbuf_dma; + end_addr[1] = phy_addr[1] = 0; + *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; + switch (pkt->cdb[1] & 7) + { + case RW_BUF_HDATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_HDATA\n\r"); +#endif + if (len > TARGET_DATA_SIZE + 4) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, length > buffer size\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + len = 0; + } + else if (len) + { + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_OUT; +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: Issuing SDI_TARMOD_WRCOMP\n\r"); +#endif + sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr, + pkt->target_id, pkt->lun, 0, offset); + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + + break; + case RW_BUF_DATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_DATA\n\r"); +#endif + *a64 += offset + TARGET_DATA_OFFSET; + if (pkt->cdb[2] != 0 || *a64 >= *end_a64 || + *a64 + len > *end_a64) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_DATA BAD\n\r"); + qla1280_print("buf_id="); + qla1280_output_number((uint32_t)pkt->cdb[2], 16); + qla1280_print(", offset="); + qla1280_output_number((uint32_t)offset, 16); + qla1280_print(", length="); + qla1280_output_number((uint32_t)len, 16); + qla1280_print("\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + else if (len) + { + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_OUT; +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: Issuing SDI_TARMOD_WRCOMP\n\r"); +#endif + sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr, + pkt->target_id, pkt->lun, 0, offset); + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB unknown mode\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + } + break; + case SM_RDDB: + bzero(sense_ptr, TARGET_SENSE_SIZE); + offset = pkt->cdb[5]; + offset |= pkt->cdb[4] << 8; + offset |= pkt->cdb[3] << 16; + len = pkt->cdb[8]; + len |= pkt->cdb[7] << 8; + len |= pkt->cdb[6] << 16; + end_addr[0] = phy_addr[0] = ha->tbuf_dma; + end_addr[1] = phy_addr[1] = 0; + *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; + switch (pkt->cdb[1] & 7) + { + case RW_BUF_HDATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_HDATA\n\r"); +#endif + if (len) + { + ha->tbuf->hdr[0] = 0; + ha->tbuf->hdr[1] = + (uint8_t)(TARGET_DATA_SIZE >> 16); + ha->tbuf->hdr[2] = + (uint8_t)(TARGET_DATA_SIZE >> 8); + ha->tbuf->hdr[3] = (uint8_t)TARGET_DATA_SIZE; + if (len > TARGET_DATA_SIZE + 4) + len = TARGET_DATA_SIZE + 4; + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + break; + case RW_BUF_DATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DATA\n\r"); +#endif + *a64 += offset + TARGET_DATA_OFFSET; + if (pkt->cdb[2] != 0 || *a64 >= *end_a64) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DATA BAD\n\r"); + qla1280_print("buf_id="); + qla1280_output_number((uint32_t)pkt->cdb[2], 16); + qla1280_print(", offset="); + qla1280_output_number((uint32_t)offset, 16); + qla1280_print("\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + else + { + if (*a64 + len > *end_a64) + len = *end_a64 - *a64; + if (len) + { + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + } + break; + case RW_BUF_DESC: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DESC\n\r"); +#endif + if (len) + { + if (len > 4) + len = 4; + + ha->tbuf->hdr[0] = 0; + if (pkt->cdb[2] != 0) + { + ha->tbuf->hdr[1] = 0; + ha->tbuf->hdr[2] = 0; + ha->tbuf->hdr[3] = 0; + } + else + { + ha->tbuf->hdr[1] = + (uint8_t)(TARGET_DATA_SIZE >> 16); + ha->tbuf->hdr[2] = + (uint8_t)(TARGET_DATA_SIZE >> 8); + ha->tbuf->hdr[3] = + (uint8_t)TARGET_DATA_SIZE; + } + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB unknown mode\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: Unknown SCSI command\n\r"); + qla1280_dump_buffer((caddr_t)&pkt->cdb[0], pkt->cdb_len); +#endif + bzero(sense_ptr, TARGET_SENSE_SIZE); + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_INVOPCODE; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + } + if (ha->flags.enable_64bit_addressing) + qla1280_64bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); + else + qla1280_32bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); + break; + default: + break; + } + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: exiting normally\n\r"); +#endif +} + +/* + * qla1280_notify_entry + * Processes received ISP immediate notify entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + */ +STATIC void +qla1280_notify_entry(scsi_qla_host_t *ha, notify_entry_t *pkt) +{ +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_notify_entry: entered\n\r"); +#endif + + /* Acknowledge immediate notify */ + qla1280_notify_ack(ha, pkt); + + /* Issue notify entry to increment resource count */ + qla1280_immed_notify(ha, pkt); + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_notify_entry: exiting normally\n\r"); +#endif +} + +#endif /* QLA1280_TARGET_MODE_SUPPORT */ +/* + * qla1280_status_entry + * Processes received ISP status entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + */ +STATIC void +qla1280_status_entry(scsi_qla_host_t *ha, sts_entry_t *pkt, srb_t **done_q_first, + srb_t **done_q_last) +{ + uint32_t b, t, l; + uint8_t sense_sz = 0; + srb_t *sp; + scsi_lu_t *q; + Scsi_Cmnd *cp; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_status_entry"); +#endif + + /* Validate handle. */ + if (pkt->handle < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[pkt->handle]; + else + sp = 0; + + if (sp) + { + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle] = 0; + + cp = sp->cmd; + /* Generate LU queue on cntrl, target, LUN */ + b = SCSI_BUS_32(cp); + t = SCSI_TCN_32(cp); + l = SCSI_LUN_32(cp); + q = LU_Q(ha, b, t, l); + if( pkt->comp_status || pkt->scsi_status ) + { + DEBUG(qla1280_print( "scsi: comp_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->comp_status,16);) + DEBUG(qla1280_print( ", ");) + DEBUG(qla1280_print( " scsi_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->scsi_status,16);) + DEBUG(qla1280_print( "\n\r");) + DEBUG(qla1280_print(", handle = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->handle, 16);) + DEBUG(qla1280_print("\n\r");) + } + + /* Target busy */ + if ( pkt->scsi_status & SS_BUSY_CONDITION && + pkt->scsi_status != SS_RESERVE_CONFLICT ) + { + CMD_RESULT(cp) = (int) (DID_BUS_BUSY << 16) | + (pkt->scsi_status & 0xff); + } + else + { + + /* Save ISP completion status */ + CMD_RESULT(cp) = qla1280_return_status( pkt, cp ); + + if (pkt->scsi_status & SS_CHECK_CONDITION) + { + BZERO(cp->sense_buffer, CMD_SNSLEN(cp)); + if (pkt->comp_status != CS_ARS_FAILED) + { + if ( pkt->req_sense_length < CMD_SNSLEN(cp) ) + sense_sz = pkt->req_sense_length; + else + sense_sz = CMD_SNSLEN(cp) - 1; + + BCOPY((caddr_t)&pkt->req_sense_data, cp->sense_buffer, sense_sz); + + } +#ifdef QL_DEBUG_LEVEL_2 + DEBUG(qla1280_print( + "qla1280_status_entry: Check condition Sense data, b");) + DEBUG(qla1280_output_number((uint32_t)b, 10);) + DEBUG(qla1280_print("t");) + DEBUG(qla1280_output_number((uint32_t)t, 10);) + DEBUG(qla1280_print("d");) + DEBUG(qla1280_output_number((uint32_t)l, 10);) + DEBUG(qla1280_print("\n\r");) + DEBUG(if (sense_sz)) + DEBUG(qla1280_dump_buffer(cp->sense_buffer, sense_sz);) +#endif + } + } + /* Place command on done queue. */ + qla1280_done_q_put(sp, done_q_first, done_q_last); + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_status_entry: ISP Invalid handle\n\r"); +#endif + printk(KERN_WARNING "qla1280: Status Entry invalid handle\n"); + ha->flags.isp_abort_needed = TRUE; + } +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_status_entry"); +#endif +} + +/* + * qla1280_error_entry + * Processes error entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + */ +STATIC void +qla1280_error_entry(scsi_qla_host_t *ha, response_t *pkt, srb_t **done_q_first, + srb_t **done_q_last) +{ + srb_t *sp; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_error_entry"); +#endif + +#ifdef QL_DEBUG_LEVEL_2 + if (pkt->entry_status & BIT_3) + qla1280_print("qla1280_error_entry: BAD PAYLOAD flag error\n\r"); + else if (pkt->entry_status & BIT_2) + qla1280_print("qla1280_error_entry: BAD HEADER flag error\n\r"); + else if (pkt->entry_status & BIT_1) + qla1280_print("qla1280_error_entry: FULL flag error\n\r"); + else + qla1280_print("qla1280_error_entry: UNKNOWN flag error\n\r"); +#endif + + /* Validate handle. */ + if (pkt->handle < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[pkt->handle]; + else + sp = 0; + + if (sp) + { + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle] = 0; + + /* Bad payload or header */ + if (pkt->entry_status & (BIT_3 + BIT_2)) + { + /* Bad payload or header, set error status. */ + /* CMD_RESULT(sp->cmd) = CS_BAD_PAYLOAD; */ + CMD_RESULT(sp->cmd) = (int) DID_ERROR << 16; + } + else if (pkt->entry_status & BIT_1 ) /* FULL flag */ + { + CMD_RESULT(sp->cmd) = (int) DID_BUS_BUSY << 16; + } + else + { + /* Set error status. */ + CMD_RESULT(sp->cmd) =(int) DID_ERROR << 16; + } + /* Place command on done queue. */ + qla1280_done_q_put(sp, done_q_first, done_q_last); + } +#if QLA1280_64BIT_SUPPORT + else if (pkt->entry_type == COMMAND_A64_TYPE) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_error_entry: ISP Invalid handle\n\r"); +#endif + printk(KERN_WARNING, "!qla1280: Error Entry invalid handle"); + ha->flags.isp_abort_needed = TRUE; + } +#endif + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_error_entry"); +#endif +} + +/* + * qla1280_abort_isp + * Resets ISP and aborts all outstanding commands. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_abort_isp(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + uint16_t cnt; + srb_t *sp; + scsi_lu_t *q; + uint32_t b, t, l; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_abort_isp"); +#endif + + DRIVER_LOCK + ha->flags.isp_abort_needed = FALSE; + if (!ha->flags.abort_isp_active && ha->flags.online) + { + ha->flags.abort_isp_active = TRUE; + + /* Disable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, 0); + + /* Dequeue 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; + + /* Generate LU queue on controller, target, LUN */ + b = SCSI_BUS_32(sp->cmd); + t = SCSI_TCN_32(sp->cmd); + l = SCSI_LUN_32(sp->cmd); + + q = (scsi_lu_t *)LU_Q(ha, b, t, l); + + /* Reset outstanding command count. */ + q->q_outcnt = 0; + q->q_flag &= ~QLA1280_QBUSY; + q->q_flag = 0; + + /* Adjust watchdog timer for command. */ + /* if (sp->flags & SRB_WATCHDOG) + sp->timeout += 2; */ + + /* Place request back on top of device queue. */ + sp->flags &= ~(SRB_SENT | SRB_TIMEOUT); + sp->flags = 0; + qla1280_putq_t(q, sp); + } + } + + /* If firmware needs to be loaded */ + if (qla1280_isp_firmware(ha)) + { + if (!(status = qla1280_chip_diag(ha))) + status = qla1280_setup_chip(ha); + } + + if (!status) + { + /* Setup adapter based on NVRAM parameters. */ + qla1280_nvram_config(ha); + + if (!(status = qla1280_init_rings(ha))) + { + /* Issue SCSI reset. */ + for (b = 0; b < ha->ports; b++) + { + qla1280_bus_reset(ha, b); + } + do + { + /* Issue marker command. */ + ha->flags.reset_marker = FALSE; + for (b = 0; b < ha->ports; b++) + { + ha->bus_settings[b].reset_marker = FALSE; + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + } + }while (ha->flags.reset_marker); + + /* Enable host adapter target mode. */ + for (b = 0; b < ha->ports; b++) + { + if (!(status = qla1280_enable_tgt(ha, b))) + { + for (cnt = 0; cnt < MAX_LUNS; cnt++) + { + /* qla1280_enable_lun(ha, b, cnt); */ + qla1280_poll(ha); + } + } + else + break; + } + + if (!status) + { + /* Enable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC); + ha->flags.abort_isp_active = FALSE; + /* Restart queues that may have been stopped. */ + qla1280_restart_queues(ha); + } + } + } + } + + if (status) + { + printk(KERN_WARNING + "qla1280: ISP error recovery failed, board disabled"); + qla1280_reset_adapter(ha); + qla1280_abort_queues(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_abort_isp: **** FAILED ****\n\r"); +#endif + } +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_abort_isp"); +#endif + DRIVER_UNLOCK + + return(status); +} + +/* + * qla1280_restart_queues + * Restart all device queues. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_restart_queues(scsi_qla_host_t *ha) +{ + scsi_lu_t *q; + uint32_t b, t, l; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_restart_queues"); +#endif + + for (b = 0; b < ha->ports; b++) + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + { + q = (scsi_lu_t *) LU_Q(ha, b, t, l); + if (q != NULL) + { + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + + if (q->q_first) + qla1280_next(ha, q, b); + else + /* Release LU queue specific lock */ + QLA1280_SCSILU_UNLOCK(q); + } + } +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_restart_queues: exiting normally\n"); +#endif +} + +/* + * qla1280_abort_queue_single + * Abort all commands on a device queues. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void qla1280_abort_queue_single(scsi_qla_host_t *ha,uint32_t b,uint32_t t,uint32_t l,uint32_t stat) +{ + scsi_lu_t *q; + srb_t *sp, *sp_next; + + ENTER("qla1280_abort_queue_single"); + q = (scsi_lu_t * )LU_Q(ha, b, t, l); + if (q != NULL) + { + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + + sp = q->q_first; + q->q_first = q->q_last = NULL; + + QLA1280_SCSILU_UNLOCK(q); + + while (sp) + { + sp_next = sp->s_next; + CMD_RESULT(sp->cmd) = stat; + qla1280_done_q_put(sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + sp = sp_next; + } + } + LEAVE("qla1280_abort_queue_single"); +} + +/* + * qla1280_abort_queues + * Abort all commands on device queues. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_abort_queues(scsi_qla_host_t *ha) +{ + uint32_t b, t, l; + + ENTER("qla1280_abort_queues"); + + for (b = 0; b < ha->ports; b++) + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + qla1280_abort_queue_single(ha,b,t,l,DID_RESET); + + LEAVE("qla1280_abort_queues"); +} + +/* + * qla1280_debounce_register + * Debounce register. + * + * Input: + * port = register address. + * + * Returns: + * register value. + */ +STATIC uint16_t +qla1280_debounce_register(volatile uint16_t *addr) +{ + volatile uint16_t ret; + volatile uint16_t ret2; + + do + { + ret = RD_REG_WORD(addr); + ret2 = RD_REG_WORD(addr); + }while (ret != ret2); + + return(ret); +} + + +/* + * Declarations for load module + */ +#ifdef MODULE +Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; + +#include "scsi_module.c" +#endif + +/************************************************************************ + * qla1280_check_for_dead_scsi_bus * + * * + * This routine checks for a dead SCSI bus * + ************************************************************************/ +#define SET_SXP_BANK 0x0100 +#define SCSI_PHASE_INVALID 0x87FF +int qla1280_check_for_dead_scsi_bus(scsi_qla_host_t *ha, srb_t *sp) +{ + uint16_t config_reg, scsi_control; + device_reg_t *reg = ha->iobase; + uint32_t b; + Scsi_Cmnd *cp; + + /* + * If SCSI Bus is Dead because of bad termination, + * we will return a status of Selection timeout. + */ + + cp = sp->cmd; + b = SCSI_BUS_32(cp); + if (ha->bus_settings[b].scsi_bus_dead) + { + WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); + config_reg = RD_REG_WORD(®->cfg_1); + WRT_REG_WORD(®->cfg_1,SET_SXP_BANK); + scsi_control = RD_REG_WORD(®->scsiControlPins); + WRT_REG_WORD(®->cfg_1,config_reg); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + + if (scsi_control == SCSI_PHASE_INVALID) + { + CMD_RESULT(cp) = DID_NO_CONNECT << 16; + CMD_HANDLE(cp) = (unsigned char *) 0; + /* ha->actthreads--; */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + sti(); + (*(cp)->scsi_done)(cp); + cli(); +#else + (*(cp)->scsi_done)(cp); +#endif + return(TRUE); /* bus is dead */ + } + else + { + ha->bus_settings[b].scsi_bus_dead = FALSE; + ha->bus_settings[b].failed_reset_count= 0; + } + } + return(FALSE); /* bus is not dead */ +} + + + +#ifdef QL_DEBUG_ROUTINES +/****************************************************************************/ +/* Driver Debug Functions. */ +/****************************************************************************/ + +/* + * Get byte from I/O port + */ +STATIC uint8_t +qla1280_getbyte(uint8_t *port) +{ + uint8_t ret; + +#if MEMORY_MAPPED_IO + ret = *port; +#else + ret = inb((int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_getbyte: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)ret, 16); + qla1280_print("\n\r"); + } + + return(ret); +} + +/* + * Get word from I/O port + */ +STATIC uint16_t +qla1280_getword(uint16_t *port) +{ + uint16_t ret; + +#if MEMORY_MAPPED_IO + ret = *port; +#else + ret = inw((int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_getword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)ret, 16); + qla1280_print("\n\r"); + } + + return(ret); +} + +/* + * Get double word from I/O port + */ +STATIC uint32_t +qla1280_getdword(uint32_t *port) +{ + uint32_t ret; + +#if MEMORY_MAPPED_IO + ret = *port; +#else + ret = inl((int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_getdword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)ret, 16); + qla1280_print("\n\r"); + } + + return(ret); +} + +/* + * Send byte to I/O port + */ +STATIC void +qla1280_putbyte(uint8_t *port, uint8_t data) +{ +#if MEMORY_MAPPED_IO + *port = data; +#else + outb(data, (int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_putbyte: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); + } +} + +/* + * Send word to I/O port + */ +STATIC void +qla1280_putword(uint16_t *port, uint16_t data) +{ +#if MEMORY_MAPPED_IO + *port = data; +#else +#ifdef _LINUX_IOPORTS + outw(data, (int)port); +#else + outw((int)port, data); +#endif +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_putword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); + } +} + +/* + * Send double word to I/O port + */ +STATIC void +qla1280_putdword(uint32_t *port, uint32_t data) +{ +#if MEMORY_MAPPED_IO + *port = data; +#else +#ifdef _LINUX_IOPORTS + outl(data,(int)port); +#else + outl((int)port, data); +#endif +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_putdword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); + } +} + +/* + * Dummy function to prevent warnings for + * declared and unused debug functions + */ +void +qla1280_debug(void) +{ + qla1280_getbyte(0); + qla1280_getword(0); + qla1280_getdword(0); + qla1280_putbyte(0, 0); + qla1280_putword(0, 0); + qla1280_putdword(0, 0); +} + +/* + * Out character to COM2 port. + * PORT must be at standard address for COM2 = 0x2F8, + * or COM1 = 0x3F8 + */ +#define OUTB(addr,data) outb((data),(addr)) + +STATIC void +qla1280_putc(uint8_t c) +{ +#ifdef QL_DEBUG_CONSOLE + printk("%c", c); +#else + int com_addr = 0x2f8; + int hardware_flow_control = 1; + int software_flow_control = 0; + uint8_t data; + + /* Wait for transmitter holding and shift registers for empty. */ + do + { + data = inb(com_addr+5); + }while (!(data & BIT_6)); + + /* + * Set BAUD rate for COM2 to 19200 (0x6) + */ + + /* Select rate divisor. */ + OUTB(com_addr+3, 0x83); + + /* BAUD rate divisor LSB. */ + OUTB(com_addr, 0xc); /* 0xC = 9600 baud */ + + /* BAUD rate divisor MSB. */ + OUTB(com_addr+1, 0); + + /* Set No parity, 8 bits, 1 stop bit and + select interrupt enable register. */ + OUTB(com_addr+3, 3); + + /* Disable interrupts. */ + OUTB(com_addr+1, 0); + + /* Set data terminal ready and request to send */ + OUTB(com_addr+4,3); + + if (hardware_flow_control) + { + /* Wait for clear-to-send and data-set-ready */ + do + { + data = inb(com_addr+6) & (BIT_5 + BIT_4); + }while (data != (BIT_5 + BIT_4)); + } + else if (software_flow_control) + { + /* Test for data ready. */ + data = inb(com_addr+5); + if (data & BIT_0) + { + /* If XOFF */ + data = inb(com_addr); + if (data == '\023') + { + /* Wait for XON */ + do + { + /* Wait for char */ + do + { + data = inb(com_addr+5); + }while (!(data & BIT_0)); + data = inb(com_addr); + }while (data != '\021'); + } + } + } + + /* Output character. */ + OUTB(com_addr, c); +#endif +} + +/* + * Out NULL terminated string to COM port. + */ +STATIC void +qla1280_print(caddr_t s) +{ + if (ql_debug_print) + { +#ifdef QL_DEBUG_CONSOLE + printk("%s",s); +#else + /* Output string. */ + while (*s) + qla1280_putc(*s++); +#endif + } +} + +/* + * Output long number to COM port. + */ +STATIC void +qla1280_output_number(uint32_t n, uint8_t base) +{ + int8_t str[12]; + int8_t *s = &str[11]; + int8_t output = 0; + int8_t hex = FALSE; + + if (ql_debug_print) + { + if (base == 10 || base == 16) + { + if (base == 16 && n > 9) + hex = TRUE; + + *s = 0; + do + { + s--; + *s = n % base; + if (*s > 9) + *s += 55; + else + *s += '0'; + n /= base; + }while (n); + + for (; *s; s++) + { + if (*s != '0') + output = 1; + if (output) + qla1280_putc(*s); + } + if (!output) + qla1280_putc(*--s); + + if (hex) + qla1280_putc('h'); + } + } +} + +STATIC void +qla1280_dump_buffer(caddr_t b, uint32_t size) +{ + uint32_t cnt; + uint8_t c; + + if (ql_debug_print) + { + qla1280_print( + " 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh Fh\n\r"); + qla1280_print( + "---------------------------------------------------------------\n\r"); + + for (cnt = 0; cnt < size; ) + { + c = *b++; + if (c < 16) + qla1280_putc(' '); + qla1280_output_number((uint32_t)c, 16); + cnt++; + if (!(cnt % 16)) + qla1280_print("\n\r"); + else if (c < 10) + qla1280_print(" "); + else + qla1280_putc(' '); + } + if (cnt % 16) + qla1280_print("\n\r"); + } +} +/************************************************************************** + * ql1280_print_scsi_cmd + * + **************************************************************************/ +void qla1280_print_scsi_cmd(Scsi_Cmnd *cmd) +{ + scsi_qla_host_t *ha; + struct Scsi_Host *host = cmd->host; + srb_t *sp; + /* struct scatterlist *sg; */ + + int i; + ha = (scsi_qla_host_t *) host->hostdata; + + ql_debug_print = 1; + sp = (srb_t *) CMD_SP(cmd); + sprintf(debug_buff,"SCSI Command @= 0x%08x, Handle=0x%08x\n\r", (int)cmd,(int) (int)CMD_HANDLE(cmd)); + qla1280_print(debug_buff); + sprintf(debug_buff," chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n\r", + cmd->channel, cmd->target, cmd->lun, cmd->cmd_len); + qla1280_print(debug_buff); + qla1280_print(" CDB = "); + for (i = 0; i < cmd->cmd_len; i++) + { + sprintf(debug_buff,"0x%02x ", cmd->cmnd[i]); + qla1280_print(debug_buff); + } + sprintf(debug_buff," seg_cnt =%d\n\r",cmd->use_sg); + qla1280_print(debug_buff); + sprintf(debug_buff," request buffer=0x%x, request buffer len=0x%x\n\r",(int)cmd->request_buffer,cmd->request_bufflen); + qla1280_print(debug_buff); + /* if( cmd->use_sg ) + { + sg = (struct scatterlist *) cmd->request_buffer; + qla1280_print(" SG buffer: \n\r"); + qla1280_dump_buffer((caddr_t)sg, (cmd->use_sg*sizeof(struct scatterlist)) ); + } */ + sprintf(debug_buff," tag=%d, flags=0x%x, transfersize=0x%x \n\r", + cmd->tag, cmd->flags,cmd->transfersize ); + qla1280_print(debug_buff); + sprintf(debug_buff," Pid=%d, SP=0x%x\n\r", (int)cmd->pid, (int)CMD_SP(cmd)); + qla1280_print(debug_buff); + sprintf(debug_buff," r_start=0x%lx, u_start=0x%lx\n\r",sp->r_start,sp->u_start); + qla1280_print(debug_buff); + sprintf(debug_buff," underflow size = 0x%lx, direction=0x%x, req.cmd=0x%x \n\r", cmd->underflow, sp->dir,cmd->request.cmd); + qla1280_print(debug_buff); +} +/************************************************************************** + * ql1280_dump_device + * + **************************************************************************/ +void +ql1280_dump_device(scsi_qla_host_t *ha) +{ + + Scsi_Cmnd *cp; + srb_t *sp; + int i; + qla1280_print("Outstanding Commands on controller:\n\r"); + for ( i=0; i < MAX_OUTSTANDING_COMMANDS; i++ ) + { + if( (sp = ha->outstanding_cmds[i]) == NULL ) + continue; + if( (cp = sp->cmd) == NULL ) + continue; + qla1280_print_scsi_cmd(cp); + } + +} +#endif + +#ifdef QLA1280_UNUSED +/************************************************************************** + * ql1280_dump_regs + * + **************************************************************************/ +static void qla1280_dump_regs(struct Scsi_Host *host) +{ + printk("Mailbox registers:\n"); + printk("qla1280 : mbox 0 0x%04x \n", inw(host->io_port + 0x70)); + printk("qla1280 : mbox 1 0x%04x \n", inw(host->io_port + 0x72)); + printk("qla1280 : mbox 2 0x%04x \n", inw(host->io_port + 0x74)); + printk("qla1280 : mbox 3 0x%04x \n", inw(host->io_port + 0x76)); + printk("qla1280 : mbox 4 0x%04x \n", inw(host->io_port + 0x78)); + printk("qla1280 : mbox 5 0x%04x \n", inw(host->io_port + 0x7a)); +} +#endif + + + +#if STOP_ON_ERROR +/************************************************************************** + * ql1280_panic + * + **************************************************************************/ +static void qla1280_panic(char *cp, struct Scsi_Host *host) +{ + scsi_qla_host_t *ha; + long *fp; + + ha = (scsi_qla_host_t *) host->hostdata; + printk("qla1280 - PANIC: %s\n",cp); + printk("Current time=0x%lx\n", jiffies); + printk("Number of pending commands =0x%lx\n", ha->actthreads); + printk("Number of SCSI 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); + DEBUG2(ql_debug_print = 1;) + /* DEBUG2(ql1280_dump_device((scsi_qla_host_t *) host->hostdata)); */ +#ifdef QLA1280_UNUSED + qla1280_dump_regs(host); +#endif + sti(); + panic("Ooops"); + /* cli(); + for(;;) + { + barrier(); + sti(); + } + */ +} +#endif + +#ifdef QLA1280_UNUSED +static void qla1280_set_flags(char * s) +{ +} +#endif + +/************************************************************************** + * qla1280_setup + * + * Handle Linux boot parameters. This routine allows for assigning a value + * to a parameter with a ':' between the parameter and the value. + * ie. qla1280=max_reqs:0x0A,verbose + **************************************************************************/ +void +qla1280_setup(char *s, int *dummy) +{ + char *end, *str, *cp; + +#ifdef QLA1280_UNUSED + static struct + { + const char *name; + int siz; + void (*func)(); + int arg; + } options[] = + { + { "dump_regs", 9, &qla1280_dump_regs, 0 + }, + { "verbose", 7, &qla1280_set_flags, 0x1 + }, + { "", 0, NULL, 0 + } + }; +#endif + + printk("scsi: Processing Option str = %s\n", s); + end = strchr(s, '\0'); + /* locate command */ + str = s; + for( cp = s; *cp && cp != end; cp++ ) + { + cp = qla1280_get_token(cp, str); + printk("scsi: token str = %s\n", str); + /* if found execute routine */ + + } + +} + +static char *qla1280_get_token(char *cmdline, char *str ) +{ + register char *cp = cmdline; + + /* skip preceeding spaces */ + while(strchr(cp,' ')) + ++cp; + /* symbol starts here */ + str = cp; + /* skip char if not a space or : */ + while (*cp && !( strchr(cp,' ') || strchr(cp,':')) ) + cp++; + *cp = '\0'; + return( cp ); +} + +/* + * 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 -Naur linux.2210/drivers/scsi/qla1280.h linux.2210.vw/drivers/scsi/qla1280.h --- linux.2210/drivers/scsi/qla1280.h Wed Dec 31 16:00:00 1969 +++ linux.2210.vw/drivers/scsi/qla1280.h Wed Jul 28 09:05:18 1999 @@ -0,0 +1,1334 @@ +/* + * QLogic ISP1280 Linux Driver + * Host Bus Adapter driver include file. + */ + +/************************************************************************* +** ** +** NOTICE ** +** COPYRIGHT (C) 1999 QLOGIC CORPORATION ** +** ALL RIGHTS RESERVED ** +** ** +** This computer program is CONFIDENTIAL and contains TRADE SECRETS of ** +** QLOGIC CORPORATION. The receipt or possession of this program does ** +** not convey any rights to reproduce or disclose its contents, or to ** +** manufacture, use, or sell anything that it may describe, in whole or ** +** in part, without the specific written consent of QLOGIC CORPORATION. ** +** Any reproduction of this program without the express written consent ** +** of QLOGIC CORPORATION is a violation of the copyright laws and may ** +** subject you to civil liability and criminal prosecution. ** +** ** +*************************************************************************/ + +#ifndef _IO_HBA_QLA1280_H /* wrapper symbol for kernel use */ +#define _IO_HBA_QLA1280_H /* subject to change without notice */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * Enable define statement to ignore Data Underrun Errors, + * remove define statement to enable detection. + */ +/* #define DATA_UNDERRUN_ERROR_DISABLE */ + +/* + * Driver debug definitions. + */ +/* #define QL_DEBUG_LEVEL_1 */ /* Output register accesses to COM2. */ +/* #define QL_DEBUG_LEVEL_2 */ /* Output error msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_3 */ /* Output function trace msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_4 */ /* Output NVRAM trace msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_5 */ /* Output ring trace msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_6 */ /* Output WATCHDOG timer trace to COM2. */ +/* #define QL_DEBUG_LEVEL_7 */ /* Output RISC load trace msgs to COM2. */ + +#define QL_DEBUG_CONSOLE /* Output to console instead of COM2. */ + +#ifndef TRUE +# define TRUE 1 +#endif +#ifndef FALSE +# define FALSE 0 +#endif + + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) +# if defined(__sparc_v9__) || defined(__powerpc__) +# error "PPC and Sparc platforms are only support under 2.1.92 and above" +# endif +#endif + + +/* + * Locking + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) +# include +# include +# define cpuid smp_processor_id() +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +# define DRIVER_LOCK_INIT \ + spin_lock_init(&ha->spin_lock); +# define DRIVER_LOCK \ + if(!ha->cpu_lock_count[cpuid]) { \ + spin_lock_irqsave(&ha->spin_lock, cpu_flags); \ + ha->cpu_lock_count[cpuid]++; \ + } else { \ + ha->cpu_lock_count[cpuid]++; \ + } +# define DRIVER_UNLOCK \ + if(--ha->cpu_lock_count[cpuid] == 0) \ + spin_unlock_irqrestore(&ha->spin_lock, cpu_flags); +# else +# define DRIVER_LOCK_INIT +# define DRIVER_LOCK +# define DRIVER_UNLOCK +# endif +#else +# define cpuid 0 +# define DRIVER_LOCK_INIT +# define DRIVER_LOCK \ + save_flags(cpu_flags); \ + cli(); +# define DRIVER_UNLOCK \ + restore_flags(cpu_flags); +# define le32_to_cpu(x) (x) +# define cpu_to_le32(x) (x) +#endif + +/* + * 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 + +/* + * Common size type definitions + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif + +/* + * 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) + #define QL_DEBUG_ROUTINES +#endif + +/* + * I/O port macros +*/ +#define LINUX_IOPORTS /* Linux in/out routines are define*/ + /* differently from other OSs */ +/* #define MEMORY_MAPPED_IO */ /* Enable memory mapped I/O */ +#undef MEMORY_MAPPED_IO /* Disable memory mapped I/O */ + +#ifdef QL_DEBUG_LEVEL_1 +#define RD_REG_BYTE(addr) qla1280_getbyte((uint8_t *)addr) +#define RD_REG_WORD(addr) qla1280_getword((uint16_t *)addr) +#define RD_REG_DWORD(addr) qla1280_getdword((uint32_t *)addr) +#define WRT_REG_BYTE(addr, data) qla1280_putbyte((uint8_t *)addr, data) +#define WRT_REG_WORD(addr, data) qla1280_putword((uint16_t *)addr, data) +#define WRT_REG_DWORD(addr, data) qla1280_putdword((uint32_t *)addr, data) +#else /* QL_DEBUG_LEVEL_1 */ +#ifdef MEMORY_MAPPED_IO + #define RD_REG_BYTE(addr) (*((volatile uint8_t *)addr)) + #define RD_REG_WORD(addr) (*((volatile uint16_t *)addr)) + #define RD_REG_DWORD(addr) (*((volatile uint32_t *)addr)) + #define WRT_REG_BYTE(addr, data) (*((volatile uint8_t *)addr) = data) + #define WRT_REG_WORD(addr, data) (*((volatile uint16_t *)addr) = data) + #define WRT_REG_DWORD(addr, data) (*((volatile uint32_t *)addr) = data) +#else /* MEMORY_MAPPED_IO */ +#define RD_REG_BYTE(addr) (inb((int)addr)) +#define RD_REG_WORD(addr) (inw((int)addr)) +#define RD_REG_DWORD(addr) (inl((int)addr)) +#ifdef LINUX_IOPORTS +/* Parameters are reversed in Linux */ +#define WRT_REG_BYTE(addr, data) (outb(data,(int)addr)) +#define WRT_REG_WORD(addr, data) (outw(data,(int)addr)) +#define WRT_REG_DWORD(addr, data) (outl(data,(int)addr)) +#else +#define WRT_REG_BYTE(addr, data) (outb((int)addr, data)) +#define WRT_REG_WORD(addr, data) (outw((int)addr, data)) +#define WRT_REG_DWORD(addr, data) (outl((int)addr, data)) +#endif +#endif /* MEMORY_MAPPED_IO */ +#endif /* QL_DEBUG_LEVEL_1 */ + +/* + * Host adapter default definitions. + */ +#define MAX_BUSES 2 /* 2 */ +#define MAX_B_BITS 1 + +#define MAX_TARGETS 16 /* 16 */ +#define MAX_T_BITS 4 /* 4 */ + +#define MAX_LUNS 8 /* 32 */ +#define MAX_L_BITS 3 /* 5 */ + +/* + * Watchdog time quantum + */ +#define QLA1280_WDG_TIME_QUANTUM 5 /* In seconds */ + +/* Command retry count (0-65535) */ +#define COMMAND_RETRY_COUNT 255 + +/* Maximum outstanding commands in ISP queues (1-65535) */ +#define MAX_OUTSTANDING_COMMANDS 512 + +/* ISP request and response entry counts (37-65535) */ +#define REQUEST_ENTRY_CNT 256 /* Number of request entries. */ +#define RESPONSE_ENTRY_CNT 16 /* Number of response entries. */ + +/* Maximum equipage per controller */ +#define MAX_EQ (MAX_BUSES * MAX_TARGETS * MAX_LUNS) + +/* Number of segments 1 - 65535 */ +#define SG_SEGMENTS 32 /* Cmd entry + 6 continuations */ + + +typedef struct timer_list timer_t; /* timer */ + +/* + * SCSI Request Block structure + */ +typedef struct srb +{ + Scsi_Cmnd *cmd; /* (4) SCSI command block */ + struct srb *s_next; /* (4) Next block on LU queue */ + struct srb *s_prev; /* (4) Previous block on LU queue */ + uint8_t flags; /* (1) Status flags. */ + uint8_t dir; /* direction of transfer */ + uint8_t unused[2]; + u_long r_start; /* jiffies at start of request */ + u_long u_start; /* jiffies when sent to F/W */ +}srb_t; + +/* + * SRB flag definitions + */ +#define SRB_TIMEOUT BIT_0 /* Command timed out */ +#define SRB_SENT BIT_1 /* Command sent to ISP */ +#define SRB_ABORT_PENDING BIT_2 /* Command abort sent to device */ +#define SRB_ABORTED BIT_3 /* Command aborted command already */ + + +/* + * Logical Unit Queue structure + */ +typedef struct scsi_lu +{ + srb_t *q_first; /* First block on LU queue */ + srb_t *q_last; /* Last block on LU queue */ + uint8_t q_flag; /* LU queue state flags */ + uint8_t q_sense[16]; /* sense data */ + u_long io_cnt; /* total xfer count */ + u_long resp_time; /* total response time (start - finish) */ + u_long act_time; /* total actived time (minus queuing time) */ + u_long w_cnt; /* total writes */ + u_long r_cnt; /* total reads */ + uint16_t q_outcnt; /* Pending jobs for this LU */ +#if QL1280_TARGET_MODE_SUPPORT + void (*q_func)(); /* Target driver event handler */ + int32_t q_param; /* Target driver event param */ + uint8_t q_lock; /* Device Queue Lock */ +#endif +}scsi_lu_t; + +/* + * Logical Unit flags + */ +#define QLA1280_QBUSY BIT_0 +#define QLA1280_QWAIT BIT_1 +#define QLA1280_QSUSP BIT_2 +#define QLA1280_QSENSE BIT_3 /* Sense data cache valid */ +#define QLA1280_QRESET BIT_4 +#define QLA1280_QHBA BIT_5 +#define QLA1280_BSUSP BIT_6 /* controller is suspended */ +#define QLA1280_BREM BIT_7 /* controller is removed */ + +/* + * ISP PCI Configuration Register Set + */ +typedef volatile struct +{ + uint16_t vendor_id; /* 0x0 */ + uint16_t device_id; /* 0x2 */ + uint16_t command; /* 0x4 */ + uint16_t status; /* 0x6 */ + uint8_t revision_id; /* 0x8 */ + uint8_t programming_interface; /* 0x9 */ + uint8_t sub_class; /* 0xa */ + uint8_t base_class; /* 0xb */ + uint8_t cache_line; /* 0xc */ + uint8_t latency_timer; /* 0xd */ + uint8_t header_type; /* 0xe */ + uint8_t bist; /* 0xf */ + uint32_t base_port; /* 0x10 */ + uint32_t mem_base_addr; /* 0x14 */ + uint32_t base_addr[4]; /* 0x18-0x24 */ + uint32_t reserved_1[2]; /* 0x28-0x2c */ + uint16_t expansion_rom; /* 0x30 */ + uint32_t reserved_2[2]; /* 0x34-0x38 */ + uint8_t interrupt_line; /* 0x3c */ + uint8_t interrupt_pin; /* 0x3d */ + uint8_t min_grant; /* 0x3e */ + uint8_t max_latency; /* 0x3f */ +}config_reg_t; + +/* + * ISP I/O Register Set structure definitions. + */ +typedef volatile struct +{ + uint16_t id_l; /* ID low */ + uint16_t id_h; /* ID high */ + uint16_t cfg_0; /* Configuration 0 */ + uint16_t cfg_1; /* Configuration 1 */ + uint16_t ictrl; /* Interface control */ + #define ISP_RESET BIT_0 /* ISP soft reset */ + #define ISP_EN_INT BIT_1 /* ISP enable interrupts. */ + #define ISP_EN_RISC BIT_2 /* ISP enable RISC interrupts. */ + uint16_t istatus; /* Interface status */ + #define PCI_64BIT_SLOT BIT_14 /* PCI 64-bit slot indicator. */ + #define RISC_INT BIT_2 /* RISC interrupt */ + #define PCI_INT BIT_1 /* PCI interrupt */ + uint16_t semaphore; /* Semaphore */ + uint16_t nvram; /* NVRAM register. */ + #define NV_DESELECT 0 + #define NV_CLOCK BIT_0 + #define NV_SELECT BIT_1 + #define NV_DATA_OUT BIT_2 + #define NV_DATA_IN BIT_3 + uint16_t flash_data; /* Flash BIOS data */ + uint16_t flash_address; /* Flash BIOS address */ + + uint16_t unused_1[0x2e]; /* 0x14-0x6f Gap */ + + uint16_t mailbox0; /* Mailbox 0 */ + uint16_t mailbox1; /* Mailbox 1 */ + uint16_t mailbox2; /* Mailbox 2 */ + uint16_t mailbox3; /* Mailbox 3 */ + uint16_t mailbox4; /* Mailbox 4 */ + uint16_t mailbox5; /* Mailbox 5 */ + uint16_t mailbox6; /* Mailbox 6 */ + uint16_t mailbox7; /* Mailbox 7 */ + + uint16_t unused_2[0x20]; /* 0x80-0xbf Gap */ + + uint16_t host_cmd; /* Host command and control */ + #define HOST_INT BIT_7 /* host interrupt bit */ + #define BIOS_ENABLE BIT_0 + + uint16_t unused_6[0x5]; /* 0xc2-0xcb Gap */ + + uint16_t gpio_data; + uint16_t gpio_enable; + + uint16_t unused_7[0x11]; /* d0-f0 */ + uint16_t scsiControlPins; /* f2 */ + +}device_reg_t; + +#define MAILBOX_REGISTER_COUNT 8 + +/* + * 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 +#define PROD_ID_4 0x1 + +/* + * ISP host command and control register command definitions + */ +#define HC_RESET_RISC 0x1000 /* Reset RISC */ +#define HC_PAUSE_RISC 0x2000 /* Pause RISC */ +#define HC_RELEASE_RISC 0x3000 /* Release RISC from reset. */ +#define HC_SET_HOST_INT 0x5000 /* Set host interrupt */ +#define HC_CLR_HOST_INT 0x6000 /* Clear HOST interrupt */ +#define HC_CLR_RISC_INT 0x7000 /* Clear RISC interrupt */ +#define HC_DISABLE_BIOS 0x9000 /* Disable BIOS. */ + +/* + * ISP mailbox Self-Test status codes + */ +#define MBS_FRM_ALIVE 0 /* Firmware Alive. */ +#define MBS_CHKSUM_ERR 1 /* Checksum Error. */ +#define MBS_SHADOW_LD_ERR 2 /* Shadow Load Error. */ +#define MBS_BUSY 4 /* Busy. */ + +/* + * ISP mailbox command complete status codes + */ +#define MBS_CMD_CMP 0x4000 /* Command Complete. */ +#define MBS_INV_CMD 0x4001 /* Invalid Command. */ +#define MBS_HOST_INF_ERR 0x4002 /* Host Interface Error. */ +#define MBS_TEST_FAILED 0x4003 /* Test Failed. */ +#define MBS_CMD_ERR 0x4005 /* Command Error. */ +#define MBS_CMD_PARAM_ERR 0x4006 /* Command Parameter Error. */ + +/* + * ISP mailbox asynchronous event status codes + */ +#define MBA_ASYNC_EVENT 0x8000 /* Asynchronous event. */ +#define MBA_BUS_RESET 0x8001 /* SCSI Bus Reset. */ +#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_TIMEOUT_RESET 0x8006 /* Execution Timeout Reset. */ +#define MBA_DEVICE_RESET 0x8007 /* Bus Device Reset. */ +#define MBA_BUS_MODE_CHANGE 0x800E /* SCSI bus mode transition. */ +#define MBA_SCSI_COMPLETION 0x8020 /* Completion response. */ + +/* + * ISP mailbox commands + */ +#define MBC_NOP 0 /* No Operation. */ +#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_ABOUT_FIRMWARE 8 /* Get firmware revision. */ +#define MBC_INIT_REQUEST_QUEUE 0x10 /* Initialize request queue. */ +#define MBC_INIT_RESPONSE_QUEUE 0x11 /* Initialize response queue. */ +#define MBC_EXECUTE_IOCB 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_BUS_RESET 0x18 /* SCSI bus reset. */ +#define MBC_GET_RETRY_COUNT 0x22 /* Get retry count and delay. */ +#define MBC_GET_TARGET_PARAMETERS 0x28 /* Get target parameters. */ +#define MBC_SET_INITIATOR_ID 0x30 /* Set initiator SCSI ID. */ +#define MBC_SET_SELECTION_TIMEOUT 0x31 /* Set selection timeout. */ +#define MBC_SET_RETRY_COUNT 0x32 /* Set retry count and delay. */ +#define MBC_SET_TAG_AGE_LIMIT 0x33 /* Set tag age limit. */ +#define MBC_SET_CLOCK_RATE 0x34 /* Set clock rate. */ +#define MBC_SET_ACTIVE_NEGATION 0x35 /* Set active negation state. */ +#define MBC_SET_ASYNC_DATA_SETUP 0x36 /* Set async data setup time. */ +#define MBC_SET_PCI_CONTROL 0x37 /* Set BUS control parameters. */ +#define MBC_SET_TARGET_PARAMETERS 0x38 /* Set target parameters. */ +#define MBC_SET_DEVICE_QUEUE 0x39 /* Set device queue parameters */ +#define MBC_SET_SYSTEM_PARAMETER 0x45 /* Set system parameter word. */ +#define MBC_SET_FIRMWARE_FEATURES 0x4A /* Set firmware feature word. */ +#define MBC_INIT_REQUEST_QUEUE_A64 0x52 /* Initialize request queue A64 */ +#define MBC_INIT_RESPONSE_QUEUE_A64 0x53 /* Initialize response q A64. */ +#define MBC_ENABLE_TARGET_MODE 0x55 /* Enable target mode. */ + +/* + * ISP Get/Set Target Parameters mailbox command control flags. + */ +#define TP_RENEGOTIATE BIT_8 /* Renegotiate on error. */ +#define TP_STOP_QUEUE BIT_9 /* Stop que on check condition */ +#define TP_AUTO_REQUEST_SENSE BIT_10 /* Automatic request sense. */ +#define TP_TAGGED_QUEUE BIT_11 /* Tagged queuing. */ +#define TP_SYNC BIT_12 /* Synchronous data transfers. */ +#define TP_WIDE BIT_13 /* Wide data transfers. */ +#define TP_PARITY BIT_14 /* Parity checking. */ +#define TP_DISCONNECT BIT_15 /* Disconnect privilege. */ + +/* + * 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 ISP1280 NVRAM structure definition. + */ +typedef struct +{ + uint8_t id[4]; /* 0, 1, 2, 3 */ + uint8_t version; /* 4 */ + + struct + { + uint8_t bios_configuration_mode :2; + uint8_t bios_disable :1; + uint8_t selectable_scsi_boot_enable :1; + uint8_t cd_rom_boot_enable :1; + uint8_t disable_loading_risc_code :1; + uint8_t enable_64bit_addressing :1; + uint8_t unused_7 :1; + }cntr_flags_1; /* 5 */ + + struct + { + uint8_t boot_lun_number :5; + uint8_t scsi_bus_number :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t boot_target_number :4; + uint8_t unused_12 :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }cntr_flags_2; /* 6, 7 */ + + uint16_t unused_8; /* 8, 9 */ + uint16_t unused_10; /* 10, 11 */ + uint16_t unused_12; /* 12, 13 */ + uint16_t unused_14; /* 14, 15 */ + + union + { + uint8_t c; + struct + { + uint8_t reserved :2; + uint8_t burst_enable :1; + uint8_t reserved_1 :1; + uint8_t fifo_threshold :4; + }f; + }isp_config; /* 16 */ + + /* Termination + * 0 = Disable, 1 = high only, 3 = Auto term + */ + union + { + uint8_t c; + struct + { + uint8_t scsi_bus_1_control :2; + uint8_t scsi_bus_0_control :2; + uint8_t unused_0 :1; + uint8_t unused_1 :1; + uint8_t unused_2 :1; + uint8_t auto_term_support :1; + }f; + }termination; /* 17 */ + + uint16_t isp_parameter; /* 18, 19 */ + + union + { + uint16_t w; + struct + { + uint8_t enable_fast_posting :1; + uint8_t report_lvd_bus_transition :1; + uint8_t unused_2 :1; + uint8_t unused_3 :1; + uint8_t unused_4 :1; + uint8_t unused_5 :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t unused_8 :1; + uint8_t unused_9 :1; + uint8_t unused_10 :1; + uint8_t unused_11 :1; + uint8_t unused_12 :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }f; + }firmware_feature; /* 20, 21 */ + + uint16_t unused_22; /* 22, 23 */ + + struct + { + struct + { + uint8_t initiator_id :4; + uint8_t scsi_reset_disable :1; + uint8_t scsi_bus_size :1; + uint8_t scsi_bus_type :1; + uint8_t unused_7 :1; + }config_1; /* 24 */ + + uint8_t bus_reset_delay; /* 25 */ + uint8_t retry_count; /* 26 */ + uint8_t retry_delay; /* 27 */ + + struct + { + uint8_t async_data_setup_time :4; + uint8_t req_ack_active_negation :1; + uint8_t data_line_active_negation :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + }config_2; /* 28 */ + + uint8_t unused_29; /* 29 */ + + uint16_t selection_timeout; /* 30, 31 */ + uint16_t max_queue_depth; /* 32, 33 */ + + uint16_t unused_34; /* 34, 35 */ + uint16_t unused_36; /* 36, 37 */ + uint16_t unused_38; /* 38, 39 */ + + struct + { + union + { + uint8_t c; + struct + { + uint8_t renegotiate_on_error :1; + uint8_t stop_queue_on_check :1; + uint8_t auto_request_sense :1; + uint8_t tag_queuing :1; + uint8_t sync_data_transfers :1; + uint8_t wide_data_transfers :1; + uint8_t parity_checking :1; + uint8_t disconnect_allowed :1; + }f; + }parameter; /* 40 */ + + uint8_t execution_throttle; /* 41 */ + uint8_t sync_period; /* 42 */ + + struct + { + uint8_t sync_offset :4; + uint8_t device_enable :1; + uint8_t lun_disable :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + }flags; /* 43 */ + + uint16_t unused_44; /* 44, 45 */ + }target[MAX_TARGETS]; + }bus[MAX_BUSES]; + + uint16_t unused_248; /* 248, 249 */ + + uint16_t subsystem_id[2]; /* 250, 251, 252, 253 */ + + uint8_t unused_254; /* 254 */ + + uint8_t chksum; /* 255 */ +}nvram_t; + +/* + * ISP queue - command entry structure definition. + */ +#define MAX_CMDSZ 12 /* SCSI maximum CDB size. */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define COMMAND_TYPE 1 /* Command entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t lun; /* SCSI LUN */ + uint8_t target; /* SCSI ID */ + uint16_t cdb_len; /* SCSI command length. */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + 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. */ +}cmd_entry_t; + +/* + * ISP queue - continuation entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_TYPE 2 /* Continuation entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved; /* 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 - status entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define STATUS_TYPE 3 /* Status entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + #define RF_CONT BIT_0 /* Continuation. */ + #define RF_FULL BIT_1 /* Full */ + #define RF_BAD_HEADER BIT_2 /* Bad header. */ + #define RF_BAD_PAYLOAD BIT_3 /* Bad payload. */ + uint32_t handle; /* System handle. */ + uint16_t scsi_status; /* SCSI status. */ + uint16_t comp_status; /* Completion status. */ + uint16_t state_flags; /* State flags. */ + #define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */ + #define SF_GOT_SENSE BIT_13 /* Got Sense */ + #define SF_GOT_STATUS BIT_12 /* Got Status */ + #define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */ + #define SF_SENT_CDB BIT_10 /* Send CDB */ + #define SF_GOT_TARGET BIT_9 /* */ + #define SF_GOT_BUS BIT_8 /* */ + uint16_t status_flags; /* Status flags. */ + uint16_t time; /* Time. */ + uint16_t req_sense_length; /* Request sense data length. */ + uint32_t residual_length; /* Residual transfer length. */ + uint16_t reserved[4]; + uint8_t req_sense_data[32]; /* Request sense data. */ +}sts_entry_t, response_t; + +/* + * ISP queue - marker entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define MARKER_TYPE 4 /* Marker entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved; + uint8_t lun; /* SCSI LUN */ + uint8_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 */ + uint8_t reserved_1[53]; +}mrk_entry_t; + +/* + * ISP queue - extended command entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define EXTENDED_CMD_TYPE 5 /* Extended command entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t lun; /* SCSI LUN */ + uint8_t target; /* SCSI ID */ + uint16_t cdb_len; /* SCSI command length. */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[88]; /* SCSI command words. */ +}ecmd_entry_t; + +/* + * ISP queue - 64-Bit addressing, command entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define COMMAND_A64_TYPE 9 /* Command A64 entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t lun; /* SCSI LUN */ + uint8_t target; /* SCSI ID */ + uint16_t cdb_len; /* SCSI command length. */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + uint32_t reserved_1[2]; /* unused */ + 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 - 64-Bit addressing, continuation entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_A64_TYPE 0xA /* Continuation A64 entry. */ + 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 - enable LUN entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define ENABLE_LUN_TYPE 0xB /* Enable LUN entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status not used. */ + uint32_t reserved_2; + uint16_t lun; /* Bit 15 is bus number. */ + uint16_t reserved_4; + uint32_t option_flags; + uint8_t status; + uint8_t reserved_5; + uint8_t command_count; /* Number of ATIOs allocated. */ + uint8_t immed_notify_count; /* Number of Immediate Notify */ + /* entries allocated. */ + uint8_t group_6_length; /* SCSI CDB length for group 6 */ + /* commands (2-26). */ + uint8_t group_7_length; /* SCSI CDB length for group 7 */ + /* commands (2-26). */ + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t reserved_6[20]; +}elun_entry_t; + +/* + * ISP queue - modify LUN entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define MODIFY_LUN_TYPE 0xC /* Modify LUN entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t reserved_3; + uint8_t operators; + uint8_t reserved_4; + uint32_t option_flags; + uint8_t status; + uint8_t reserved_5; + uint8_t command_count; /* Number of ATIOs allocated. */ + uint8_t immed_notify_count; /* Number of Immediate Notify */ + /* entries allocated. */ + uint16_t reserved_6; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t reserved_7[20]; +}modify_lun_entry_t; + +/* + * ISP queue - immediate notify entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define IMMED_NOTIFY_TYPE 0xD /* Immediate notify entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t reserved_4; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + /* entries allocated. */ + uint16_t seq_id; + uint8_t scsi_msg[8]; /* SCSI message not handled by ISP */ + uint16_t reserved_5[8]; + uint8_t sense_data[18]; +}notify_entry_t; + +/* + * ISP queue - notify acknowledge entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define NOTIFY_ACK_TYPE 0xE /* Notify acknowledge entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t event; + uint16_t seq_id; + uint16_t reserved_4[22]; +}nack_entry_t; + +/* + * ISP queue - Accept Target I/O (ATIO) entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define ACCEPT_TGT_IO_TYPE 6 /* Accept target I/O entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; + uint8_t initiator_id; + uint8_t cdb_len; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint8_t cdb[26]; + uint8_t sense_data[18]; +}atio_entry_t; + +/* + * ISP queue - Continue Target I/O (CTIO) entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_TGT_IO_TYPE 7 /* CTIO entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment 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. */ + uint32_t dseg_3_address; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ +}ctio_entry_t; + +/* + * ISP queue - CTIO returned entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_RET_TYPE 7 /* CTIO return entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment 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. */ + uint16_t dseg_1_length; /* Data segment 1 length. */ + uint8_t sense_data[18]; +}ctio_ret_entry_t; + +/* + * ISP queue - CTIO A64 entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_A64_TYPE 0xF /* CTIO A64 entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t reserved_4[2]; + 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. */ +}ctio_a64_entry_t; + +/* + * ISP queue - CTIO returned entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_A64_RET_TYPE 0xF /* CTIO A64 returned entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint16_t reserved_4[7]; + uint8_t sense_data[18]; +}ctio_a64_ret_entry_t; + +/* + * ISP request and response queue entry sizes + */ +#define RESPONSE_ENTRY_SIZE (sizeof(response_t)) +#define REQUEST_ENTRY_SIZE (sizeof(request_t)) + +/* + * ISP status entry - completion status definitions. + */ +#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_COMMAND_OVERRUN 0x8 /* Command Overrun. */ +#define CS_STATUS_OVERRUN 0x9 /* Status Overrun. */ +#define CS_BAD_MSG 0xA /* Bad msg after status phase. */ +#define CS_NO_MSG_OUT 0xB /* No msg out after selection. */ +#define CS_EXTENDED_ID 0xC /* Extended ID failed. */ +#define CS_IDE_MSG 0xD /* Target rejected IDE msg. */ +#define CS_ABORT_MSG 0xE /* Target rejected abort msg. */ +#define CS_REJECT_MSG 0xF /* Target rejected reject msg. */ +#define CS_NOP_MSG 0x10 /* Target rejected NOP msg. */ +#define CS_PARITY_MSG 0x11 /* Target rejected parity msg. */ +#define CS_DEV_RESET_MSG 0x12 /* Target rejected dev rst msg. */ +#define CS_ID_MSG 0x13 /* Target rejected ID msg. */ +#define CS_FREE 0x14 /* Unexpected bus free. */ +#define CS_DATA_UNDERRUN 0x15 /* Data Underrun. */ +#define CS_TRANACTION_1 0x18 /* Transaction error 1 */ +#define CS_TRANACTION_2 0x19 /* Transaction error 2 */ +#define CS_TRANACTION_3 0x1a /* Transaction error 3 */ +#define CS_INV_ENTRY_TYPE 0x1b /* Invalid entry type */ +#define CS_DEV_QUEUE_FULL 0x1c /* Device queue full */ +#define CS_PHASED_SKIPPED 0x1d /* SCSI phase skipped */ +#define CS_ARS_FAILED 0x1e /* ARS failed */ +#define CS_LVD_BUS_ERROR 0x21 /* LVD bus error */ +#define CS_BAD_PAYLOAD 0x80 /* Driver defined */ +#define CS_UNKNOWN 0x81 /* Driver defined */ +#define CS_RETRY 0x82 /* Driver defined */ + +/* + * ISP status entry - SCSI status byte bit definitions. + */ +#define SS_CHECK_CONDITION BIT_1 +#define SS_CONDITION_MET BIT_2 +#define SS_BUSY_CONDITION BIT_3 +#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3) + +/* + * ISP target entries - Option flags bit definitions. + */ +#define OF_ENABLE_TAG BIT_1 /* Tagged queue action enable */ +#define OF_DATA_IN BIT_6 /* Data in to initiator */ + /* (data from target to initiator) */ +#define OF_DATA_OUT BIT_7 /* Data out from initiator */ + /* (data from initiator to target) */ +#define OF_NO_DATA (BIT_7 | BIT_6) +#define OF_DISC_DISABLED BIT_15 /* Disconnects disabled */ +#define OF_DISABLE_SDP BIT_24 /* Disable sending save data ptr */ +#define OF_SEND_RDP BIT_26 /* Send restore data pointers msg */ +#define OF_FORCE_DISC BIT_30 /* Disconnects mandatory */ +#define OF_SSTS BIT_31 /* Send SCSI status */ + +#if QL1280_TARGET_MODE_SUPPORT +/* + * Target Read/Write buffer structure. + */ +#define TARGET_DATA_OFFSET 4 +#define TARGET_DATA_SIZE 0x2000 /* 8K */ +#define TARGET_INQ_OFFSET (TARGET_DATA_OFFSET + TARGET_DATA_SIZE) +#define TARGET_SENSE_SIZE 18 +#define TARGET_BUF_SIZE 36 + +typedef struct +{ + uint8_t hdr[4]; + uint8_t data[TARGET_DATA_SIZE]; + struct ident inq; +}tgt_t; +#endif + +/* + * BUS parameters/settings structure + */ +typedef struct +{ + uint8_t id; /* Host adapter SCSI id */ + uint8_t bus_reset_delay; /* SCSI bus reset delay. */ + uint8_t failed_reset_count; /* number of time reset failed */ + uint8_t unused; + uint16_t device_enables; /* Device enable bits. */ + uint16_t lun_disables; /* LUN disable bits. */ + uint16_t qtag_enables; /* Tag queue enables. */ + uint16_t hiwat; /* High water mark per device. */ + uint8_t reset_marker :1; + uint8_t disable_scsi_reset :1; + uint8_t scsi_bus_dead :1; /* SCSI Bus is Dead, when 5 back to back resets failed */ + +}bus_param_t; + +/* + * Linux Host Adapter structure + */ +typedef struct scsi_qla_host +{ + /* Linux adapter configuration data */ + struct Scsi_Host *host; /* pointer to host data */ + struct scsi_qla_host *next; + device_reg_t *iobase; /* Base Memory-mapped I/O address */ + uint8_t pci_bus; + uint8_t pci_device_fn; + uint8_t devnum; + volatile unsigned char *mmpbase; /* memory mapped address */ + unsigned long host_no; + unsigned long instance; + uint8_t revision; + uint8_t ports; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) + spinlock_t spin_lock; +#endif + volatile unsigned char cpu_lock_count[NR_CPUS]; + unsigned long actthreads; + unsigned long qthreads; + unsigned long isr_count; /* Interrupt count */ + unsigned long spurious_int; + + /* Outstandings ISP commands. */ + srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS]; + + /* BUS configuration data */ + bus_param_t bus_settings[MAX_BUSES]; + + /* Device LUN queues. */ + scsi_lu_t *dev[MAX_EQ]; /* Logical unit queues */ + +#ifdef UNUSED + /* Interrupt lock, and data */ + uint8_t intr_lock; /* Lock for interrupt locking */ +#endif + + /* bottom half run queue */ + struct tq_struct run_qla_bh; + + /* Received ISP mailbox data. */ + volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; + +#ifdef UNUSED + /* ISP ring lock, rings, and indexes */ + uint8_t ring_lock; /* ISP ring lock */ + struct timer_list dev_timer[MAX_TARGETS]; +#endif + + request_t req[REQUEST_ENTRY_CNT+1]; + response_t res[RESPONSE_ENTRY_CNT+1]; + uint32_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. */ + + uint32_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. */ + +#if QL1280_TARGET_MODE_SUPPORT + /* Target buffer and sense data. */ + uint32_t tbuf_dma; /* Physical address. */ + tgt_t *tbuf; + uint32_t tsense_dma; /* Physical address. */ + uint8_t *tsense; +#endif + +#if WATCHDOGTIMER + /* Watchdog queue, lock and total timer */ + uint8_t watchdog_q_lock; /* Lock for watchdog queue */ + srb_t *wdg_q_first; /* First job on watchdog queue */ + srb_t *wdg_q_last; /* Last job on watchdog queue */ + uint32_t total_timeout; /* Total timeout (quantum count) */ + uint32_t watchdogactive; +#endif + + srb_t *done_q_first; /* First job on done queue */ + srb_t *done_q_last; /* Last job on done queue */ + + volatile struct + { + uint32_t watchdog_enabled :1; /* 0 */ + uint32_t mbox_int :1; /* 1 */ + uint32_t mbox_busy :1; /* 2 */ + uint32_t online :1; /* 3 */ + uint32_t reset_marker :1; /* 4 */ + uint32_t isp_abort_needed :1; /* 5 */ + uint32_t pci_64bit_slot :1; /* 6 */ + uint32_t disable_host_adapter :1; /* 7 */ + uint32_t reset_active :1; /* 8 */ + uint32_t abort_isp_active :1; /* 9 */ + uint32_t disable_risc_code_load :1; /* 10 */ + uint32_t enable_64bit_addressing :1; /* 11 */ +#define QLA1280_IN_ISR_BIT 12 + uint32_t in_isr :1; /* 12 */ + uint32_t in_abort :1; /* 13 */ + uint32_t in_reset :1; /* 14 */ + uint32_t dpc :1; /* 15 */ + uint32_t dpc_sched :1; /* 16 */ + }flags; + +}scsi_qla_host_t; + +/* + * Macros to help code, maintain, etc. + */ +#define SUBDEV(b, t, l) ( (b << (MAX_T_BITS + MAX_L_BITS)) | (t << MAX_L_BITS) | l) +#define LU_Q(ha, b, t, l) (ha->dev[SUBDEV(b, t, l)]) + +/* + * Locking Macro Definitions + * + * LOCK/UNLOCK definitions are lock/unlock primitives for multi-processor + * or spl/splx for uniprocessor. + */ +#define QLA1280_HIER HBA_HIER_BASE /* Locking hierarchy base for hba */ + +#define QLA1280_WATCHDOG_Q_LOCK(ha, p) +#define QLA1280_WATCHDOG_Q_UNLOCK(ha, p) + +#define QLA1280_SCSILU_LOCK(q) +#define QLA1280_SCSILU_UNLOCK(q) + +#define QLA1280_INTR_LOCK(ha) +#define QLA1280_INTR_UNLOCK(ha) + +#define QLA1280_RING_LOCK(ha) +#define QLA1280_RING_UNLOCK(ha) + + +#if defined(__cplusplus) +} +#endif + +#endif /* _IO_HBA_QLA1280_H */ diff -Naur linux.2210/drivers/scsi/qla1280host.h linux.2210.vw/drivers/scsi/qla1280host.h --- linux.2210/drivers/scsi/qla1280host.h Wed Dec 31 16:00:00 1969 +++ linux.2210.vw/drivers/scsi/qla1280host.h Wed Jul 28 08:56:41 1999 @@ -0,0 +1,46 @@ +/* + * Linux - SCSI Driver Interface Function Prototypes. + */ +int qla1280_proc_info ( char *, char **, off_t, int, int, int); +const char * qla1280_info(struct Scsi_Host *host); +int qla1280_detect(Scsi_Host_Template *); +int qla1280_release(struct Scsi_Host *); +const char * qla1280_info(struct Scsi_Host *); +int qla1280_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int qla1280_abort(Scsi_Cmnd *); +int qla1280_reset(Scsi_Cmnd *, unsigned int); +int qla1280_biosparam(Disk *, kdev_t, int[]); /* x86 only XXX BH */ +void qla1280_intr_handler(int, void *, struct pt_regs *); +void qla1280_setup(char *s, int *dummy); + +#define QLA1280 { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: qla1280_proc_info, \ + name: "Qlogic ISP 1280\1080", \ + detect: qla1280_detect, \ + release: qla1280_release, \ + info: qla1280_info, \ + ioctl: NULL, \ + command: NULL, \ + queuecommand: qla1280_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: qla1280_abort, \ + reset: qla1280_reset, \ + slave_attach: NULL, \ + bios_param: qla1280_biosparam, \ + can_queue: 255, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: SG_ALL, /* max scatter-gather cmds */\ + cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0, \ + emulated: 0 \ +} diff -Naur linux.2210/drivers/sound/Config.in linux.2210.vw/drivers/sound/Config.in --- linux.2210/drivers/sound/Config.in Sun Mar 7 15:22:06 1999 +++ linux.2210.vw/drivers/sound/Config.in Wed Jul 28 08:56:41 1999 @@ -9,6 +9,9 @@ # Prompt user for primary drivers. +if [ "$CONFIG_VISWS" = "y" ]; then + dep_tristate 'SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND +fi dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND if [ "$CONFIG_SOUND_ES1370" = "y" ]; then bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT diff -Naur linux.2210/drivers/sound/Makefile linux.2210.vw/drivers/sound/Makefile --- linux.2210/drivers/sound/Makefile Thu Jan 14 22:59:47 1999 +++ linux.2210.vw/drivers/sound/Makefile Wed Jul 28 08:56:41 1999 @@ -72,6 +72,7 @@ obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o +obj-$(CONFIG_SOUND_VWSND) += vwsnd.o obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o diff -Naur linux.2210/drivers/sound/sound_core.c linux.2210.vw/drivers/sound/sound_core.c --- linux.2210/drivers/sound/sound_core.c Mon Jun 7 11:06:06 1999 +++ linux.2210.vw/drivers/sound/sound_core.c Wed Jul 28 08:56:41 1999 @@ -395,6 +395,9 @@ /* * Now init non OSS drivers */ +#ifdef CONFIG_SOUND_VWSND + init_vwsnd(); +#endif #ifdef CONFIG_SOUND_SONICVIBES init_sonicvibes(); #endif diff -Naur linux.2210/drivers/sound/vwsnd.c linux.2210.vw/drivers/sound/vwsnd.c --- linux.2210/drivers/sound/vwsnd.c Wed Dec 31 16:00:00 1969 +++ linux.2210.vw/drivers/sound/vwsnd.c Wed Jul 28 08:56:42 1999 @@ -0,0 +1,3306 @@ +/* + * Sound driver for Silicon Graphics 320 and 540 Visual Workstations' + * onboard audio. See notes in ../../Documentation/sound/vwsnd . + * + * Copyright 1999 Silicon Graphics, Inc. All rights reserved. + */ + +#undef VWSND_DEBUG /* define for debugging */ + +/* + * XXX to do - + * + * Trigger. + * Too many frags -- how to reduce frags, extra copying? + * Sync. + * What do SYNC, RESET, POST do on input? + * Rename swbuf, hwbuf, u&i, hwptr&swptr to something rational. + * Bug - if select() called before read(), pcm_setup() not called. + */ + +/* + * XXX things to test - + * + * Will readv/writev work? Write a test. + * + * insmod/rmmod 100 million times. + * + * Run I/O until int ptrs wrap around (roughly 6.2 hours @ DAT + * rate). + * + * Concurrent threads banging on mixer simultaneously, both UP + * and MP. Especially, watch for thread A changing OUTSRC while + * thread B changes gain. + * + * What happens if a client opens /dev/audio then forks? + * Do two procs have /dev/audio open? Test. + * + * Pump audio through the CD, MIC and line inputs and verify that + * they mix/mute into the output. + * + * Apps: + * sndconfig + * amp + * mpg123 + * x11amp + * mxv + * kmedia + * esound + * need more input apps + * + * Run tests while bombarding with signals. setitimer(2) will do it... + */ + +/* + * This driver is organized in nine sections. + * The nine sections are: + * + * debug stuff + * low level lithium access + * high level lithium access + * AD1843 access + * PCM I/O + * audio driver + * mixer driver + * probe/attach/unload + * initialization and loadable kernel module interface + * + * That is roughly the order of increasing abstraction, so forward + * dependencies are minimal. + */ + +/* + * Locking Notes + * + * INC_USE_COUNT and DEC_USE_COUNT keep track of the number of + * open descriptors to this driver. When the driver is compiled + * as a module, they call MOD_{INC,DEC}_USE_COUNT; otherwise they + * bump vwsnd_use_count. The global device list, vwsnd_dev_list, + * is immutable when the IN_USE is true. + * + * devc->open_lock is a semaphore that is used to enforce the + * single reader/single writer rule for /dev/audio. The rule is + * that each device may have at most one reader and one writer. + * Open will block until the previous client has closed the + * device, unless O_NONBLOCK is specified. + * + * The semaphore devc->io_sema serializes PCM I/O syscalls. This + * is unnecessary in Linux 2.2, because the kernel lock + * serializes read, write, and ioctl globally, but it's there, + * ready for the brave, new post-kernel-lock world. + * + * Locking between interrupt and baselevel is handled by the + * "lock" spinlock in vwsnd_port (one lock each for read and + * write). Each half holds the lock just long enough to see what + * area it owns and update its pointers. See pcm_output() and + * pcm_input() for most of the gory stuff. + * + * devc->mix_sema serializes all mixer ioctls. This is also + * redundant because of the kernel lock. + * + * The lowest level lock is lith->lithium_lock. It is a + * spinlock which is held during the two-register tango of + * reading/writing an AD1843 register. See + * li_{read,write}_ad1843_reg(). + */ + +/* + * Sample Format Notes + * + * Lithium's DMA engine has two formats: 16-bit 2's complement + * and 8-bit unsigned . 16-bit transfers the data unmodified, 2 + * bytes per sample. 8-bit unsigned transfers 1 byte per sample + * and XORs each byte with 0x80. Lithium can input or output + * either mono or stereo in either format. + * + * The AD1843 has four formats: 16-bit 2's complement, 8-bit + * unsigned, 8-bit mu-Law and 8-bit A-Law. + * + * This driver supports five formats: AFMT_S8, AFMT_U8, + * AFMT_MU_LAW, AFMT_A_LAW, and AFMT_S16_LE. + * + * For AFMT_U8 output, we keep the AD1843 in 16-bit mode, and + * rely on Lithium's XOR to translate between U8 and S8. + * + * For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR + * the 0x80 bit in software to compensate for Lithium's XOR. + * This happens in pcm_copy_{in,out}(). + */ + +#include +#include +#include +#include +#include +#include + +#include "sound_config.h" + +/*****************************************************************************/ +/* debug stuff */ + +#ifdef VWSND_DEBUG + +#include /* for in_interrupt() */ + +static int shut_up = 1; + +/* + * dbgassert - called when an assertion fails. + */ + +static void dbgassert(const char *fcn, int line, const char *expr) +{ + if (in_interrupt()) + panic("ASSERTION FAILED IN INTERRUPT, %s:%s:%d %s\n", + __FILE__, fcn, line, expr); + else { + int x; + printk(KERN_ERR "ASSERTION FAILED, %s:%s:%d %s\n", + __FILE__, fcn, line, expr); + x = * (volatile int *) 0; /* force proc to exit */ + } +} + +/* + * Bunch of useful debug macros: + * + * ASSERT - print unless e nonzero (panic if in interrupt) + * DBGDO - include arbitrary code if debugging + * DBGX - debug print raw (w/o function name) + * DBGP - debug print w/ function name + * DBGE - debug print function entry + * DBGC - debug print function call + * DBGR - debug print function return + * DBGXV - debug print raw when verbose + * DBGPV - debug print when verbose + * DBGEV - debug print function entry when verbose + * DBGRV - debug print function return when verbose + */ + +#define ASSERT(e) ((e) ? (void) 0 : dbgassert(__FUNCTION__, __LINE__, #e)) +#define DBGDO(x) x +#define DBGX(fmt, args...) (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args)) +#define DBGP(fmt, args...) (DBGX(__FUNCTION__ ": " fmt, ##args)) +#define DBGE(fmt, args...) (DBGX(__FUNCTION__ fmt, ##args)) +#define DBGC(rtn) (DBGP("calling %s\n", rtn)) +#define DBGR() (DBGP("returning\n")) +#define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args)) +#define DBGPV(fmt, args...) (shut_up ? 0 : DBGP(fmt, ##args)) +#define DBGEV(fmt, args...) (shut_up ? 0 : DBGE(fmt, ##args)) +#define DBGCV(rtn) (shut_up ? 0 : DBGC(rtn)) +#define DBGRV() (shut_up ? 0 : DBGR()) + +#else /* !VWSND_DEBUG */ + +#define ASSERT(e) ((void) 0) +#define DBGDO(x) /* don't */ +#define DBGX(fmt, args...) ((void) 0) +#define DBGP(fmt, args...) ((void) 0) +#define DBGE(fmt, args...) ((void) 0) +#define DBGC(rtn) ((void) 0) +#define DBGR() ((void) 0) +#define DBGPV(fmt, args...) ((void) 0) +#define DBGXV(fmt, args...) ((void) 0) +#define DBGEV(fmt, args...) ((void) 0) +#define DBGCV(rtn) ((void) 0) +#define DBGRV() ((void) 0) + +#endif /* !VWSND_DEBUG */ + +/*****************************************************************************/ +/* low level lithium access */ + +/* + * We need to talk to Lithium registers on three pages. Here are + * the pages' offsets from the base address (0xFF001000). + */ + +enum { + LI_PAGE0_OFFSET = 0x01000 - 0x1000, /* FF001000 */ + LI_PAGE1_OFFSET = 0x0F000 - 0x1000, /* FF00F000 */ + LI_PAGE2_OFFSET = 0x10000 - 0x1000, /* FF010000 */ +}; + +/* low-level lithium data */ + +typedef struct lithium { + caddr_t page0; /* virtual addresses */ + caddr_t page1; + caddr_t page2; + spinlock_t lock; /* protects codec and UST/MSC access */ +} lithium_t; + +/* + * li_create initializes the lithium_t structure and sets up vm mappings + * to access the registers. + * Returns 0 on success, -errno on failure. + */ + +static int li_create(lithium_t *lith, unsigned long baseaddr) +{ + static void li_destroy(lithium_t *); + + lith->lock = SPIN_LOCK_UNLOCKED; + lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE); + lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE); + lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE); + if (!lith->page0 || !lith->page1 || !lith->page2) { + li_destroy(lith); + return -ENOMEM; + } + return 0; +} + +/* + * li_destroy destroys the lithium_t structure and vm mappings. + */ + +static void li_destroy(lithium_t *lith) +{ + if (lith->page0) { + iounmap(lith->page0); + lith->page0 = NULL; + } + if (lith->page1) { + iounmap(lith->page1); + lith->page1 = NULL; + } + if (lith->page2) { + iounmap(lith->page2); + lith->page2 = NULL; + } +} + +/* + * basic register accessors - read/write long/byte + */ + +static __inline__ unsigned long li_readl(lithium_t *lith, int off) +{ + return * (volatile unsigned long *) (lith->page0 + off); +} + +static __inline__ unsigned char li_readb(lithium_t *lith, int off) +{ + return * (volatile unsigned char *) (lith->page0 + off); +} + +static __inline__ void li_writel(lithium_t *lith, int off, unsigned long val) +{ + * (volatile unsigned long *) (lith->page0 + off) = val; +} + +static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val) +{ + * (volatile unsigned char *) (lith->page0 + off) = val; +} + +/*****************************************************************************/ +/* High Level Lithium Access */ + +/* + * Lithium DMA Notes + * + * Lithium has two dedicated DMA channels for audio. They are known + * as comm1 and comm2 (communication areas 1 and 2). Comm1 is for + * input, and comm2 is for output. Each is controlled by three + * registers: BASE (base address), CFG (config) and CCTL + * (config/control). + * + * Each DMA channel points to a physically contiguous ring buffer in + * main memory of up to 8 Kbytes. (This driver always uses 8 Kb.) + * There are three pointers into the ring buffer: read, write, and + * trigger. The pointers are 8 bits each. Each pointer points to + * 32-byte "chunks" of data. The DMA engine moves 32 bytes at a time, + * so there is no finer-granularity control. + * + * In comm1, the hardware updates the write ptr, and software updates + * the read ptr. In comm2, it's the opposite: hardware updates the + * read ptr, and software updates the write ptr. I designate the + * hardware-updated ptr as the hwptr, and the software-updated ptr as + * the swptr. + * + * The trigger ptr and trigger mask are used to trigger interrupts. + * From the Lithium spec, section 5.6.8, revision of 12/15/1998: + * + * Trigger Mask Value + * + * A three bit wide field that represents a power of two mask + * that is used whenever the trigger pointer is compared to its + * respective read or write pointer. A value of zero here + * implies a mask of 0xFF and a value of seven implies a mask + * 0x01. This value can be used to sub-divide the ring buffer + * into pie sections so that interrupts monitor the progress of + * hardware from section to section. + * + * My interpretation of that is, whenever the hw ptr is updated, it is + * compared with the trigger ptr, and the result is masked by the + * trigger mask. (Actually, by the complement of the trigger mask.) + * If the result is zero, an interrupt is triggered. I.e., interrupt + * if ((hwptr & ~mask) == (trptr & ~mask)). The mask is formed from + * the trigger register value as mask = (1 << (8 - tmreg)) - 1. + * + * In yet different words, setting tmreg to 0 causes an interrupt after + * every 256 DMA chunks (8192 bytes) or once per traversal of the + * ring buffer. Setting it to 7 caues an interrupt every 2 DMA chunks + * (64 bytes) or 128 times per traversal of the ring buffer. + */ + +/* Lithium register offsets and bit definitions */ + +#define LI_HOST_CONTROLLER 0x000 +# define LI_HC_RESET 0x00008000 +# define LI_HC_LINK_ENABLE 0x00004000 +# define LI_HC_LINK_FAILURE 0x00000004 +# define LI_HC_LINK_CODEC 0x00000002 +# define LI_HC_LINK_READY 0x00000001 + +#define LI_INTR_STATUS 0x010 +#define LI_INTR_MASK 0x014 +# define LI_INTR_LINK_ERR 0x00008000 +# define LI_INTR_COMM2_TRIG 0x00000008 +# define LI_INTR_COMM2_UNDERFLOW 0x00000004 +# define LI_INTR_COMM1_TRIG 0x00000002 +# define LI_INTR_COMM1_OVERFLOW 0x00000001 + +#define LI_CODEC_COMMAND 0x018 +# define LI_CC_BUSY 0x00008000 +# define LI_CC_DIR 0x00000080 +# define LI_CC_DIR_RD LI_CC_DIR +# define LI_CC_DIR_WR (!LI_CC_DIR) +# define LI_CC_ADDR_MASK 0x0000007F + +#define LI_CODEC_DATA 0x01C + +#define LI_COMM1_BASE 0x100 +#define LI_COMM1_CTL 0x104 +# define LI_CCTL_RESET 0x80000000 +# define LI_CCTL_SIZE 0x70000000 +# define LI_CCTL_DMA_ENABLE 0x08000000 +# define LI_CCTL_TMASK 0x07000000 /* trigger mask */ +# define LI_CCTL_TPTR 0x00FF0000 /* trigger pointer */ +# define LI_CCTL_RPTR 0x0000FF00 +# define LI_CCTL_WPTR 0x000000FF +#define LI_COMM1_CFG 0x108 +# define LI_CCFG_LOCK 0x00008000 +# define LI_CCFG_SLOT 0x00000070 +# define LI_CCFG_DIRECTION 0x00000008 +# define LI_CCFG_DIR_IN (!LI_CCFG_DIRECTION) +# define LI_CCFG_DIR_OUT LI_CCFG_DIRECTION +# define LI_CCFG_MODE 0x00000004 +# define LI_CCFG_MODE_MONO (!LI_CCFG_MODE) +# define LI_CCFG_MODE_STEREO LI_CCFG_MODE +# define LI_CCFG_FORMAT 0x00000003 +# define LI_CCFG_FMT_8BIT 0x00000000 +# define LI_CCFG_FMT_16BIT 0x00000001 +#define LI_COMM2_BASE 0x10C +#define LI_COMM2_CTL 0x110 + /* bit definitions are the same as LI_COMM1_CTL */ +#define LI_COMM2_CFG 0x114 + /* bit definitions are the same as LI_COMM1_CFG */ + +#define LI_UST_LOW 0x200 /* 64-bit Unadjusted System Time is */ +#define LI_UST_HIGH 0x204 /* microseconds since boot */ + +#define LI_AUDIO1_UST 0x300 /* UST-MSC pairs */ +#define LI_AUDIO1_MSC 0x304 /* MSC (Media Stream Counter) */ +#define LI_AUDIO2_UST 0x308 /* counts samples actually */ +#define LI_AUDIO2_MSC 0x30C /* processed as of time UST */ + +/* + * Lithium's DMA engine operates on chunks of 32 bytes. We call that + * a DMACHUNK. + */ + +#define DMACHUNK_SHIFT 5 +#define DMACHUNK_SIZE (1 << DMACHUNK_SHIFT) +#define BYTES_TO_CHUNKS(bytes) ((bytes) >> DMACHUNK_SHIFT) +#define CHUNKS_TO_BYTES(chunks) ((chunks) << DMACHUNK_SHIFT) + +/* + * Two convenient macros to shift bitfields into/out of position. + * + * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)). + * As long as mask is constant, we trust the compiler will change the + * multipy and divide into shifts. + */ + +#define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask)) +#define UNSHIFT_FIELD(val, mask) (((val) & (mask)) / ((mask) & -(mask))) + +/* + * dma_chan_desc is invariant information about a Lithium + * DMA channel. There are two instances, li_comm1 and li_comm2. + * + * Note that the CCTL register fields are write ptr and read ptr, but what + * we care about are which pointer is updated by software and which by + * hardware. + */ + +typedef struct dma_chan_desc { + int basereg; + int cfgreg; + int ctlreg; + int hwptrreg; + int swptrreg; + unsigned long swptrmask; + int ad1843_slot; + int direction; /* LI_CCTL_DIR_IN/OUT */ +} dma_chan_desc_t; + +static const dma_chan_desc_t li_comm1 = { + LI_COMM1_BASE, /* base register offset */ + LI_COMM1_CFG, /* config register offset */ + LI_COMM1_CTL, /* control register offset */ + LI_COMM1_CTL + 0, /* hw ptr reg offset (write ptr) */ + LI_COMM1_CTL + 1, /* sw ptr reg offset (read ptr) */ + LI_CCTL_RPTR, /* sw ptr bitmask in ctlval */ + 2, /* ad1843 serial slot */ + LI_CCFG_DIR_IN /* direction */ +}; + +static const dma_chan_desc_t li_comm2 = { + LI_COMM2_BASE, /* base register offset */ + LI_COMM2_CFG, /* config register offset */ + LI_COMM2_CTL, /* control register offset */ + LI_COMM2_CTL + 1, /* hw ptr reg offset (read ptr) */ + LI_COMM2_CTL + 0, /* sw ptr reg offset (writr ptr) */ + LI_CCTL_WPTR, /* sw ptr bitmask in ctlval */ + 2, /* ad1843 serial slot */ + LI_CCFG_DIR_OUT /* direction */ +}; + +/* + * dma_chan is variable information about a Lithium DMA channel. + * + * The desc field points to invariant information. + * The lith field points to a lithium_t which is passed + * to li_read* and li_write* to access the registers. + * The *val fields shadow the lithium registers' contents. + */ + +typedef struct dma_chan { + const dma_chan_desc_t *desc; + lithium_t *lith; + unsigned long baseval; + unsigned long cfgval; + unsigned long ctlval; +} dma_chan_t; + +/* + * li_ad1843_wait waits until lithium says the AD1843 register + * exchange is not busy. Returns 0 on success, -EBUSY on timeout. + * + * Locking: must be called with lithium_lock held. + */ + +static int li_ad1843_wait(lithium_t *lith) +{ + unsigned long later = jiffies + 2; + while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY) + if (jiffies >= later) + return -EBUSY; + return 0; +} + +/* + * li_read_ad1843_reg returns the current contents of a 16 bit AD1843 register. + * + * Returns unsigned register value on success, -errno on failure. + */ + +static int li_read_ad1843_reg(lithium_t *lith, int reg) +{ + int val; + + ASSERT(!in_interrupt()); + spin_lock(&lith->lock); + { + val = li_ad1843_wait(lith); + if (val == 0) { + li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_RD | reg); + val = li_ad1843_wait(lith); + } + if (val == 0) + val = li_readl(lith, LI_CODEC_DATA); + } + spin_unlock(&lith->lock); + + DBGXV("li_read_ad1843_reg(lith=0x%p, reg=%d) returns 0x%04x\n", + lith, reg, val); + + return val; +} + +/* + * li_write_ad1843_reg writes the specified value to a 16 bit AD1843 register. + */ + +static void li_write_ad1843_reg(lithium_t *lith, int reg, int newval) +{ + spin_lock(&lith->lock); + { + if (li_ad1843_wait(lith) == 0) { + li_writel(lith, LI_CODEC_DATA, newval); + li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_WR | reg); + } + } + spin_unlock(&lith->lock); +} + +/* + * li_setup_dma calculates all the register settings for DMA in a particular + * mode. It takes too many arguments. + */ + +static void li_setup_dma(dma_chan_t *chan, + const dma_chan_desc_t *desc, + lithium_t *lith, + unsigned long buffer_paddr, + int bufshift, + int fragshift, + int channels, + int sampsize) +{ + unsigned long mode, format; + unsigned long size, tmask; + + DBGEV("(chan=0x%p, desc=0x%p, lith=0x%p, buffer_paddr=0x%lx, " + "bufshift=%d, fragshift=%d, channels=%d, sampsize=%d)\n", + chan, desc, lith, buffer_paddr, + bufshift, fragshift, channels, sampsize); + + /* Reset the channel first. */ + + li_writel(lith, desc->ctlreg, LI_CCTL_RESET); + + ASSERT(channels == 1 || channels == 2); + if (channels == 2) + mode = LI_CCFG_MODE_STEREO; + else + mode = LI_CCFG_MODE_MONO; + ASSERT(sampsize == 1 || sampsize == 2); + if (sampsize == 2) + format = LI_CCFG_FMT_16BIT; + else + format = LI_CCFG_FMT_8BIT; + chan->desc = desc; + chan->lith = lith; + + /* + * Lithium DMA address register takes a 40-bit physical + * address, right-shifted by 8 so it fits in 32 bits. Bit 37 + * must be set -- it enables cache coherence. + */ + + ASSERT(!(buffer_paddr & 0xFF)); + chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8); + + chan->cfgval = (!LI_CCFG_LOCK | + SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) | + desc->direction | + mode | + format); + + size = bufshift - 6; + tmask = 13 - fragshift; /* See Lithium DMA Notes above. */ + ASSERT(size >= 2 && size <= 7); + ASSERT(tmask >= 1 && tmask <= 7); + chan->ctlval = (!LI_CCTL_RESET | + SHIFT_FIELD(size, LI_CCTL_SIZE) | + !LI_CCTL_DMA_ENABLE | + SHIFT_FIELD(tmask, LI_CCTL_TMASK) | + SHIFT_FIELD(0, LI_CCTL_TPTR)); + + DBGPV("basereg 0x%x = 0x%lx\n", desc->basereg, chan->baseval); + DBGPV("cfgreg 0x%x = 0x%lx\n", desc->cfgreg, chan->cfgval); + DBGPV("ctlreg 0x%x = 0x%lx\n", desc->ctlreg, chan->ctlval); + + li_writel(lith, desc->basereg, chan->baseval); + li_writel(lith, desc->cfgreg, chan->cfgval); + li_writel(lith, desc->ctlreg, chan->ctlval); + + DBGRV(); +} + +static void li_shutdown_dma(dma_chan_t *chan) +{ + lithium_t *lith = chan->lith; + caddr_t lith1 = lith->page1; + + DBGEV("(chan=0x%p)\n", chan); + + chan->ctlval &= ~LI_CCTL_DMA_ENABLE; + DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval); + li_writel(lith, chan->desc->ctlreg, chan->ctlval); + + /* + * Offset 0x500 on Lithium page 1 is an undocumented, + * unsupported register that holds the zero sample value. + * Lithium is supposed to output zero samples when DMA is + * inactive, and repeat the last sample when DMA underflows. + * But it has a bug, where, after underflow occurs, the zero + * sample is not reset. + * + * I expect this to break in a future rev of Lithium. + */ + + if (lith1 && chan->desc->direction == LI_CCFG_DIR_OUT) + * (volatile unsigned long *) (lith1 + 0x500) = 0; +} + +/* + * li_activate_dma always starts dma at the beginning of the buffer. + * + * N.B., these may be called from interrupt. + */ + +static __inline__ void li_activate_dma(dma_chan_t *chan) +{ + chan->ctlval |= LI_CCTL_DMA_ENABLE; + DBGPV("ctlval = 0x%lx\n", chan->ctlval); + li_writel(chan->lith, chan->desc->ctlreg, chan->ctlval); +} + +static void li_deactivate_dma(dma_chan_t *chan) +{ + lithium_t *lith = chan->lith; + caddr_t lith2 = lith->page2; + + chan->ctlval &= ~(LI_CCTL_DMA_ENABLE | LI_CCTL_RPTR | LI_CCTL_WPTR); + DBGPV("ctlval = 0x%lx\n", chan->ctlval); + DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval); + li_writel(lith, chan->desc->ctlreg, chan->ctlval); + + /* + * Offsets 0x98 and 0x9C on Lithium page 2 are undocumented, + * unsupported registers that are internal copies of the DMA + * read and write pointers. Because of a Lithium bug, these + * registers aren't zeroed correctly when DMA is shut off. So + * we whack them directly. + * + * I expect this to break in a future rev of Lithium. + */ + + if (lith2 && chan->desc->direction == LI_CCFG_DIR_OUT) { + * (volatile unsigned long *) (lith2 + 0x98) = 0; + * (volatile unsigned long *) (lith2 + 0x9C) = 0; + } +} + +/* + * read/write the ring buffer pointers. These routines' arguments and results + * are byte offsets from the beginning of the ring buffer. + */ + +static __inline__ int li_read_swptr(dma_chan_t *chan) +{ + const unsigned long mask = chan->desc->swptrmask; + + return CHUNKS_TO_BYTES(UNSHIFT_FIELD(chan->ctlval, mask)); +} + +static __inline__ int li_read_hwptr(dma_chan_t *chan) +{ + return CHUNKS_TO_BYTES(li_readb(chan->lith, chan->desc->hwptrreg)); +} + +static __inline__ void li_write_swptr(dma_chan_t *chan, int val) +{ + const unsigned long mask = chan->desc->swptrmask; + + ASSERT(!(val & ~CHUNKS_TO_BYTES(0xFF))); + val = BYTES_TO_CHUNKS(val); + chan->ctlval = (chan->ctlval & ~mask) | SHIFT_FIELD(val, mask); + li_writeb(chan->lith, chan->desc->swptrreg, val); +} + +static void li_enable_interrupts(lithium_t *lith, unsigned int mask) +{ + DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask); + + /* clear any already-pending interrupts. */ + + li_writel(lith, LI_INTR_STATUS, mask); + + /* enable the interrupts. */ + + mask |= li_readl(lith, LI_INTR_MASK); + li_writel(lith, LI_INTR_MASK, mask); +} + +static void li_disable_interrupts(lithium_t *lith, unsigned int mask) +{ + unsigned int keepmask; + + DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask); + + /* disable the interrupts */ + + keepmask = li_readl(lith, LI_INTR_MASK) & ~mask; + li_writel(lith, LI_INTR_MASK, keepmask); + + /* clear any pending interrupts. */ + + li_writel(lith, LI_INTR_STATUS, mask); +} + +/* Get the interrupt status and clear all pending interrupts. */ + +static unsigned int li_get_clear_intr_status(lithium_t *lith) +{ + unsigned int status; + + status = li_readl(lith, LI_INTR_STATUS); + li_writel(lith, LI_INTR_STATUS, ~0); + return status & li_readl(lith, LI_INTR_MASK); +} + +static int li_init(lithium_t *lith) +{ + /* 1. System power supplies stabilize. */ + + /* 2. Assert the ~RESET signal. */ + + li_writel(lith, LI_HOST_CONTROLLER, LI_HC_RESET); + udelay(1); + + /* 3. Deassert the ~RESET signal and enter a wait period to allow + the AD1843 internal clocks and the external crystal oscillator + to stabilize. */ + + li_writel(lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE); + udelay(1); + + return 0; +} + +/*****************************************************************************/ +/* AD1843 access */ + +/* + * AD1843 bitfield definitions. All are named as in the AD1843 data + * sheet, with ad1843_ prepended and individual bit numbers removed. + * + * E.g., bits LSS0 through LSS2 become ad1843_LSS. + * + * Only the bitfields we need are defined. + */ + +typedef struct ad1843_bitfield { + char reg; + char lo_bit; + char nbits; +} ad1843_bitfield_t; + +static const ad1843_bitfield_t + ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */ + ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */ + ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */ + ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */ + ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */ + ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */ + ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */ + ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */ + ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */ + ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */ + ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */ + ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */ + ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */ + ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */ + ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */ + ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */ + ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */ + ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */ + ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */ + ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */ + ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */ + ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */ + ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */ + ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */ + ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */ + ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */ + ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */ + ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */ + ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */ + ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */ + ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */ + ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */ + ad1843_C2C = { 20, 0, 16 }, /* Clock 1 Sample Rate Select */ + ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */ + ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */ + ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */ + ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */ + ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */ + ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */ + ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */ + ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */ + ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */ + ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */ + ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */ + ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */ + ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */ + ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */ + ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */ + ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */ + ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */ + ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */ + +/* + * The various registers of the AD1843 use three different formats for + * specifying gain. The ad1843_gain structure parameterizes the + * formats. + */ + +typedef struct ad1843_gain { + + int negative; /* nonzero if gain is negative. */ + const ad1843_bitfield_t *lfield; + const ad1843_bitfield_t *rfield; + +} ad1843_gain_t; + +static const ad1843_gain_t ad1843_gain_RECLEV + = { 0, &ad1843_LIG, &ad1843_RIG }; +static const ad1843_gain_t ad1843_gain_LINE + = { 1, &ad1843_LX1M, &ad1843_RX1M }; +static const ad1843_gain_t ad1843_gain_CD + = { 1, &ad1843_LX2M, &ad1843_RX2M }; +static const ad1843_gain_t ad1843_gain_MIC + = { 1, &ad1843_LMCM, &ad1843_RMCM }; +static const ad1843_gain_t ad1843_gain_PCM + = { 1, &ad1843_LDA1G, &ad1843_RDA1G }; + +/* read the current value of an AD1843 bitfield. */ + +static int ad1843_read_bits(lithium_t *lith, const ad1843_bitfield_t *field) +{ + int w = li_read_ad1843_reg(lith, field->reg); + int val = w >> field->lo_bit & ((1 << field->nbits) - 1); + + DBGXV("ad1843_read_bits(lith=0x%p, field->{%d %d %d}) returns 0x%x\n", + lith, field->reg, field->lo_bit, field->nbits, val); + + return val; +} + +/* + * write a new value to an AD1843 bitfield and return the old value. + */ + +static int ad1843_write_bits(lithium_t *lith, + const ad1843_bitfield_t *field, + int newval) +{ + int w = li_read_ad1843_reg(lith, field->reg); + int mask = ((1 << field->nbits) - 1) << field->lo_bit; + int oldval = (w & mask) >> field->lo_bit; + int newbits = (newval << field->lo_bit) & mask; + w = (w & ~mask) | newbits; + (void) li_write_ad1843_reg(lith, field->reg, w); + + DBGXV("ad1843_write_bits(lith=0x%p, field->{%d %d %d}, val=0x%x) " + "returns 0x%x\n", + lith, field->reg, field->lo_bit, field->nbits, newval, + oldval); + + return oldval; +} + +/* + * ad1843_read_multi reads multiple bitfields from the same AD1843 + * register. It uses a single read cycle to do it. (Reading the + * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 + * microseconds.) + * + * Called ike this. + * + * ad1843_read_multi(lith, nfields, + * &ad1843_FIELD1, &val1, + * &ad1843_FIELD2, &val2, ...); + */ + +static void ad1843_read_multi(lithium_t *lith, int argcount, ...) +{ + va_list ap; + const ad1843_bitfield_t *fp; + int w = 0, mask, *value, reg = -1; + + va_start(ap, argcount); + while (--argcount >= 0) { + fp = va_arg(ap, const ad1843_bitfield_t *); + value = va_arg(ap, int *); + if (reg == -1) { + reg = fp->reg; + w = li_read_ad1843_reg(lith, reg); + } + ASSERT(reg == fp->reg); + mask = (1 << fp->nbits) - 1; + *value = w >> fp->lo_bit & mask; + } + va_end(ap); +} + +/* + * ad1843_write_multi stores multiple bitfields into the same AD1843 + * register. It uses one read and one write cycle to do it. + * + * Called like this. + * + * ad1843_write_multi(lith, nfields, + * &ad1843_FIELD1, val1, + * &ad1843_FIELF2, val2, ...); + */ + +static void ad1843_write_multi(lithium_t *lith, int argcount, ...) +{ + va_list ap; + int reg; + const ad1843_bitfield_t *fp; + int value; + int w, m, mask, bits; + + mask = 0; + bits = 0; + reg = -1; + + va_start(ap, argcount); + while (--argcount >= 0) { + fp = va_arg(ap, const ad1843_bitfield_t *); + value = va_arg(ap, int); + if (reg == -1) + reg = fp->reg; + ASSERT(fp->reg == reg); + m = ((1 << fp->nbits) - 1) << fp->lo_bit; + mask |= m; + bits |= (value << fp->lo_bit) & m; + } + va_end(ap); + ASSERT(!(bits & ~mask)); + if (~mask & 0xFFFF) + w = li_read_ad1843_reg(lith, reg); + else + w = 0; + w = (w & ~mask) | bits; + (void) li_write_ad1843_reg(lith, reg, w); +} + +/* + * ad1843_get_gain reads the specified register and extracts the gain value + * using the supplied gain type. It returns the gain in OSS format. + */ + +static int ad1843_get_gain(lithium_t *lith, const ad1843_gain_t *gp) +{ + int lg, rg; + unsigned short mask = (1 << gp->lfield->nbits) - 1; + + ad1843_read_multi(lith, 2, gp->lfield, &lg, gp->rfield, &rg); + if (gp->negative) { + lg = mask - lg; + rg = mask - rg; + } + lg = (lg * 100 + (mask >> 1)) / mask; + rg = (rg * 100 + (mask >> 1)) / mask; + return lg << 0 | rg << 8; +} + +/* + * Set an audio channel's gain. Converts from OSS format to AD1843's + * format. + * + * Returns the new gain, which may be lower than the old gain. + */ + +static int ad1843_set_gain(lithium_t *lith, + const ad1843_gain_t *gp, + int newval) +{ + unsigned short mask = (1 << gp->lfield->nbits) - 1; + + int lg = newval >> 0 & 0xFF; + int rg = newval >> 8; + if (lg < 0 || lg > 100 || rg < 0 || rg > 100) + return -EINVAL; + lg = (lg * mask + (mask >> 1)) / 100; + rg = (rg * mask + (mask >> 1)) / 100; + if (gp->negative) { + lg = mask - lg; + rg = mask - rg; + } + ad1843_write_multi(lith, 2, gp->lfield, lg, gp->rfield, rg); + return ad1843_get_gain(lith, gp); +} + +/* Returns the current recording source, in OSS format. */ + +static int ad1843_get_recsrc(lithium_t *lith) +{ + int ls = ad1843_read_bits(lith, &ad1843_LSS); + + switch (ls) { + case 1: + return SOUND_MASK_MIC; + case 2: + return SOUND_MASK_LINE; + case 3: + return SOUND_MASK_CD; + case 6: + return SOUND_MASK_PCM; + default: + ASSERT(0); + return -1; + } +} + +/* + * Enable/disable digital resample mode in the AD1843. + * + * The AD1843 requires that ADL, ADR, DA1 and DA2 be powered down + * while switching modes. So we save DA1's state (DA2's state is not + * interesting), power them down, switch into/out of resample mode, + * power them up, and restore state. + * + * This will cause audible glitches if D/A or A/D is going on, so the + * driver disallows that (in mixer_write_ioctl()). + * + * The open question is, is this worth doing? I'm leaving it in, + * because it's written, but... + */ + +static void ad1843_set_resample_mode(lithium_t *lith, int onoff) +{ + /* Save DA1 mute and gain (addr 9 is DA1 analog gain/attenuation) */ + int save_da1 = li_read_ad1843_reg(lith, 9); + + /* Power down A/D and D/A. */ + ad1843_write_multi(lith, 4, + &ad1843_DA1EN, 0, + &ad1843_DA2EN, 0, + &ad1843_ADLEN, 0, + &ad1843_ADREN, 0); + + /* Switch mode */ + ASSERT(onoff == 0 || onoff == 1); + ad1843_write_bits(lith, &ad1843_DRSFLT, onoff); + + /* Power up A/D and D/A. */ + ad1843_write_multi(lith, 3, + &ad1843_DA1EN, 1, + &ad1843_ADLEN, 1, + &ad1843_ADREN, 1); + + /* Restore DA1 mute and gain. */ + li_write_ad1843_reg(lith, 9, save_da1); +} + +/* + * Set recording source. Arg newsrc specifies an OSS channel mask. + * + * The complication is that when we switch into/out of loopback mode + * (i.e., src = SOUND_MASK_PCM), we change the AD1843 into/out of + * digital resampling mode. + * + * Returns newsrc on success, -errno on failure. + */ + +static int ad1843_set_recsrc(lithium_t *lith, int newsrc) +{ + int bits; + int oldbits; + + switch (newsrc) { + case SOUND_MASK_PCM: + bits = 6; + break; + + case SOUND_MASK_MIC: + bits = 1; + break; + + case SOUND_MASK_LINE: + bits = 2; + break; + + case SOUND_MASK_CD: + bits = 3; + break; + + default: + return -EINVAL; + } + oldbits = ad1843_read_bits(lith, &ad1843_LSS); + if (newsrc == SOUND_MASK_PCM && oldbits != 6) { + DBGP("enabling digital resample mode\n"); + ad1843_set_resample_mode(lith, 1); + ad1843_write_multi(lith, 2, + &ad1843_DAADL, 2, + &ad1843_DAADR, 2); + } else if (newsrc != SOUND_MASK_PCM && oldbits == 6) { + DBGP("disabling digital resample mode\n"); + ad1843_set_resample_mode(lith, 0); + ad1843_write_multi(lith, 2, + &ad1843_DAADL, 0, + &ad1843_DAADR, 0); + } + ad1843_write_multi(lith, 2, &ad1843_LSS, bits, &ad1843_RSS, bits); + return newsrc; +} + +/* + * Return current output sources, in OSS format. + */ + +static int ad1843_get_outsrc(lithium_t *lith) +{ + int pcm, line, mic, cd; + + pcm = ad1843_read_bits(lith, &ad1843_LDA1GM) ? 0 : SOUND_MASK_PCM; + line = ad1843_read_bits(lith, &ad1843_LX1MM) ? 0 : SOUND_MASK_LINE; + cd = ad1843_read_bits(lith, &ad1843_LX2MM) ? 0 : SOUND_MASK_CD; + mic = ad1843_read_bits(lith, &ad1843_LMCMM) ? 0 : SOUND_MASK_MIC; + + return pcm | line | cd | mic; +} + +/* + * Set output sources. Arg is a mask of active sources in OSS format. + * + * Returns source mask on success, -errno on failure. + */ + +static int ad1843_set_outsrc(lithium_t *lith, int mask) +{ + int pcm, line, mic, cd; + + if (mask & ~(SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_CD | SOUND_MASK_MIC)) + return -EINVAL; + pcm = (mask & SOUND_MASK_PCM) ? 0 : 1; + line = (mask & SOUND_MASK_LINE) ? 0 : 1; + mic = (mask & SOUND_MASK_MIC) ? 0 : 1; + cd = (mask & SOUND_MASK_CD) ? 0 : 1; + + ad1843_write_multi(lith, 2, &ad1843_LDA1GM, pcm, &ad1843_RDA1GM, pcm); + ad1843_write_multi(lith, 2, &ad1843_LX1MM, line, &ad1843_RX1MM, line); + ad1843_write_multi(lith, 2, &ad1843_LX2MM, cd, &ad1843_RX2MM, cd); + ad1843_write_multi(lith, 2, &ad1843_LMCMM, mic, &ad1843_RMCMM, mic); + + return mask; +} + +/* Setup ad1843 for D/A conversion. */ + +static void ad1843_setup_dac(lithium_t *lith, + int framerate, + int fmt, + int channels) +{ + int ad_fmt = 0, ad_mode = 0; + + DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n", + lith, framerate, fmt, channels); + + switch (fmt) { + case AFMT_S8: ad_fmt = 1; break; + case AFMT_U8: ad_fmt = 1; break; + case AFMT_S16_LE: ad_fmt = 1; break; + case AFMT_MU_LAW: ad_fmt = 2; break; + case AFMT_A_LAW: ad_fmt = 3; break; + default: ASSERT(0); + } + + switch (channels) { + case 2: ad_mode = 0; break; + case 1: ad_mode = 1; break; + default: ASSERT(0); + } + + DBGPV("ad_mode = %d, ad_fmt = %d\n", ad_mode, ad_fmt); + ASSERT(framerate >= 4000 && framerate <= 49000); + ad1843_write_bits(lith, &ad1843_C1C, framerate); + ad1843_write_multi(lith, 2, + &ad1843_DA1SM, ad_mode, &ad1843_DA1F, ad_fmt); +} + +static void ad1843_shutdown_dac(lithium_t *lith) +{ + ad1843_write_bits(lith, &ad1843_DA1F, 1); +} + +static void ad1843_setup_adc(lithium_t *lith, int framerate, int fmt, int channels) +{ + int da_fmt = 0; + + DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n", + lith, framerate, fmt, channels); + + switch (fmt) { + case AFMT_S8: da_fmt = 1; break; + case AFMT_U8: da_fmt = 1; break; + case AFMT_S16_LE: da_fmt = 1; break; + case AFMT_MU_LAW: da_fmt = 2; break; + case AFMT_A_LAW: da_fmt = 3; break; + default: ASSERT(0); + } + + DBGPV("da_fmt = %d\n", da_fmt); + ASSERT(framerate >= 4000 && framerate <= 49000); + ad1843_write_bits(lith, &ad1843_C2C, framerate); + ad1843_write_multi(lith, 2, + &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt); +} + +static void ad1843_shutdown_adc(lithium_t *lith) +{ + /* nothing to do */ +} + +/* + * Fully initialize the ad1843. As described in the AD1843 data + * sheet, section "START-UP SEQUENCE". The numbered comments are + * subsection headings from the data sheet. See the data sheet, pages + * 52-54, for more info. + * + * return 0 on success, -errno on failure. */ + +static int ad1843_init(lithium_t *lith) +{ + unsigned long later; + int err; + + err = li_init(lith); + if (err) + return err; + + if (ad1843_read_bits(lith, &ad1843_INIT) != 0) { + printk(KERN_ERR "vwsnd sound: AD1843 won't initialize\n"); + return -EIO; + } + + ad1843_write_bits(lith, &ad1843_SCF, 1); + + /* 4. Put the conversion resources into standby. */ + + ad1843_write_bits(lith, &ad1843_PDNI, 0); + later = jiffies + HZ / 2; /* roughly half a second */ + DBGDO(shut_up++); + while (ad1843_read_bits(lith, &ad1843_PDNO)) { + if (jiffies > later) { + printk(KERN_ERR + "vwsnd audio: AD1843 won't power up\n"); + return -EIO; + } + schedule(); + } + DBGDO(shut_up--); + + /* 5. Power up the clock generators and enable clock output pins. */ + + ad1843_write_multi(lith, 2, &ad1843_C1EN, 1, &ad1843_C2EN, 1); + + /* 6. Configure conversion resources while they are in standby. */ + + /* DAC1 uses clock 1 as source, ADC uses clock 2. Always. */ + + ad1843_write_multi(lith, 3, + &ad1843_DA1C, 1, + &ad1843_ADLC, 2, + &ad1843_ADRC, 2); + + /* 7. Enable conversion resources. */ + + ad1843_write_bits(lith, &ad1843_ADTLK, 1); + ad1843_write_multi(lith, 5, + &ad1843_ANAEN, 1, + &ad1843_AAMEN, 1, + &ad1843_DA1EN, 1, + &ad1843_ADLEN, 1, + &ad1843_ADREN, 1); + + /* 8. Configure conversion resources while they are enabled. */ + + ad1843_write_bits(lith, &ad1843_DA1C, 1); + + /* Unmute all channels. */ + + ad1843_set_outsrc(lith, + (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD)); + ad1843_write_multi(lith, 2, &ad1843_LDA1AM, 0, &ad1843_RDA1AM, 0); + + /* Set default recording source to Line In and set + * mic gain to +20 dB. + */ + + ad1843_set_recsrc(lith, SOUND_MASK_LINE); + ad1843_write_multi(lith, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1); + + /* Set Speaker Out level to +/- 4V and unmute it. */ + + ad1843_write_multi(lith, 2, &ad1843_HPOS, 1, &ad1843_HPOM, 0); + + return 0; +} + +/*****************************************************************************/ +/* PCM I/O */ + +#define READ_INTR_MASK (LI_INTR_COMM1_TRIG | LI_INTR_COMM1_OVERFLOW) +#define WRITE_INTR_MASK (LI_INTR_COMM2_TRIG | LI_INTR_COMM2_UNDERFLOW) + +typedef enum vwsnd_port_swstate { /* software state */ + SW_OFF, + SW_INITIAL, + SW_RUN, + SW_DRAIN, +} vwsnd_port_swstate_t; + +typedef enum vwsnd_port_hwstate { /* hardware state */ + HW_STOPPED, + HW_RUNNING, +} vwsnd_port_hwstate_t; + +/* + * These flags are read by ISR, but only written at baseline. + */ + +typedef enum vwsnd_port_flags { + DISABLED = 1 << 0, + ERFLOWN = 1 << 1, /* overflown or underflown */ + HW_BUSY = 1 << 2, +} vwsnd_port_flags_t; + +/* + * vwsnd_port is the per-port data structure. Each device has two + * ports, one for input and one for output. + * + * Locking: + * + * port->lock protects: hwstate, flags, swb_[iu]_avail. + * + * devc->io_sema protects: swstate, sw_*, swb_[iu]_idx. + * + * everything else is only written by open/release or + * pcm_{setup,shutdown}(), which are serialized by a + * combination of devc->open_sema and devc->io_sema. + */ + +typedef struct vwsnd_port { + + spinlock_t lock; + struct wait_queue *queue; + vwsnd_port_swstate_t swstate; + vwsnd_port_hwstate_t hwstate; + vwsnd_port_flags_t flags; + + int sw_channels; + int sw_samplefmt; + int sw_framerate; + int sample_size; + int frame_size; + unsigned int zero_word; /* zero for the sample format */ + + int sw_fragshift; + int sw_fragcount; + int sw_subdivshift; + + unsigned int hw_fragshift; + unsigned int hw_fragsize; + unsigned int hw_fragcount; + + int hwbuf_size; + unsigned long hwbuf_paddr; + unsigned long hwbuf_vaddr; + caddr_t hwbuf; /* hwbuf == hwbuf_vaddr */ + int hwbuf_max; /* max bytes to preload */ + + caddr_t swbuf; + unsigned int swbuf_size; /* size in bytes */ + unsigned int swb_u_idx; /* index of next user byte */ + unsigned int swb_i_idx; /* index of next intr byte */ + unsigned int swb_u_avail; /* # bytes avail to user */ + unsigned int swb_i_avail; /* # bytes avail to intr */ + + dma_chan_t chan; + +} vwsnd_port_t; + +/* vwsnd_dev is the per-device data structure. */ + +typedef struct vwsnd_dev { + struct vwsnd_dev *next_dev; + int audio_minor; /* minor number of audio device */ + int mixer_minor; /* minor number of mixer device */ + + struct semaphore open_sema; + struct semaphore io_sema; + struct semaphore mix_sema; + mode_t open_mode; + struct wait_queue *open_wait; + + lithium_t lith; + + vwsnd_port_t rport; + vwsnd_port_t wport; +} vwsnd_dev_t; + +static vwsnd_dev_t *vwsnd_dev_list; /* linked list of all devices */ + +#ifdef MODULE + +# define INC_USE_COUNT MOD_INC_USE_COUNT +# define DEC_USE_COUNT MOD_DEC_USE_COUNT +# define IN_USE MOD_IN_USE + +#else + +static atomic_t vwsnd_use_count = ATOMIC_INIT(0); + +# define INC_USE_COUNT (atomic_inc(&vwsnd_use_count)) +# define DEC_USE_COUNT (atomic_dec(&vwsnd_use_count)) +# define IN_USE (atomic_read(&vwsnd_use_count) != 0) + +#endif + +/* + * Lithium can only DMA multiples of 32 bytes. Its DMA buffer may + * be up to 8 Kb. This driver always uses 8 Kb. + * + * Memory bug workaround -- I'm not sure what's going on here, but + * somehow pcm_copy_out() was triggering segv's going on to the next + * page of the hw buffer. So, I make the hw buffer one size bigger + * than we actually use. That way, the following page is allocated + * and mapped, and no error. I suspect that something is broken + * in Cobalt, but haven't really investigated. HBO is the actual + * size of the buffer, and HWBUF_ORDER is what we allocate. + */ + +#define HWBUF_SHIFT 13 +#define HWBUF_SIZE (1 << HWBUF_SHIFT) +# define HBO (HWBUF_SHIFT > PAGE_SHIFT ? HWBUF_SHIFT - PAGE_SHIFT : 0) +# define HWBUF_ORDER (HBO + 1) /* next size bigger */ +#define MIN_SPEED 4000 +#define MAX_SPEED 49000 + +#define MIN_FRAGSHIFT (DMACHUNK_SHIFT + 1) +#define MAX_FRAGSHIFT (PAGE_SHIFT) +#define MIN_FRAGSIZE (1 << MIN_FRAGSHIFT) +#define MAX_FRAGSIZE (1 << MAX_FRAGSHIFT) +#define MIN_FRAGCOUNT(fragsize) 2 +#define MAX_FRAGCOUNT(fragsize) (32 * PAGE_SIZE / (fragsize)) +#define DEFAULT_FRAGSHIFT 12 +#define DEFAULT_FRAGCOUNT 16 +#define DEFAULT_SUBDIVSHIFT 0 + +/* + * The software buffer (swbuf) is a ring buffer shared between user + * level and interrupt level. Each level owns some of the bytes in + * the buffer, and may give bytes away by calling swb_inc_{u,i}(). + * User level calls _u for user, and interrupt level calls _i for + * interrupt. + * + * port->swb_{u,i}_avail is the number of bytes available to that level. + * + * port->swb_{u,i}_idx is the index of the first available byte in the + * buffer. + * + * Each level calls swb_inc_{u,i}() to atomically increment its index, + * recalculate the number of bytes available for both sides, and + * return the number of bytes available. Since each side can only + * give away bytes, the other side can only increase the number of + * bytes available to this side. Each side updates its own index + * variable, swb_{u,i}_idx, so no lock is needed to read it. + * + * To query the number of bytes available, call swb_inc_{u,i} with an + * increment of zero. + */ + +static __inline__ unsigned int __swb_inc_u(vwsnd_port_t *port, int inc) +{ + if (inc) { + port->swb_u_idx += inc; + port->swb_u_idx %= port->swbuf_size; + port->swb_u_avail -= inc; + port->swb_i_avail += inc; + } + return port->swb_u_avail; +} + +static __inline__ unsigned int swb_inc_u(vwsnd_port_t *port, int inc) +{ + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + { + ret = __swb_inc_u(port, inc); + } + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +static __inline__ unsigned int __swb_inc_i(vwsnd_port_t *port, int inc) +{ + if (inc) { + port->swb_i_idx += inc; + port->swb_i_idx %= port->swbuf_size; + port->swb_i_avail -= inc; + port->swb_u_avail += inc; + } + return port->swb_i_avail; +} + +static __inline__ unsigned int swb_inc_i(vwsnd_port_t *port, int inc) +{ + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + { + ret = __swb_inc_i(port, inc); + } + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +/* + * pcm_setup - this routine initializes all port state after + * mode-setting ioctls have been done, but before the first I/O is + * done. + * + * Locking: called with devc->io_sema held. + * + * Returns 0 on success, -errno on failure. + */ + +static int pcm_setup(vwsnd_dev_t *devc, + vwsnd_port_t *rport, + vwsnd_port_t *wport) +{ + vwsnd_port_t *aport = rport ? rport : wport; + int sample_size; + unsigned int zero_word; + + DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport); + + ASSERT(aport != NULL); + if (aport->swbuf != NULL) + return 0; + switch (aport->sw_samplefmt) { + case AFMT_MU_LAW: + sample_size = 1; + zero_word = 0xFFFFFFFF ^ 0x80808080; + break; + + case AFMT_A_LAW: + sample_size = 1; + zero_word = 0xD5D5D5D5 ^ 0x80808080; + break; + + case AFMT_U8: + sample_size = 1; + zero_word = 0x80808080; + break; + + case AFMT_S8: + sample_size = 1; + zero_word = 0x00000000; + break; + + case AFMT_S16_LE: + sample_size = 2; + zero_word = 0x00000000; + break; + + default: + sample_size = 0; /* prevent compiler warning */ + zero_word = 0; + ASSERT(0); + } + aport->sample_size = sample_size; + aport->zero_word = zero_word; + aport->frame_size = aport->sw_channels * aport->sample_size; + aport->hw_fragshift = aport->sw_fragshift - aport->sw_subdivshift; + aport->hw_fragsize = 1 << aport->hw_fragshift; + aport->hw_fragcount = aport->sw_fragcount << aport->sw_subdivshift; + aport->swbuf_size = aport->hw_fragcount * aport->hw_fragsize; + aport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE; + aport->swb_u_idx = 0; + aport->swb_i_idx = 0; + + /* + * Is this a Cobalt bug? We need to make this buffer extend one + * page further than we actually use -- somehow memcpy fails + * otherwise. I suspect there's a bug in Cobalt (or somewhere) + * where it's generating a fault on a speculative load or something. + * Obviously, I haven't taken the time to track it down. + */ + + aport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE); + if (!aport->swbuf) + return -ENOMEM; + if (rport && wport) { + ASSERT(aport == rport); + ASSERT(wport->swbuf == NULL); + /* One extra page - see comment above. */ + wport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE); + if (!wport->swbuf) { + vfree(aport->swbuf); + aport->swbuf = NULL; + return -ENOMEM; + } + wport->sample_size = rport->sample_size; + wport->zero_word = rport->zero_word; + wport->frame_size = rport->frame_size; + wport->hw_fragshift = rport->hw_fragshift; + wport->hw_fragsize = rport->hw_fragsize; + wport->hw_fragcount = rport->hw_fragcount; + wport->swbuf_size = rport->swbuf_size; + wport->hwbuf_max = rport->hwbuf_max; + wport->swb_u_idx = rport->swb_u_idx; + wport->swb_i_idx = rport->swb_i_idx; + } + if (rport) { + rport->swb_u_avail = 0; + rport->swb_i_avail = rport->swbuf_size; + rport->swstate = SW_RUN; + li_setup_dma(&rport->chan, + &li_comm1, + &devc->lith, + rport->hwbuf_paddr, + HWBUF_SHIFT, + rport->hw_fragshift, + rport->sw_channels, + rport->sample_size); + ad1843_setup_adc(&devc->lith, + rport->sw_framerate, + rport->sw_samplefmt, + rport->sw_channels); + li_enable_interrupts(&devc->lith, READ_INTR_MASK); + if (!(rport->flags & DISABLED)) { + rport->hwstate = HW_RUNNING; + li_activate_dma(&rport->chan); + } + } + if (wport) { + if (aport->hwbuf_max > aport->swbuf_size) + aport->hwbuf_max = aport->swbuf_size; + wport->flags &= ~ERFLOWN; + wport->swb_u_avail = wport->swbuf_size; + wport->swb_i_avail = 0; + wport->swstate = SW_RUN; + li_setup_dma(&wport->chan, + &li_comm2, + &devc->lith, + wport->hwbuf_paddr, + HWBUF_SHIFT, + wport->hw_fragshift, + wport->sw_channels, + wport->sample_size); + ad1843_setup_dac(&devc->lith, + wport->sw_framerate, + wport->sw_samplefmt, + wport->sw_channels); + li_enable_interrupts(&devc->lith, WRITE_INTR_MASK); + } + DBGRV(); + return 0; +} + +/* + * pcm_shutdown_port - shut down one port (direction) for PCM I/O. + * Only called from pcm_shutdown. + */ + +static void pcm_shutdown_port(vwsnd_dev_t *devc, + vwsnd_port_t *aport, + unsigned int mask) +{ + unsigned long flags; + vwsnd_port_hwstate_t hwstate; + struct wait_queue wait = { current, NULL }; + + aport->swstate = SW_INITIAL; + add_wait_queue(&aport->queue, &wait); + current->state = TASK_UNINTERRUPTIBLE; + while (1) { + spin_lock_irqsave(&aport->lock, flags); + { + hwstate = aport->hwstate; + } + spin_unlock_irqrestore(&aport->lock, flags); + if (hwstate == HW_STOPPED) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&aport->queue, &wait); + li_disable_interrupts(&devc->lith, mask); + if (aport == &devc->rport) + ad1843_shutdown_adc(&devc->lith); + else /* aport == &devc->wport) */ + ad1843_shutdown_dac(&devc->lith); + li_shutdown_dma(&aport->chan); + vfree(aport->swbuf); + aport->swbuf = NULL; +} + +/* + * pcm_shutdown undoes what pcm_setup did. + * Also sets the ports' swstate to newstate. + */ + +static void pcm_shutdown(vwsnd_dev_t *devc, + vwsnd_port_t *rport, + vwsnd_port_t *wport) +{ + DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport); + + if (rport && rport->swbuf) { + DBGPV("shutting down rport\n"); + pcm_shutdown_port(devc, rport, READ_INTR_MASK); + } + if (wport && wport->swbuf) { + DBGPV("shutting down wport\n"); + pcm_shutdown_port(devc, wport, READ_INTR_MASK); + } + DBGRV(); +} + +static void pcm_copy_in(vwsnd_port_t *rport, int swidx, int hwidx, int nb) +{ + char *src = rport->hwbuf + hwidx; + char *dst = rport->swbuf + swidx; + int fmt = rport->sw_samplefmt; + + DBGPV("swidx = %d, hwidx = %d\n", swidx, hwidx); + ASSERT(rport->hwbuf != NULL); + ASSERT(rport->swbuf != NULL); + ASSERT(nb > 0 && (nb % 32) == 0); + ASSERT(swidx % 32 == 0 && hwidx % 32 == 0); + ASSERT(swidx >= 0 && swidx + nb <= rport->swbuf_size); + ASSERT(hwidx >= 0 && hwidx + nb <= rport->hwbuf_size); + + if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) { + + /* See Sample Format Notes above. */ + + char *end = src + nb; + while (src < end) + *dst++ = *src++ ^ 0x80; + } else + memcpy(dst, src, nb); +} + +static void pcm_copy_out(vwsnd_port_t *wport, int swidx, int hwidx, int nb) +{ + char *src = wport->swbuf + swidx; + char *dst = wport->hwbuf + hwidx; + int fmt = wport->sw_samplefmt; + + ASSERT(nb > 0 && (nb % 32) == 0); + ASSERT(wport->hwbuf != NULL); + ASSERT(wport->swbuf != NULL); + ASSERT(swidx % 32 == 0 && hwidx % 32 == 0); + ASSERT(swidx >= 0 && swidx + nb <= wport->swbuf_size); + ASSERT(hwidx >= 0 && hwidx + nb <= wport->hwbuf_size); + if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) { + + /* See Sample Format Notes above. */ + + char *end = src + nb; + while (src < end) + *dst++ = *src++ ^ 0x80; + } else + memcpy(dst, src, nb); +} + +/* + * pcm_output() is called both from baselevel and from interrupt level. + * This is where audio frames are copied into the hardware-accessible + * ring buffer. + * + * Locking note: The part of this routine that figures out what to do + * holds wport->lock. The longer part releases wport->lock, but sets + * wport->flags & HW_BUSY. Afterward, it reacquires wport->lock, and + * checks for more work to do. + * + * If another thread calls pcm_output() while HW_BUSY is set, it + * returns immediately, knowing that the thread that set HW_BUSY will + * look for more work to do before returning. + * + * This has the advantage that port->lock is held for several short + * periods instead of one long period. Also, when pcm_output is + * called from base level, it reenables interrupts. + */ + +static void pcm_output(vwsnd_dev_t *devc, int erflown, int nb) +{ + vwsnd_port_t *wport = &devc->wport; + const int hwmax = wport->hwbuf_max; + const int hwsize = wport->hwbuf_size; + const int swsize = wport->swbuf_size; + const int fragsize = wport->hw_fragsize; + unsigned long iflags; + + DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb); + spin_lock_irqsave(&wport->lock, iflags); + if (erflown) + wport->flags |= ERFLOWN; + (void) __swb_inc_u(wport, nb); + if (wport->flags & HW_BUSY) { + spin_unlock_irqrestore(&wport->lock, iflags); + DBGPV("returning: HW BUSY\n"); + return; + } + if (wport->flags & DISABLED) { + spin_unlock_irqrestore(&wport->lock, iflags); + DBGPV("returning: DISABLED\n"); + return; + } + wport->flags |= HW_BUSY; + while (1) { + int swptr, hwptr, hw_avail, sw_avail, swidx; + vwsnd_port_hwstate_t hwstate = wport->hwstate; + vwsnd_port_swstate_t swstate = wport->swstate; + int hw_unavail; + + hwptr = li_read_hwptr(&wport->chan); + swptr = li_read_swptr(&wport->chan); + hw_unavail = (swptr - hwptr + hwsize) % hwsize; + hw_avail = (hwmax - hw_unavail) & -fragsize; + sw_avail = wport->swb_i_avail & -fragsize; + if (sw_avail && swstate == SW_RUN) + wport->flags &= ~ERFLOWN; + else if (swstate == SW_INITIAL || + swstate == SW_OFF || + (swstate == SW_DRAIN && + !sw_avail && + (wport->flags & ERFLOWN))) { + DBGP("stopping. hwstate = %d\n", hwstate); + if (hwstate != HW_STOPPED) { + li_deactivate_dma(&wport->chan); + wport->hwstate = HW_STOPPED; + } + wake_up(&wport->queue); + break; + } + if (!sw_avail || !hw_avail) + break; + spin_unlock_irqrestore(&wport->lock, iflags); + + /* + * We gave up the port lock, but we have the HW_BUSY flag. + * Proceed without accessing any nonlocal state. + * Do not exit the loop -- must check for more work. + */ + + swidx = wport->swb_i_idx; + nb = hw_avail; + if (nb > sw_avail) + nb = sw_avail; + if (nb > hwsize - swptr) + nb = hwsize - swptr; /* don't overflow hwbuf */ + if (nb > swsize - swidx) + nb = swsize - swidx; /* don't overflow swbuf */ + ASSERT(nb > 0); + if (nb % fragsize) { + DBGP("nb = %d, fragsize = %d\n", nb, fragsize); + DBGP("hw_avail = %d\n", hw_avail); + DBGP("sw_avail = %d\n", sw_avail); + DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr); + DBGP("swsize = %d, swidx = %d\n", swsize, swidx); + } + ASSERT(!(nb % fragsize)); + DBGPV("copying swb[%d..%d] to hwb[%d..%d]\n", + swidx, swidx + nb, swptr, swptr + nb); + pcm_copy_out(wport, swidx, swptr, nb); + li_write_swptr(&wport->chan, (swptr + nb) % hwsize); + spin_lock_irqsave(&wport->lock, iflags); + if (hwstate == HW_STOPPED) { + DBGPV("starting\n"); + li_activate_dma(&wport->chan); + wport->hwstate = HW_RUNNING; + } + __swb_inc_i(wport, nb); + wake_up(&wport->queue); + } + wport->flags &= ~HW_BUSY; + spin_unlock_irqrestore(&wport->lock, iflags); + DBGRV(); +} + +/* + * pcm_input() is called both from baselevel and from interrupt level. + * This is where audio frames are copied into the hardware-accessible + * ring buffer. + * + * Locking note: The part of this routine that figures out what to do + * holds rport->lock. The longer part releases rport->lock, but sets + * rport->flags & HW_BUSY. Afterward, it reacquires rport->lock, and + * checks for more work to do. + * + * If another thread calls pcm_input() while HW_BUSY is set, it + * returns immediately, knowing that the thread that set HW_BUSY will + * look for more work to do before returning. + * + * This has the advantage that port->lock is held for several short + * periods instead of one long period. Also, when pcm_input is + * called from base level, it reenables interrupts. + */ + +static void pcm_input(vwsnd_dev_t *devc, int erflown, int nb) +{ + vwsnd_port_t *rport = &devc->rport; + const int hwmax = rport->hwbuf_max; + const int hwsize = rport->hwbuf_size; + const int swsize = rport->swbuf_size; + const int fragsize = rport->hw_fragsize; + unsigned long iflags; + + DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb); + + spin_lock_irqsave(&rport->lock, iflags); + if (erflown) + rport->flags |= ERFLOWN; + (void) __swb_inc_u(rport, nb); + if (rport->flags & HW_BUSY || !rport->swbuf) { + spin_unlock_irqrestore(&rport->lock, iflags); + DBGPV("returning: HW BUSY or !swbuf\n"); + return; + } + if (rport->flags & DISABLED) { + spin_unlock_irqrestore(&rport->lock, iflags); + DBGPV("returning: DISABLED\n"); + return; + } + rport->flags |= HW_BUSY; + while (1) { + int swptr, hwptr, hw_avail, sw_avail, swidx; + vwsnd_port_hwstate_t hwstate = rport->hwstate; + vwsnd_port_swstate_t swstate = rport->swstate; + + hwptr = li_read_hwptr(&rport->chan); + swptr = li_read_swptr(&rport->chan); + hw_avail = (hwptr - swptr + hwsize) % hwsize & -fragsize; + if (hw_avail > hwmax) + hw_avail = hwmax; + sw_avail = rport->swb_i_avail & -fragsize; + if (swstate != SW_RUN) { + DBGP("stopping. hwstate = %d\n", hwstate); + if (hwstate != HW_STOPPED) { + li_deactivate_dma(&rport->chan); + rport->hwstate = HW_STOPPED; + } + wake_up(&rport->queue); + break; + } + if (!sw_avail || !hw_avail) + break; + spin_unlock_irqrestore(&rport->lock, iflags); + + /* + * We gave up the port lock, but we have the HW_BUSY flag. + * Proceed without accessing any nonlocal state. + * Do not exit the loop -- must check for more work. + */ + + swidx = rport->swb_i_idx; + nb = hw_avail; + if (nb > sw_avail) + nb = sw_avail; + if (nb > hwsize - swptr) + nb = hwsize - swptr; /* don't overflow hwbuf */ + if (nb > swsize - swidx) + nb = swsize - swidx; /* don't overflow swbuf */ + ASSERT(nb > 0); + if (nb % fragsize) { + DBGP("nb = %d, fragsize = %d\n", nb, fragsize); + DBGP("hw_avail = %d\n", hw_avail); + DBGP("sw_avail = %d\n", sw_avail); + DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr); + DBGP("swsize = %d, swidx = %d\n", swsize, swidx); + } + ASSERT(!(nb % fragsize)); + DBGPV("copying hwb[%d..%d] to swb[%d..%d]\n", + swptr, swptr + nb, swidx, swidx + nb); + pcm_copy_in(rport, swidx, swptr, nb); + li_write_swptr(&rport->chan, (swptr + nb) % hwsize); + spin_lock_irqsave(&rport->lock, iflags); + __swb_inc_i(rport, nb); + wake_up(&rport->queue); + } + rport->flags &= ~HW_BUSY; + spin_unlock_irqrestore(&rport->lock, iflags); + DBGRV(); +} + +/* + * pcm_flush_frag() writes zero samples to fill the current fragment, + * then flushes it to the hardware. + * + * It is only meaningful to flush output, not input. + */ + +static void pcm_flush_frag(vwsnd_dev_t *devc) +{ + vwsnd_port_t *wport = &devc->wport; + + DBGPV("swstate = %d\n", wport->swstate); + if (wport->swstate == SW_RUN) { + int idx = wport->swb_u_idx; + int end = (idx + wport->hw_fragsize - 1) + >> wport->hw_fragshift + << wport->hw_fragshift; + int nb = end - idx; + DBGPV("clearing %d bytes\n", nb); + if (nb) + memset(wport->swbuf + idx, + (char) wport->zero_word, + nb); + wport->swstate = SW_DRAIN; + pcm_output(devc, 0, nb); + } + DBGRV(); +} + +/* + * Wait for output to drain. This sleeps uninterruptibly because + * there is nothing intelligent we can do if interrupted. This + * means the process will be delayed in responding to the signal. + */ + +static void pcm_write_sync(vwsnd_dev_t *devc) +{ + vwsnd_port_t *wport = &devc->wport; + struct wait_queue wait = { current, NULL }; + unsigned long flags; + vwsnd_port_hwstate_t hwstate; + + DBGEV("(devc=0x%p)\n", devc); + add_wait_queue(&wport->queue, &wait); + current->state = TASK_UNINTERRUPTIBLE; + while (1) { + spin_lock_irqsave(&wport->lock, flags); + { + hwstate = wport->hwstate; + } + spin_unlock_irqrestore(&wport->lock, flags); + if (hwstate == HW_STOPPED) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + DBGPV("swstate = %d, hwstate = %d\n", wport->swstate, wport->hwstate); + DBGRV(); +} + +/*****************************************************************************/ +/* audio driver */ + +/* + * seek on an audio device always fails. + */ + +static void vwsnd_audio_read_intr(vwsnd_dev_t *devc, unsigned int status) +{ + int overflown = status & LI_INTR_COMM1_OVERFLOW; + + if (status & READ_INTR_MASK) + pcm_input(devc, overflown, 0); +} + +static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status) +{ + int underflown = status & LI_INTR_COMM2_UNDERFLOW; + + if (status & WRITE_INTR_MASK) + pcm_output(devc, underflown, 0); +} + +static void vwsnd_audio_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) dev_id; + unsigned int status; + + DBGEV("(irq=%d, dev_id=0x%p, regs=0x%p)\n", irq, dev_id, regs); + + status = li_get_clear_intr_status(&devc->lith); + vwsnd_audio_read_intr(devc, status); + vwsnd_audio_write_intr(devc, status); +} + +static loff_t vwsnd_audio_llseek(struct file *file, loff_t offset, int whence) +{ + DBGEV("(file=0x%p, offset=%Ld, whence=%d)\n", file, offset, whence); + return -ESPIPE; +} + +static ssize_t vwsnd_audio_do_read(struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + vwsnd_port_t *rport = ((file->f_mode & FMODE_READ) ? + &devc->rport : NULL); + int ret, nb; + + DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n", + file, buffer, count, ppos); + + if (!rport) + return -EINVAL; + + if (rport->swbuf == NULL) { + vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL; + ret = pcm_setup(devc, rport, wport); + if (ret < 0) + return ret; + } + + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + while (count) { + struct wait_queue wait = { current, NULL }; + add_wait_queue(&rport->queue, &wait); + current->state = TASK_INTERRUPTIBLE; + while ((nb = swb_inc_u(rport, 0)) == 0) { + DBGPV("blocking\n"); + if (rport->flags & DISABLED || + file->f_flags & O_NONBLOCK) { + current->state = TASK_RUNNING; + remove_wait_queue(&rport->queue, &wait); + return ret ? ret : -EAGAIN; + } + schedule(); + if (signal_pending(current)) { + current->state = TASK_RUNNING; + remove_wait_queue(&rport->queue, &wait); + return ret ? ret : -ERESTARTSYS; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&rport->queue, &wait); + pcm_input(devc, 0, 0); + /* nb bytes are available in userbuf. */ + if (nb > count) + nb = count; + DBGPV("nb = %d\n", nb); + copy_to_user(buffer, rport->swbuf + rport->swb_u_idx, nb); + (void) swb_inc_u(rport, nb); + buffer += nb; + count -= nb; + ret += nb; + } + DBGPV("returning %d\n", ret); + return ret; +} + +static ssize_t vwsnd_audio_read(struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + ssize_t ret; + + down(&devc->io_sema); + ret = vwsnd_audio_do_read(file, buffer, count, ppos); + up(&devc->io_sema); + return ret; +} + +static ssize_t vwsnd_audio_do_write(struct file *file, + const char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + vwsnd_port_t *wport = ((file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL); + int ret, nb; + + DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n", + file, buffer, count, ppos); + + if (!wport) + return -EINVAL; + + if (wport->swbuf == NULL) { + vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? + &devc->rport : NULL; + ret = pcm_setup(devc, rport, wport); + if (ret < 0) + return ret; + } + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + while (count) { + struct wait_queue wait = { current, NULL }; + add_wait_queue(&wport->queue, &wait); + current->state = TASK_INTERRUPTIBLE; + while ((nb = swb_inc_u(wport, 0)) == 0) { + if (wport->flags & DISABLED || + file->f_flags & O_NONBLOCK) { + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + return ret ? ret : -EAGAIN; + } + schedule(); + if (signal_pending(current)) { + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + return ret ? ret : -ERESTARTSYS; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + /* nb bytes are available in userbuf. */ + if (nb > count) + nb = count; + DBGPV("nb = %d\n", nb); + copy_from_user(wport->swbuf + wport->swb_u_idx, buffer, nb); + pcm_output(devc, 0, nb); + buffer += nb; + count -= nb; + ret += nb; + } + DBGPV("returning %d\n", ret); + return ret; +} + +static ssize_t vwsnd_audio_write(struct file *file, + const char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + ssize_t ret; + + down(&devc->io_sema); + ret = vwsnd_audio_do_write(file, buffer, count, ppos); + up(&devc->io_sema); + return ret; +} + +static unsigned int vwsnd_audio_poll(struct file *file, + struct poll_table_struct *wait) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? + &devc->rport : NULL; + vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL; + unsigned int mask = 0; + + DBGEV("(file=0x%p, wait=0x%p)\n", file, wait); + + ASSERT(rport || wport); + if (rport) { + poll_wait(file, &rport->queue, wait); + if (swb_inc_u(rport, 0)) + mask |= (POLLIN | POLLRDNORM); + } + if (wport) { + poll_wait(file, &wport->queue, wait); + if (wport->swbuf == NULL || swb_inc_u(wport, 0)) + mask |= (POLLOUT | POLLWRNORM); + } + + DBGPV("returning 0x%x\n", mask); + return mask; +} + +static int vwsnd_audio_do_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? + &devc->rport : NULL; + vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL; + vwsnd_port_t *aport = rport ? rport : wport; + struct audio_buf_info buf_info; + int ival; + + + DBGEV("(inode=0x%p, file=0x%p, cmd=0x%x, arg=0x%lx)\n", + inode, file, cmd, arg); + switch (cmd) { + case OSS_GETVERSION: /* _SIOR ('M', 118, int) */ + ival = SOUND_VERSION; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETCAPS: /* _SIOR ('P',15, int) */ +/* XXX ival = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER; */ + ival = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETFMTS: /* _SIOR ('P',11, int) */ + ival = (AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | + AFMT_U8 | AFMT_S8); + return put_user(ival, (int *) arg); + break; + + case SOUND_PCM_READ_RATE: /* _SIOR ('P', 2, int) */ + ival = aport->sw_framerate; + return put_user(ival, (int *) arg); + + case SOUND_PCM_READ_CHANNELS: /* _SIOR ('P', 6, int) */ + ival = aport->sw_channels; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SPEED: /* _SIOWR('P', 2, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SPEED %d\n", ival); + if (ival) { + if (aport->swstate != SW_INITIAL) { + DBGX("SNDCTL_DSP_SPEED failed: swstate = %d\n", + aport->swstate); + return -EINVAL; + } + if (ival < MIN_SPEED) + ival = MIN_SPEED; + if (ival > MAX_SPEED) + ival = MAX_SPEED; + if (rport) + rport->sw_framerate = ival; + if (wport) + wport->sw_framerate = ival; + } else + ival = aport->sw_framerate; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_STEREO: /* _SIOWR('P', 3, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_STEREO %d\n", ival); + if (ival != 0 && ival != 1) + return -EINVAL; + if (aport->swstate != SW_INITIAL) + return -EINVAL; + if (rport) + rport->sw_channels = ival + 1; + if (wport) + wport->sw_channels = ival + 1; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_CHANNELS: /* _SIOWR('P', 6, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_CHANNELS %d\n", ival); + if (ival != 1 && ival != 2) + return -EINVAL; + if (aport->swstate != SW_INITIAL) + return -EINVAL; + if (rport) + rport->sw_channels = ival; + if (wport) + wport->sw_channels = ival; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETBLKSIZE: /* _SIOWR('P', 4, int) */ + ival = pcm_setup(devc, rport, wport); + if (ival < 0) + return ival; + ival = 1 << aport->sw_fragshift; + DBGX("SNDCTL_DSP_GETBLKSIZE returning %d\n", ival); + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SETFRAGMENT: /* _SIOWR('P',10, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SETFRAGMENT %d:%d\n", + ival >> 16, ival & 0xFFFF); + DBGP("aport = 0x%p\n", aport); + if (aport->swstate != SW_INITIAL) + return -EINVAL; + { + int sw_fragshift = ival & 0xFFFF; + int sw_subdivshift = aport->sw_subdivshift; + int hw_fragshift = sw_fragshift - sw_subdivshift; + int sw_fragcount = (ival >> 16) & 0xFFFF; + int hw_fragsize; + if (hw_fragshift < MIN_FRAGSHIFT) + hw_fragshift = MIN_FRAGSHIFT; + if (hw_fragshift > MAX_FRAGSHIFT) + hw_fragshift = MAX_FRAGSHIFT; + sw_fragshift = hw_fragshift + aport->sw_subdivshift; + hw_fragsize = 1 << hw_fragshift; + if (sw_fragcount < MIN_FRAGCOUNT(hw_fragsize)) + sw_fragcount = MIN_FRAGCOUNT(hw_fragsize); + if (sw_fragcount > MAX_FRAGCOUNT(hw_fragsize)) + sw_fragcount = MAX_FRAGCOUNT(hw_fragsize); + DBGP("sw_fragshift = %d\n", sw_fragshift); + DBGP("rport = 0x%p, wport = 0x%p\n", rport, wport); + if (rport) { + rport->sw_fragshift = sw_fragshift; + rport->sw_fragcount = sw_fragcount; + } + if (wport) { + wport->sw_fragshift = sw_fragshift; + wport->sw_fragcount = sw_fragcount; + } + ival = sw_fragcount << 16 | sw_fragshift; + } + DBGX("SNDCTL_DSP_SETFRAGMENT returns %d:%d\n", + ival >> 16, ival & 0xFFFF); + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SUBDIVIDE: /* _SIOWR('P', 9, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + if (aport->swstate != SW_INITIAL) + return -EINVAL; + { + int subdivshift; + int hw_fragshift, hw_fragsize, hw_fragcount; + switch (ival) { + case 1: subdivshift = 0; break; + case 2: subdivshift = 1; break; + case 4: subdivshift = 2; break; + default: return -EINVAL; + } + hw_fragshift = aport->sw_fragshift - subdivshift; + if (hw_fragshift < MIN_FRAGSHIFT || + hw_fragshift > MAX_FRAGSHIFT) + return -EINVAL; + hw_fragsize = 1 << hw_fragshift; + hw_fragcount = aport->sw_fragcount >> subdivshift; + if (hw_fragcount < MIN_FRAGCOUNT(hw_fragsize) || + hw_fragcount > MAX_FRAGCOUNT(hw_fragsize)) + return -EINVAL; + if (rport) + rport->sw_subdivshift = subdivshift; + if (wport) + wport->sw_subdivshift = subdivshift; + } + return 0; + + case SNDCTL_DSP_SETFMT: /* _SIOWR('P',5, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SETFMT %d\n", ival); + if (ival != AFMT_QUERY) { + if (aport->swstate != SW_INITIAL) { + DBGP("SETFMT failed, swstate = %d\n", + aport->swstate); + return -EINVAL; + } + switch (ival) { + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + case AFMT_S16_LE: + if (rport) + rport->sw_samplefmt = ival; + if (wport) + wport->sw_samplefmt = ival; + break; + default: + return -EINVAL; + } + } + ival = aport->sw_samplefmt; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETOSPACE: /* _SIOR ('P',12, audio_buf_info) */ + if (!wport) + return -EINVAL; + ival = pcm_setup(devc, rport, wport); + if (ival < 0) + return ival; + ival = swb_inc_u(wport, 0); + buf_info.fragments = ival >> wport->sw_fragshift; + buf_info.fragstotal = wport->sw_fragcount; + buf_info.fragsize = 1 << wport->sw_fragshift; + buf_info.bytes = ival; + DBGXV("SNDCTL_DSP_GETOSPACE returns { %d %d %d %d }\n", + buf_info.fragments, buf_info.fragstotal, + buf_info.fragsize, buf_info.bytes); + return copy_to_user((void *) arg, &buf_info, sizeof buf_info); + + case SNDCTL_DSP_GETISPACE: /* _SIOR ('P',13, audio_buf_info) */ + if (!rport) + return -EINVAL; + ival = pcm_setup(devc, rport, wport); + if (ival < 0) + return ival; + ival = swb_inc_u(rport, 0); + buf_info.fragments = ival >> rport->sw_fragshift; + buf_info.fragstotal = rport->sw_fragcount; + buf_info.fragsize = 1 << rport->sw_fragshift; + buf_info.bytes = ival; + return copy_to_user((void *) arg, &buf_info, sizeof buf_info); + + case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */ + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */ + DBGX("SNDCTL_DSP_RESET\n"); + if (rport && rport->swbuf) { + /* XXX flush input */ + /* XXX write me */ + } + if (wport && wport->swbuf) { + wport->swstate = SW_INITIAL; + pcm_output(devc, 0, 0); + pcm_write_sync(devc); + } + pcm_shutdown(devc, rport, wport); + return 0; + + case SNDCTL_DSP_SYNC: /* _SIO ('P', 1) */ + DBGX("SNDCTL_DSP_SYNC\n"); + if (wport) { + pcm_flush_frag(devc); + pcm_write_sync(devc); + } + pcm_shutdown(devc, rport, wport); + return 0; + + case SNDCTL_DSP_POST: /* _SIO ('P', 8) */ + DBGX("SNDCTL_DSP_POST\n"); + if (!wport) + return -EINVAL; + pcm_flush_frag(devc); + return 0; + + case SNDCTL_DSP_GETIPTR: /* _SIOR ('P', 17, count_info) */ + /* XXX write me */ + break; + + case SNDCTL_DSP_GETOPTR: /* _SIOR ('P',18, count_info) */ + /* XXX write me */ + break; + + case SNDCTL_DSP_GETODELAY: /* _SIOR ('P', 23, int) */ + /* XXX write me */ + break; + + case SNDCTL_DSP_PROFILE: /* _SIOW ('P', 23, int) */ + /* XXX write me */ + break; + + case SNDCTL_DSP_GETTRIGGER: /* _SIOR ('P',16, int) */ + ival = 0; + if (rport) { + unsigned long flags; + spin_lock_irqsave(&rport->lock, flags); + { + if (!(rport->flags & DISABLED)) + ival |= PCM_ENABLE_INPUT; + } + spin_unlock_irqrestore(&rport->lock, flags); + } + if (wport) { + unsigned long flags; + spin_lock_irqsave(&wport->lock, flags); + { + if (!(wport->flags & DISABLED)) + ival |= PCM_ENABLE_OUTPUT; + } + spin_unlock_irqrestore(&wport->lock, flags); + } + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SETTRIGGER: /* _SIOW ('P',16, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + + /* + * If user is disabling I/O and port is not in initial + * state, fail with EINVAL. + */ + + if (((rport && !(ival & PCM_ENABLE_INPUT)) || + (wport && !(ival & PCM_ENABLE_OUTPUT))) && + aport->swstate != SW_INITIAL) + return -EINVAL; + + if (rport) { + unsigned long iflags; + vwsnd_port_flags_t pflags; + spin_lock_irqsave(&rport->lock, iflags); + { + pflags = rport->flags; + if (ival & PCM_ENABLE_INPUT) + rport->flags &= ~DISABLED; + else + rport->flags |= DISABLED; + } + spin_unlock_irqrestore(&rport->lock, iflags); + if (pflags & DISABLED && ival & PCM_ENABLE_INPUT) + li_activate_dma(&rport->chan); + } + if (wport) { + unsigned long iflags; + vwsnd_port_flags_t pflags; + spin_lock_irqsave(&wport->lock, iflags); + { + pflags = wport->flags; + if (ival & PCM_ENABLE_OUTPUT) + wport->flags &= ~DISABLED; + else + wport->flags |= DISABLED; + } + spin_unlock_irqrestore(&wport->lock, iflags); + if (pflags & DISABLED && ival & PCM_ENABLE_OUTPUT) + pcm_output(devc, 0, 0); + } + return 0; + + default: + DBGP("unknown ioctl 0x%x\n", cmd); + return -EINVAL; + } + DBGP("unimplemented ioctl 0x%x\n", cmd); + return -EINVAL; +} + +static int vwsnd_audio_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + int ret; + + down(&devc->io_sema); + ret = vwsnd_audio_do_ioctl(inode, file, cmd, arg); + up(&devc->io_sema); + return ret; +} + +/* No mmap. */ + +static int vwsnd_audio_mmap(struct file *file, struct vm_area_struct *vma) +{ + DBGE("(file=0x%p, vma=0x%p)\n", file, vma); + return -ENODEV; +} + +/* + * Open the audio device for read and/or write. + * + * Returns 0 on success, -errno on failure. + */ + +static int vwsnd_audio_open(struct inode *inode, struct file *file) +{ + vwsnd_dev_t *devc; + dev_t minor = MINOR(inode->i_rdev); + int sw_samplefmt; + + DBGE("(inode=0x%p, file=0x%p)\n", inode, file); + + INC_USE_COUNT; + for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) + if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) + break; + + if (devc == NULL) { + DEC_USE_COUNT; + return -ENODEV; + } + + down(&devc->open_sema); + while (devc->open_mode & file->f_mode) { + up(&devc->open_sema); + if (file->f_flags & O_NONBLOCK) { + DEC_USE_COUNT; + return -EBUSY; + } + interruptible_sleep_on(&devc->open_wait); + if (signal_pending(current)) { + DEC_USE_COUNT; + return -ERESTARTSYS; + } + down(&devc->open_sema); + } + devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + up(&devc->open_sema); + + /* get default sample format from minor number. */ + + sw_samplefmt = 0; + if ((minor & 0xF) == SND_DEV_DSP) + sw_samplefmt = AFMT_U8; + else if ((minor & 0xF) == SND_DEV_AUDIO) + sw_samplefmt = AFMT_MU_LAW; + else if ((minor & 0xF) == SND_DEV_DSP16) + sw_samplefmt = AFMT_S16_LE; + else + ASSERT(0); + + /* Initialize vwsnd_ports. */ + + down(&devc->io_sema); + { + if (file->f_mode & FMODE_READ) { + devc->rport.swstate = SW_INITIAL; + devc->rport.sw_channels = 1; + devc->rport.sw_samplefmt = sw_samplefmt; + devc->rport.sw_framerate = 8000; + devc->rport.sw_fragshift = DEFAULT_FRAGSHIFT; + devc->rport.sw_fragcount = DEFAULT_FRAGCOUNT; + devc->rport.sw_subdivshift = DEFAULT_SUBDIVSHIFT; + } + if (file->f_mode & FMODE_WRITE) { + devc->wport.swstate = SW_INITIAL; + devc->wport.sw_channels = 1; + devc->wport.sw_samplefmt = sw_samplefmt; + devc->wport.sw_framerate = 8000; + devc->wport.sw_fragshift = DEFAULT_FRAGSHIFT; + devc->wport.sw_fragcount = DEFAULT_FRAGCOUNT; + devc->wport.sw_subdivshift = DEFAULT_SUBDIVSHIFT; + } + } + up(&devc->io_sema); + + file->private_data = devc; + DBGRV(); + return 0; +} + +/* + * Release (close) the audio device. + */ + +static int vwsnd_audio_release(struct inode *inode, struct file *file) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + vwsnd_port_t *wport = NULL, *rport = NULL; + int err = 0; + + down(&devc->io_sema); + { + DBGE("(inode=0x%p, file=0x%p)\n", inode, file); + + if (file->f_mode & FMODE_READ) + rport = &devc->rport; + if (file->f_mode & FMODE_WRITE) { + wport = &devc->wport; + pcm_flush_frag(devc); + pcm_write_sync(devc); + } + pcm_shutdown(devc, rport, wport); + if (rport) + rport->swstate = SW_OFF; + if (wport) + wport->swstate = SW_OFF; + } + up(&devc->io_sema); + + down(&devc->open_sema); + { + devc->open_mode &= ~file->f_mode; + } + up(&devc->open_sema); + wake_up(&devc->open_wait); + DBGDO(if (IN_USE)) /* see hack in vwsnd_mixer_release() */ + DEC_USE_COUNT; + DBGR(); + return err; +} + +static struct file_operations vwsnd_audio_fops = { + &vwsnd_audio_llseek, + &vwsnd_audio_read, + &vwsnd_audio_write, + NULL, /* readdir */ + &vwsnd_audio_poll, + &vwsnd_audio_ioctl, + &vwsnd_audio_mmap, + &vwsnd_audio_open, + NULL, /* flush */ + &vwsnd_audio_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +/*****************************************************************************/ +/* mixer driver */ + +/* open the mixer device. */ + +static int vwsnd_mixer_open(struct inode *inode, struct file *file) +{ + vwsnd_dev_t *devc; + + DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); + + INC_USE_COUNT; + for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) + if (devc->mixer_minor == MINOR(inode->i_rdev)) + break; + + if (devc == NULL) { + DEC_USE_COUNT; + return -ENODEV; + } + file->private_data = devc; + return 0; +} + +/* release (close) the mixer device. */ + +static int vwsnd_mixer_release(struct inode *inode, struct file *file) +{ + DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); + + /* + * hack -- opening/closing the mixer device zeroes use count + * so driver can be unloaded. + * Use only while debugging module, and then use it carefully. + */ + + DBGDO(while (IN_USE)) + DEC_USE_COUNT; + return 0; +} + +/* seek is illegal on mixer. */ + +static loff_t vwsnd_mixer_llseek(struct file *file, loff_t offset, int whence) +{ + return -ESPIPE; +} + +/* mixer_read_ioctl handles all read ioctls on the mixer device. */ + +static int mixer_read_ioctl(vwsnd_dev_t *devc, unsigned int nr, caddr_t arg) +{ + int val = -1; + + DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg); + + switch (nr) { + case SOUND_MIXER_CAPS: + val = SOUND_CAP_EXCL_INPUT; + break; + + case SOUND_MIXER_DEVMASK: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV); + break; + + case SOUND_MIXER_STEREODEVS: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV); + break; + + case SOUND_MIXER_OUTMASK: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD); + break; + + case SOUND_MIXER_RECMASK: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD); + break; + + case SOUND_MIXER_PCM: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_PCM); + break; + + case SOUND_MIXER_LINE: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_LINE); + break; + + case SOUND_MIXER_MIC: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_MIC); + break; + + case SOUND_MIXER_CD: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_CD); + break; + + case SOUND_MIXER_RECLEV: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_RECLEV); + break; + + case SOUND_MIXER_RECSRC: + val = ad1843_get_recsrc(&devc->lith); + break; + + case SOUND_MIXER_OUTSRC: + val = ad1843_get_outsrc(&devc->lith); + break; + + default: + return -EINVAL; + } + return put_user(val, (int *) arg); +} + +/* mixer_write_ioctl handles all write ioctls on the mixer device. */ + +static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, caddr_t arg) +{ + int val; + int err; + + DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg); + + err = get_user(val, (int *) arg); + if (err) + return -EFAULT; + switch (nr) { + case SOUND_MIXER_PCM: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_PCM, val); + break; + + case SOUND_MIXER_LINE: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_LINE, val); + break; + + case SOUND_MIXER_MIC: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_MIC, val); + break; + + case SOUND_MIXER_CD: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_CD, val); + break; + + case SOUND_MIXER_RECLEV: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_RECLEV, val); + break; + + case SOUND_MIXER_RECSRC: + if (devc->rport.swbuf || devc->wport.swbuf) + return -EBUSY; /* can't change recsrc while running */ + val = ad1843_set_recsrc(&devc->lith, val); + break; + + case SOUND_MIXER_OUTSRC: + val = ad1843_set_outsrc(&devc->lith, val); + break; + + default: + return -EINVAL; + } + if (val < 0) + return val; + return put_user(val, (int *) arg); +} + +/* This is the ioctl entry to the mixer driver. */ + +static int vwsnd_mixer_ioctl(struct inode *ioctl, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + const unsigned int nrmask = _IOC_NRMASK << _IOC_NRSHIFT; + const unsigned int nr = (cmd & nrmask) >> _IOC_NRSHIFT; + int retval; + + DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); + + down(&devc->mix_sema); + { + if ((cmd & ~nrmask) == MIXER_READ(0)) + retval = mixer_read_ioctl(devc, nr, (caddr_t) arg); + else if ((cmd & ~nrmask) == MIXER_WRITE(0)) + retval = mixer_write_ioctl(devc, nr, (caddr_t) arg); + else + retval = -EINVAL; + } + up(&devc->mix_sema); + return retval; +} + +static struct file_operations vwsnd_mixer_fops = { + &vwsnd_mixer_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &vwsnd_mixer_ioctl, + NULL, /* mmap */ + &vwsnd_mixer_open, + NULL, /* flush */ + &vwsnd_mixer_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +/*****************************************************************************/ +/* probe/attach/unload */ + +/* driver probe routine. Return nonzero if hardware is found. */ + +static int probe_vwsnd(struct address_info *hw_config) +{ + lithium_t lith; + int w; + unsigned long later; + + DBGEV("(hw_config=0x%p)\n", hw_config); + + /* XXX verify lithium present (to prevent crash on non-vw) */ + + if (li_create(&lith, hw_config->io_base) != 0) { + printk(KERN_WARNING "probe_vwsnd: can't map lithium\n"); + return 0; + } + later = jiffies + 2; + li_writel(&lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE); + do { + w = li_readl(&lith, LI_HOST_CONTROLLER); + } while (w == LI_HC_LINK_ENABLE && jiffies < later); + + li_destroy(&lith); + + DBGPV("HC = 0x%04x\n", w); + + if ((w == LI_HC_LINK_ENABLE) || (w & LI_HC_LINK_CODEC)) { + + /* This may indicate a beta machine with no audio, + * or a future machine with different audio. + * On beta-release 320 w/ no audio, HC == 0x4000 */ + + printk(KERN_WARNING "probe_vwsnd: audio codec not found\n"); + return 0; + } + + if (w & LI_HC_LINK_FAILURE) { + printk(KERN_WARNING "probe_vwsnd: can't init audio codec\n"); + return 0; + } + + printk(KERN_INFO "probe_vwsnd: lithium audio found\n"); + + return 1; +} + +/* + * driver attach routine. Initialize driver data structures and + * initialize hardware. A new vwsnd_dev_t is allocated and put + * onto the global list, vwsnd_dev_list. + * + * Return +minor_dev on success, -errno on failure. + */ + +static int attach_vwsnd(struct address_info *hw_config) +{ + vwsnd_dev_t *devc = NULL; + int err = -ENOMEM; + + DBGEV("(hw_config=0x%p)\n", hw_config); + + devc = kmalloc(sizeof (vwsnd_dev_t), GFP_KERNEL); + if (devc == NULL) + goto fail0; + + err = li_create(&devc->lith, hw_config->io_base); + if (err) + goto fail1; + + init_waitqueue(&devc->open_wait); + + devc->rport.hwbuf_size = HWBUF_SIZE; + devc->rport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER); + if (!devc->rport.hwbuf_vaddr) + goto fail2; + devc->rport.hwbuf = (caddr_t) devc->rport.hwbuf_vaddr; + devc->rport.hwbuf_paddr = virt_to_phys(devc->rport.hwbuf); + + /* + * Quote from the NT driver: + * + * // WARNING!!! HACK to setup output dma!!! + * // This is required because even on output there is some data + * // trickling into the input DMA channel. This is a bug in the + * // Lithium microcode. + * // --sde + * + * We set the input side's DMA base address here. It will remain + * valid until the driver is unloaded. + */ + + li_writel(&devc->lith, LI_COMM1_BASE, + devc->rport.hwbuf_paddr >> 8 | 1 << (37 - 8)); + + devc->wport.hwbuf_size = HWBUF_SIZE; + devc->wport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER); + if (!devc->wport.hwbuf_vaddr) + goto fail3; + devc->wport.hwbuf = (caddr_t) devc->wport.hwbuf_vaddr; + devc->wport.hwbuf_paddr = virt_to_phys(devc->wport.hwbuf); + DBGP("wport hwbuf = 0x%p\n", devc->wport.hwbuf); + + DBGDO(shut_up++); + err = ad1843_init(&devc->lith); + DBGDO(shut_up--); + if (err) + goto fail4; + + /* install interrupt handler */ + + err = request_irq(hw_config->irq, vwsnd_audio_intr, 0, "vwsnd", devc); + if (err) + goto fail5; + + /* register this device's drivers. */ + + devc->audio_minor = register_sound_dsp(&vwsnd_audio_fops, -1); + if ((err = devc->audio_minor) < 0) { + DBGDO(printk(KERN_WARNING + "attach_vwsnd: register_sound_dsp error %d\n", + err)); + goto fail6; + } + devc->mixer_minor = register_sound_mixer(&vwsnd_mixer_fops, + devc->audio_minor >> 4); + if ((err = devc->mixer_minor) < 0) { + DBGDO(printk(KERN_WARNING + "attach_vwsnd: register_sound_mixer error %d\n", + err)); + goto fail7; + } + + /* Squirrel away device indices for unload routine. */ + + hw_config->slots[0] = devc->audio_minor; + + /* Initialize as much of *devc as possible */ + + devc->open_sema = MUTEX; + devc->io_sema = MUTEX; + devc->mix_sema = MUTEX; + devc->open_mode = 0; + devc->rport.lock = SPIN_LOCK_UNLOCKED; + init_waitqueue(&devc->rport.queue); + devc->rport.swstate = SW_OFF; + devc->rport.hwstate = HW_STOPPED; + devc->rport.flags = 0; + devc->rport.swbuf = NULL; + devc->wport.lock = SPIN_LOCK_UNLOCKED; + init_waitqueue(&devc->wport.queue); + devc->wport.swstate = SW_OFF; + devc->wport.hwstate = HW_STOPPED; + devc->wport.flags = 0; + devc->wport.swbuf = NULL; + + /* Success. Link us onto the local device list. */ + + devc->next_dev = vwsnd_dev_list; + vwsnd_dev_list = devc; + return devc->audio_minor; + + /* So many ways to fail. Undo what we did. */ + + fail7: + unregister_sound_dsp(devc->audio_minor); + fail6: + free_irq(hw_config->irq, devc); + fail5: + fail4: + free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER); + fail3: + free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER); + fail2: + li_destroy(&devc->lith); + fail1: + kfree(devc); + fail0: + return err; +} + +static int unload_vwsnd(struct address_info *hw_config) +{ + vwsnd_dev_t *devc, **devcp; + + DBGE("()\n"); + + if (IN_USE) + return -EBUSY; + devcp = &vwsnd_dev_list; + while ((devc = *devcp)) { + if (devc->audio_minor == hw_config->slots[0]) { + *devcp = devc->next_dev; + break; + } + devcp = &devc->next_dev; + } + + if (!devc) + return -ENODEV; + + unregister_sound_mixer(devc->mixer_minor); + unregister_sound_dsp(devc->audio_minor); + free_irq(hw_config->irq, devc); + free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER); + free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER); + li_destroy(&devc->lith); + kfree(devc); + + return 0; +} + +/*****************************************************************************/ +/* initialization and loadable kernel module interface */ + +static struct address_info the_hw_config = { + 0xFF001000, /* lithium phys addr */ + CO_IRQ(CO_APIC_LI_AUDIO) /* irq */ +}; + +#ifdef MODULE + +MODULE_DESCRIPTION("SGI Visual Workstation sound module"); +MODULE_AUTHOR("Bob Miller "); + +extern int init_module(void) +{ + int err; + + DBGXV("\n"); + DBGXV("sound::vwsnd::init_module()\n"); + + if(!probe_vwsnd(&the_hw_config)) + return -ENODEV; + err = attach_vwsnd(&the_hw_config); + if (err < 0) + return err; + return 0; +} + +extern void cleanup_module(void) +{ + DBGX("sound::vwsnd::cleanup_module()\n"); + + unload_vwsnd(&the_hw_config); +} + +#else + +extern void init_vwsnd(void) +{ + DBGX("sound::vwsnd::init_vwsnd()\n"); + if (probe_vwsnd(&the_hw_config)) + (void) attach_vwsnd(&the_hw_config); +} + +#endif /* !MODULE */ + +/* + * Local variables: + * compile-command: "cd ../..; make modules SUBDIRS=drivers/sound" + * c-basic-offset: 8 + * End: + */ diff -Naur linux.2210/drivers/usb/uhci.c linux.2210.vw/drivers/usb/uhci.c --- linux.2210/drivers/usb/uhci.c Fri Apr 30 08:20:53 1999 +++ linux.2210.vw/drivers/usb/uhci.c Wed Jul 28 08:56:42 1999 @@ -624,7 +624,9 @@ struct uhci_device *dev; unsigned short status; +#if 0 printk("uhci_connect_change: called for %d\n", nr); +#endif /* * Even if the status says we're connected, diff -Naur linux.2210/drivers/usb/usb.c linux.2210.vw/drivers/usb/usb.c --- linux.2210/drivers/usb/usb.c Fri May 7 15:16:04 1999 +++ linux.2210.vw/drivers/usb/usb.c Wed Jul 28 08:56:42 1999 @@ -124,22 +124,28 @@ if (n_len < 2 || n_len > len) { +#if 0 printk("Short descriptor.\n"); +#endif return -1; } +#if 0 printk( "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n", desctype, descindex, (n_desc >> 8) & 0xFF, n_desc & 0xFF); for (i = 0 ; i < n_len; i++) printk(" %d %02x\n", i, ptr[i]); +#endif len -= n_len; ptr += n_len; parsed += n_len; } +#if 0 printk("Found %02X:%02X\n", desctype, descindex); +#endif return parsed; } @@ -154,7 +160,9 @@ if (n_len < 2 || n_len > len) { +#if 0 printk("Short descriptor.\n"); +#endif return -1; } @@ -604,8 +612,10 @@ { int addr, i; +#if 0 printk("USB new device connect, assigned device number %d\n", dev->devnum); +#endif dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ diff -Naur linux.2210/drivers/video/Config.in linux.2210.vw/drivers/video/Config.in --- linux.2210/drivers/video/Config.in Tue May 11 16:30:36 1999 +++ linux.2210.vw/drivers/video/Config.in Wed Jul 28 08:56:42 1999 @@ -78,6 +78,7 @@ fi if [ "$CONFIG_VISWS" = "y" ]; then tristate 'SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW + define_bool CONFIG_BUS_I2C y fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_PCI" != "n" ]; then diff -Naur linux.2210/drivers/video/Makefile linux.2210.vw/drivers/video/Makefile --- linux.2210/drivers/video/Makefile Tue May 11 16:30:36 1999 +++ linux.2210.vw/drivers/video/Makefile Wed Jul 28 08:56:42 1999 @@ -141,10 +141,10 @@ endif ifeq ($(CONFIG_FB_SGIVW),y) -L_OBJS += sgivwfb.o +LX_OBJS += sgivwfb.o else ifeq ($(CONFIG_FB_SGIVW),m) - M_OBJS += sgivwfb.o + MX_OBJS += sgivwfb.o endif endif diff -Naur linux.2210/drivers/video/sgivwfb.c linux.2210.vw/drivers/video/sgivwfb.c --- linux.2210/drivers/video/sgivwfb.c Fri Apr 16 08:20:23 1999 +++ linux.2210.vw/drivers/video/sgivwfb.c Wed Jul 28 08:56:42 1999 @@ -1,8 +1,8 @@ /* * linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device * - * Copyright (C) 1999 Silicon Graphics, Inc. - * Jeffrey Newquist, newquist@engr.sgi.som + * Copyright (C) 1999 Silicon Graphics, Inc. + * Jeffrey Newquist, newquist@engr.sgi.com * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -25,32 +25,63 @@ #include #include #include +#include #include