Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 15 Oct 2007 20:41:39 +0000 (13:41 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 15 Oct 2007 20:41:39 +0000 (13:41 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (40 commits)
  Input: use full RCU API
  Input: remove tsdev interface
  Input: add support for Blackfin BF54x Keypad controller
  Input: appletouch - another fix for idle reset logic
  HWMON: hdaps - switch to using input-polldev
  Input: add support for SEGA Dreamcast keyboard
  Input: omap-keyboard - don't pretend we support changing keymap
  Input: lifebook - fix X and Y axis range
  Input: usbtouchscreen - add support for GeneralTouch devices
  Input: fix open count handling in input interfaces
  Input: keyboard - add CapsShift lock
  Input: adbhid - produce all CapsLock key events
  Input: ALPS - add signature for ThinkPad R61
  Input: jornada720_kbd - send MSC_SCAN events
  Input: add support for the HP Jornada 7xx (710/720/728) touchscreen
  Input: add support for HP Jornada 7xx onboard keyboard
  Input: add support for HP Jornada onboard keyboard (HP6XX)
  Input: ucb1400_ts - use schedule_timeout_uninterruptible
  Input: xpad - fix dependancy on LEDS class
  Input: auto-select INPUT for MAC_EMUMOUSEBTN option
  ...

Resolved conflicts manually in drivers/hwmon/applesmc.c: converting from
a class device to a device and converting to use input-polldev created a
few apparently trivial clashes..

1082 files changed:
Documentation/DocBook/deviceiobook.tmpl
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/kernel-hacking.tmpl
Documentation/DocBook/mcabook.tmpl
Documentation/DocBook/mtdnand.tmpl
Documentation/hwmon/coretemp
Documentation/hwmon/dme1737
Documentation/hwmon/f71805f
Documentation/hwmon/it87
Documentation/hwmon/lm78
Documentation/hwmon/lm93
Documentation/hwmon/sysfs-interface
Documentation/hwmon/w83791d
Documentation/i2c/busses/i2c-i801
Documentation/i2c/chips/pcf8574
Documentation/i2c/dev-interface
Documentation/i2c/i2c-stub
Documentation/kernel-parameters.txt
Documentation/networking/bonding.txt
Documentation/sched-design-CFS.txt
Documentation/scsi/00-INDEX
Documentation/scsi/ChangeLog.arcmsr
Documentation/scsi/aacraid.txt
Documentation/scsi/advansys.txt [new file with mode: 0644]
Documentation/sparc/sbus_drivers.txt
MAINTAINERS
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-osk.c
arch/i386/Kconfig
arch/ia64/Kconfig
arch/ia64/configs/sn2_defconfig
arch/ia64/hp/common/Makefile
arch/ia64/hp/common/aml_nfw.c [new file with mode: 0644]
arch/ia64/hp/sim/simscsi.c
arch/ia64/kernel/crash.c
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/mca_drv.h
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/topology.c
arch/m68k/atari/atakeyb.c
arch/mips/au1000/common/prom.c
arch/mips/au1000/common/setup.c
arch/mips/au1000/db1x00/init.c
arch/mips/au1000/mtx-1/init.c
arch/mips/au1000/pb1000/init.c
arch/mips/au1000/pb1100/init.c
arch/mips/au1000/pb1200/board_setup.c
arch/mips/au1000/pb1200/init.c
arch/mips/au1000/pb1500/init.c
arch/mips/au1000/pb1550/init.c
arch/mips/au1000/xxs1500/init.c
arch/mips/kernel/smp.c
arch/mips/mm/tlbex.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/sysdev/dcr.c
arch/powerpc/sysdev/mpic.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/sh/Kconfig
arch/sh/Kconfig.debug
arch/sh/Makefile
arch/sh/boards/hp6xx/hp6xx_apm.c
arch/sh/boards/hp6xx/setup.c
arch/sh/boards/magicpanelr2/Kconfig [new file with mode: 0644]
arch/sh/boards/magicpanelr2/Makefile [new file with mode: 0644]
arch/sh/boards/magicpanelr2/setup.c [new file with mode: 0644]
arch/sh/boards/mpc1211/setup.c
arch/sh/boards/renesas/r7780rp/Makefile
arch/sh/boards/renesas/r7780rp/irq-r7780mp.c [new file with mode: 0644]
arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
arch/sh/boards/renesas/r7780rp/setup.c
arch/sh/boards/renesas/rts7751r2d/Kconfig
arch/sh/boards/renesas/rts7751r2d/irq.c
arch/sh/boards/renesas/rts7751r2d/setup.c
arch/sh/boards/renesas/x3proto/Makefile [new file with mode: 0644]
arch/sh/boards/renesas/x3proto/ilsel.c [new file with mode: 0644]
arch/sh/boards/renesas/x3proto/setup.c [new file with mode: 0644]
arch/sh/boards/se/7206/io.c
arch/sh/boards/se/7206/setup.c
arch/sh/boards/se/7343/irq.c
arch/sh/boards/se/7343/setup.c
arch/sh/boards/se/770x/setup.c
arch/sh/boards/se/7722/setup.c
arch/sh/boards/se/7751/setup.c
arch/sh/boards/se/7780/irq.c
arch/sh/boards/se/7780/setup.c
arch/sh/boards/sh03/setup.c
arch/sh/boards/shmin/setup.c
arch/sh/boards/snapgear/setup.c
arch/sh/boards/titan/setup.c
arch/sh/cchips/Kconfig
arch/sh/cchips/hd6446x/hd64461.c
arch/sh/cchips/hd6446x/hd64465/setup.c
arch/sh/cchips/voyagergx/irq.c
arch/sh/configs/dreamcast_defconfig
arch/sh/configs/hp6xx_defconfig
arch/sh/configs/magicpanelr2_defconfig [new file with mode: 0644]
arch/sh/configs/rts7751r2d1_defconfig [moved from arch/sh/configs/rts7751r2d_defconfig with 85% similarity]
arch/sh/configs/rts7751r2dplus_defconfig [new file with mode: 0644]
arch/sh/configs/se7206_defconfig
arch/sh/configs/shx3_defconfig
arch/sh/drivers/dma/Kconfig
arch/sh/drivers/dma/dma-sh.c
arch/sh/drivers/heartbeat.c
arch/sh/drivers/pci/ops-rts7751r2d.c
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/init.c
arch/sh/kernel/cpu/irq/Makefile
arch/sh/kernel/cpu/irq/intc.c
arch/sh/kernel/cpu/irq/intc2.c [deleted file]
arch/sh/kernel/cpu/sh2/probe.c
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/probe.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh3/Makefile
arch/sh/kernel/cpu/sh3/probe.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh7708.c [deleted file]
arch/sh/kernel/cpu/sh3/setup-sh7709.c [deleted file]
arch/sh/kernel/cpu/sh3/setup-sh770x.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4/probe.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4/sq.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh4a/smp-shx3.c [new file with mode: 0644]
arch/sh/kernel/cpufreq.c
arch/sh/kernel/early_printk.c
arch/sh/kernel/entry-common.S
arch/sh/kernel/head.S
arch/sh/kernel/kgdb_stub.c
arch/sh/kernel/process.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_ksyms.c
arch/sh/kernel/signal.c
arch/sh/kernel/smp.c
arch/sh/kernel/syscalls.S
arch/sh/kernel/timers/timer-tmu.c
arch/sh/kernel/traps.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/mm/Kconfig
arch/sh/mm/Makefile
arch/sh/mm/cache-sh4.c
arch/sh/mm/copy_page.S
arch/sh/mm/fault-nommu.c [deleted file]
arch/sh/mm/pmb.c
arch/sh/mm/tlb-sh4.c
arch/sh64/Kconfig
arch/sh64/Kconfig.debug
arch/sh64/Makefile
arch/sh64/configs/cayman_defconfig
arch/sh64/configs/harp_defconfig [new file with mode: 0644]
arch/sh64/configs/sim_defconfig [new file with mode: 0644]
arch/sh64/kernel/Makefile
arch/sh64/kernel/alphanum.c
arch/sh64/kernel/sh_ksyms.c
arch/sh64/kernel/time.c
arch/sh64/kernel/vmlinux.lds.S
arch/sh64/lib/c-checksum.c
arch/sh64/lib/io.c
arch/sh64/lib/iomap.c
arch/sh64/mach-cayman/setup.c
arch/sh64/mach-harp/Makefile
arch/sh64/mach-harp/setup.c
arch/sh64/mach-romram/Makefile [deleted file]
arch/sh64/mach-romram/setup.c [deleted file]
arch/sh64/mach-sim/Makefile
arch/sh64/mach-sim/setup.c
arch/sh64/mm/Makefile
arch/sh64/mm/consistent.c [moved from arch/sh64/kernel/pci-dma.c with 92% similarity]
arch/sh64/mm/init.c
arch/sh64/mm/ioremap.c
arch/sparc/Kconfig.debug
arch/sparc/kernel/irq.c
arch/sparc/kernel/of_device.c
arch/sparc/kernel/time.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/of_device.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/pci_fire.c
arch/sparc64/kernel/pci_impl.h
arch/sparc64/kernel/pci_msi.c [new file with mode: 0644]
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_schizo.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/power.c
arch/sparc64/kernel/sun4v_ivec.S
arch/sparc64/kernel/sys_sparc.c
arch/sparc64/kernel/time.c
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/vmlinux.lds.S
arch/sparc64/lib/xor.S
arch/sparc64/mm/init.c
arch/um/Makefile
arch/um/Makefile-i386
arch/um/Makefile-x86_64
arch/um/scripts/Makefile.rules
arch/um/sys-i386/Makefile
arch/um/sys-x86_64/Makefile
arch/x86/kernel/alternative.c
arch/x86/kernel/apic_64.c
arch/x86/kernel/bugs_64.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/crash_dump_32.c
arch/x86/kernel/crash_dump_64.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/head64.c
arch/x86/kernel/i387_32.c
arch/x86/kernel/i387_64.c
arch/x86/kernel/i8237.c
arch/x86/kernel/i8253.c
arch/x86/kernel/ioport_32.c
arch/x86/kernel/ioport_64.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/irq_64.c
arch/x86/kernel/kprobes_32.c
arch/x86/kernel/kprobes_64.c
arch/x86/kernel/ldt_32.c
arch/x86/kernel/ldt_64.c
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/mca_32.c
arch/x86/kernel/msr.c
arch/x86/kernel/nmi_32.c
arch/x86/kernel/nmi_64.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace_32.c
arch/x86/kernel/ptrace_64.c
arch/x86/kernel/reboot_32.c
arch/x86/kernel/reboot_fixups_32.c
arch/x86/kernel/scx200_32.c
arch/x86/kernel/setup_32.c
arch/x86/kernel/setup_64.c
arch/x86/kernel/signal_32.c
arch/x86/kernel/signal_64.c
arch/x86/kernel/smpboot_64.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/summit_32.c
arch/x86/kernel/sys_i386_32.c
arch/x86/kernel/sys_x86_64.c
arch/x86/kernel/sysenter_32.c
arch/x86/kernel/time_32.c
arch/x86/kernel/time_64.c
arch/x86/kernel/topology.c
arch/x86/kernel/traps_32.c
arch/x86/kernel/traps_64.c
arch/x86/kernel/tsc_32.c
arch/x86/kernel/tsc_sync.c
arch/x86/kernel/vm86_32.c
arch/x86/kernel/vsyscall_64.c
arch/x86/lib/copy_user_nocache_64.S
arch/x86/lib/thunk_64.S
arch/x86/pci/acpi.c
drivers/acpi/toshiba_acpi.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/pata_cs5536.c [new file with mode: 0644]
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_sil680.c
drivers/ata/sata_nv.c
drivers/ata/sata_via.c
drivers/atm/ambassador.h
drivers/atm/firestream.c
drivers/atm/horizon.h
drivers/base/memory.c
drivers/block/cciss.c
drivers/char/agp/agp.h
drivers/char/agp/ali-agp.c
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/backend.c
drivers/char/agp/generic.c
drivers/char/agp/i460-agp.c
drivers/char/agp/intel-agp.c
drivers/char/drm/drm.h
drivers/char/drm/drmP.h
drivers/char/drm/drm_agpsupport.c
drivers/char/drm/drm_auth.c
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_context.c
drivers/char/drm/drm_dma.c
drivers/char/drm/drm_drawable.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_fops.c
drivers/char/drm/drm_ioc32.c
drivers/char/drm/drm_ioctl.c
drivers/char/drm/drm_irq.c
drivers/char/drm/drm_lock.c
drivers/char/drm/drm_os_linux.h
drivers/char/drm/drm_pciids.h
drivers/char/drm/drm_scatter.c
drivers/char/drm/drm_vm.c
drivers/char/drm/i810_dma.c
drivers/char/drm/i810_drm.h
drivers/char/drm/i810_drv.h
drivers/char/drm/i830_dma.c
drivers/char/drm/i830_drv.h
drivers/char/drm/i830_irq.c
drivers/char/drm/i915_dma.c
drivers/char/drm/i915_drv.h
drivers/char/drm/i915_irq.c
drivers/char/drm/i915_mem.c
drivers/char/drm/mga_dma.c
drivers/char/drm/mga_drv.h
drivers/char/drm/mga_state.c
drivers/char/drm/mga_warp.c
drivers/char/drm/r128_cce.c
drivers/char/drm/r128_drm.h
drivers/char/drm/r128_drv.h
drivers/char/drm/r128_state.c
drivers/char/drm/r300_cmdbuf.c
drivers/char/drm/radeon_cp.c
drivers/char/drm/radeon_drv.h
drivers/char/drm/radeon_irq.c
drivers/char/drm/radeon_mem.c
drivers/char/drm/radeon_state.c
drivers/char/drm/savage_bci.c
drivers/char/drm/savage_drv.h
drivers/char/drm/savage_state.c
drivers/char/drm/sis_drv.c
drivers/char/drm/sis_drv.h
drivers/char/drm/sis_mm.c
drivers/char/drm/via_dma.c
drivers/char/drm/via_dmablit.c
drivers/char/drm/via_drv.h
drivers/char/drm/via_irq.c
drivers/char/drm/via_map.c
drivers/char/drm/via_mm.c
drivers/char/drm/via_verifier.c
drivers/char/drm/via_video.c
drivers/char/dsp56k.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/rio/host.h
drivers/char/riscom8.h
drivers/char/sx.h
drivers/char/synclink_gt.c
drivers/char/watchdog/mpc5200_wdt.c
drivers/eisa/eisa-bus.c
drivers/fc4/fc.c
drivers/fc4/fcp_impl.h
drivers/firewire/fw-cdev.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-input.c
drivers/hid/hidraw.c [new file with mode: 0644]
drivers/hid/usbhid/Kconfig
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-ff.c
drivers/hid/usbhid/hid-plff.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hid-tmff.c
drivers/hid/usbhid/hiddev.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/ad7418.c
drivers/hwmon/adm1021.c
drivers/hwmon/adm1025.c
drivers/hwmon/adm1026.c
drivers/hwmon/adm1029.c
drivers/hwmon/adm1031.c
drivers/hwmon/adm9240.c
drivers/hwmon/adt7470.c [new file with mode: 0644]
drivers/hwmon/applesmc.c
drivers/hwmon/asb100.c
drivers/hwmon/atxp1.c
drivers/hwmon/coretemp.c
drivers/hwmon/dme1737.c
drivers/hwmon/ds1621.c
drivers/hwmon/f71805f.c
drivers/hwmon/f71882fg.c [new file with mode: 0644]
drivers/hwmon/f75375s.c [new file with mode: 0644]
drivers/hwmon/fscher.c
drivers/hwmon/fschmd.c [new file with mode: 0644]
drivers/hwmon/fscpos.c
drivers/hwmon/gl518sm.c
drivers/hwmon/gl520sm.c
drivers/hwmon/hwmon.c
drivers/hwmon/ibmpex.c [new file with mode: 0644]
drivers/hwmon/it87.c
drivers/hwmon/k8temp.c
drivers/hwmon/lm63.c
drivers/hwmon/lm70.c
drivers/hwmon/lm75.c
drivers/hwmon/lm75.h
drivers/hwmon/lm77.c
drivers/hwmon/lm78.c
drivers/hwmon/lm80.c
drivers/hwmon/lm83.c
drivers/hwmon/lm85.c
drivers/hwmon/lm87.c
drivers/hwmon/lm90.c
drivers/hwmon/lm92.c
drivers/hwmon/lm93.c
drivers/hwmon/max1619.c
drivers/hwmon/max6650.c
drivers/hwmon/pc87360.c
drivers/hwmon/pc87427.c
drivers/hwmon/sis5595.c
drivers/hwmon/smsc47b397.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/smsc47m192.c
drivers/hwmon/thmc50.c
drivers/hwmon/via686a.c
drivers/hwmon/vt1211.c
drivers/hwmon/vt8231.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/hwmon/w83l785ts.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-davinci.c [new file with mode: 0644]
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-stub.c
drivers/i2c/chips/pcf8574.c
drivers/i2c/chips/tps65010.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/ide/Kconfig
drivers/ide/arm/icside.c
drivers/ide/cris/ide-cris.c
drivers/ide/ide-acpi.c
drivers/ide/ide-dma.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-lib.c
drivers/ide/ide-probe.c
drivers/ide/ide.c
drivers/ide/legacy/ide_platform.c
drivers/ide/mips/au1xxx-ide.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/alim15x3.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/atiixp.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/cs5520.c
drivers/ide/pci/cs5530.c
drivers/ide/pci/cs5535.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c
drivers/ide/pci/it821x.c
drivers/ide/pci/jmicron.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/sc1200.c
drivers/ide/pci/scc_pata.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/sgiioc4.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c
drivers/ide/pci/triflex.c
drivers/ide/pci/via82cxxx.c
drivers/ide/ppc/pmac.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/srp/Kconfig
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/keyboard/atakbd.c
drivers/input/mouse/atarimouse.c
drivers/input/touchscreen/ads7846.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/hfc_2bds0.c
drivers/isdn/hisax/hfc_usb.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hisax_if.h
drivers/isdn/hisax/nj_s.c
drivers/kvm/Kconfig
drivers/kvm/Makefile
drivers/kvm/i8259.c [new file with mode: 0644]
drivers/kvm/ioapic.c [new file with mode: 0644]
drivers/kvm/irq.c [new file with mode: 0644]
drivers/kvm/irq.h [new file with mode: 0644]
drivers/kvm/kvm.h
drivers/kvm/kvm_main.c
drivers/kvm/kvm_svm.h
drivers/kvm/lapic.c [new file with mode: 0644]
drivers/kvm/mmu.c
drivers/kvm/paging_tmpl.h
drivers/kvm/svm.c
drivers/kvm/vmx.c
drivers/kvm/vmx.h
drivers/kvm/x86_emulate.c
drivers/kvm/x86_emulate.h
drivers/md/dm-emc.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ov511.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/usbvision/usbvision-i2c.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/videobuf-vmalloc.c
drivers/media/video/w9968cf.c
drivers/message/fusion/Kconfig
drivers/message/fusion/lsi/mpi.h
drivers/message/fusion/lsi/mpi_cnfg.h
drivers/message/fusion/lsi/mpi_fc.h
drivers/message/fusion/lsi/mpi_history.txt
drivers/message/fusion/lsi/mpi_init.h
drivers/message/fusion/lsi/mpi_ioc.h
drivers/message/fusion/lsi/mpi_lan.h
drivers/message/fusion/lsi/mpi_log_fc.h
drivers/message/fusion/lsi/mpi_log_sas.h
drivers/message/fusion/lsi/mpi_raid.h
drivers/message/fusion/lsi/mpi_sas.h
drivers/message/fusion/lsi/mpi_targ.h
drivers/message/fusion/lsi/mpi_tool.h
drivers/message/fusion/lsi/mpi_type.h
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptctl.h
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptlan.c
drivers/message/fusion/mptlan.h
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptsas.h [new file with mode: 0644]
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h
drivers/message/fusion/mptspi.c
drivers/misc/thinkpad_acpi.c
drivers/misc/thinkpad_acpi.h
drivers/mmc/core/sdio_bus.c
drivers/mmc/host/mmc_spi.c
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/Makefile
drivers/mtd/devices/at91_dataflash26.c [deleted file]
drivers/mtd/devices/docprobe.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/pmc551.c
drivers/mtd/inftlmount.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/alchemy-flash.c
drivers/mtd/maps/intel_vr_nor.c [new file with mode: 0644]
drivers/mtd/maps/lubbock-flash.c [deleted file]
drivers/mtd/maps/mainstone-flash.c [deleted file]
drivers/mtd/maps/nettel.c
drivers/mtd/maps/ocelot.c [deleted file]
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/pmcmsp-flash.c
drivers/mtd/maps/pmcmsp-ramroot.c
drivers/mtd/maps/pq2fads.c [deleted file]
drivers/mtd/maps/pxa2xx-flash.c [new file with mode: 0644]
drivers/mtd/maps/tqm834x.c [deleted file]
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdcore.h [new file with mode: 0644]
drivers/mtd/mtdoops.c [new file with mode: 0644]
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/alauda.c [new file with mode: 0644]
drivers/mtd/nand/bf5xx_nand.c [new file with mode: 0644]
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/excite_nandflash.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/onenand/Kconfig
drivers/mtd/onenand/Makefile
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_sim.c [new file with mode: 0644]
drivers/mtd/rfd_ftl.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/kapi.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/scan.h
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/vtbl.c
drivers/mtd/ubi/wl.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/atarilance.c
drivers/net/au1000_eth.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/cassini.c
drivers/net/cpmac.c [new file with mode: 0644]
drivers/net/gianfar.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/ibm_emac/ibm_emac_mal.c
drivers/net/ibm_emac/ibm_emac_mal.h
drivers/net/ibm_newemac/core.c
drivers/net/ibm_newemac/mal.c
drivers/net/ibm_newemac/mal.h
drivers/net/ibm_newemac/rgmii.c
drivers/net/ibm_newemac/tah.c
drivers/net/ibm_newemac/zmii.c
drivers/net/ipg.c
drivers/net/ipg.h
drivers/net/irda/donauboe.c
drivers/net/jazzsonic.c
drivers/net/macmace.c
drivers/net/macvlan.c
drivers/net/mipsnet.c
drivers/net/mipsnet.h
drivers/net/mlx4/main.c
drivers/net/mv643xx_eth.c
drivers/net/mvme147.c
drivers/net/myri10ge/myri10ge.c
drivers/net/myri10ge/myri10ge_mcp.h
drivers/net/natsemi.c
drivers/net/ne-h8300.c
drivers/net/ni65.c
drivers/net/saa9730.c
drivers/net/sky2.c
drivers/net/tc35815.c
drivers/net/tehuti.c
drivers/net/tg3.c
drivers/net/tulip/de4x5.c
drivers/net/tulip/de4x5.h
drivers/net/tulip/tulip_core.c
drivers/net/ucc_geth.c
drivers/net/wan/cosa.c
drivers/net/wan/sdla.c
drivers/net/wireless/b43/phy.c
drivers/net/wireless/b43/pio.h
drivers/net/wireless/b43/sysfs.c
drivers/net/wireless/hostap/hostap_wlan.h
drivers/net/wireless/ray_cs.h
drivers/net/xen-netfront.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/pci.c
drivers/pcmcia/i82365.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/tcic.c
drivers/rtc/rtc-sh.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs_unit.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/NCR53C9x.c
drivers/scsi/NCR_D700.c
drivers/scsi/a4000t.c
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commsup.c
drivers/scsi/advansys.c
drivers/scsi/aha152x.c
drivers/scsi/aic7xxx_old.c
drivers/scsi/aic94xx/aic94xx_hwi.h
drivers/scsi/aic94xx/aic94xx_init.c
drivers/scsi/aic94xx/aic94xx_task.c
drivers/scsi/arcmsr/arcmsr.h
drivers/scsi/arcmsr/arcmsr_attr.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/atari_NCR5380.c
drivers/scsi/bvme6000_scsi.c
drivers/scsi/constants.c
drivers/scsi/dc395x.c
drivers/scsi/dpt_i2o.c
drivers/scsi/dtc.c
drivers/scsi/eata.c
drivers/scsi/eata_pio.c
drivers/scsi/esp_scsi.c
drivers/scsi/fdomain.c
drivers/scsi/g_NCR5380.c
drivers/scsi/gdth.c
drivers/scsi/gdth.h
drivers/scsi/gdth_kcompat.h [deleted file]
drivers/scsi/gdth_proc.c
drivers/scsi/gdth_proc.h
drivers/scsi/hosts.c
drivers/scsi/hptiop.c
drivers/scsi/hptiop.h
drivers/scsi/ibmmca.c
drivers/scsi/ibmvscsi/Makefile
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/ibmvscsi/iseries_vscsi.c
drivers/scsi/ibmvscsi/rpa_vscsi.c
drivers/scsi/ide-scsi.c
drivers/scsi/imm.c
drivers/scsi/in2000.c
drivers/scsi/ips.c
drivers/scsi/ips.h
drivers/scsi/libsrp.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/megaraid.c
drivers/scsi/mvme16x_scsi.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/ncr53c8xx.h
drivers/scsi/osst.c
drivers/scsi/osst.h
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/nsp_cs.h
drivers/scsi/pluto.c
drivers/scsi/ps3rom.c
drivers/scsi/qla1280.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/qlogicfas.c
drivers/scsi/qlogicpti.c
drivers/scsi/qlogicpti.h
drivers/scsi/scsi.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_tgt_if.c
drivers/scsi/scsi_tgt_lib.c
drivers/scsi/scsi_tgt_priv.h
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_fc_internal.h [new file with mode: 0644]
drivers/scsi/scsi_transport_srp.c [new file with mode: 0644]
drivers/scsi/scsi_transport_srp_internal.h [new file with mode: 0644]
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/scsi/sun3_NCR5380.c
drivers/scsi/tmscsim.c
drivers/scsi/u14-34f.c
drivers/scsi/wd33c93.c
drivers/scsi/zorro7xx.c
drivers/serial/mpc52xx_uart.c
drivers/serial/sh-sci.c
drivers/serial/sh-sci.h
drivers/sh/Makefile
drivers/sh/maple/Makefile [new file with mode: 0644]
drivers/sh/maple/maple.c [new file with mode: 0644]
drivers/ssb/main.c
drivers/ssb/pcmcia.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/xusbatm.c
drivers/usb/host/ohci-ssb.c
drivers/usb/image/microtek.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/storage/transport.c
drivers/video/backlight/hp680_bl.c
drivers/video/cg6.c
drivers/video/ffb.c
drivers/video/pvr2fb.c
drivers/video/xilinxfb.c
fs/Kconfig
fs/inode.c
fs/jbd/transaction.c
fs/jffs2/Makefile
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/background.c
fs/jffs2/build.c
fs/jffs2/compr.c
fs/jffs2/compr.h
fs/jffs2/compr_lzo.c [new file with mode: 0644]
fs/jffs2/compr_rtime.c
fs/jffs2/compr_rubin.c
fs/jffs2/compr_zlib.c
fs/jffs2/dir.c
fs/jffs2/erase.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/jffs2_fs_sb.h
fs/jffs2/nodelist.h
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/security.c
fs/jffs2/summary.c
fs/jffs2/summary.h
fs/jffs2/wbuf.c
fs/jffs2/write.c
fs/jffs2/xattr.h
fs/jffs2/xattr_user.c
fs/jfs/jfs_dtree.c
fs/jfs/jfs_incore.h
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_logmgr.h
fs/lockd/mon.c
fs/lockd/xdr.c
fs/lockd/xdr4.c
fs/nfs/Makefile
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs2xdr.c
fs/nfs/nfs3acl.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/nfsroot.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/partitions/sun.c
fs/pipe.c
fs/proc/array.c
fs/proc/base.c
fs/proc/proc_misc.c
fs/smbfs/smbiod.c
include/asm-arm/arch-davinci/i2c.h [new file with mode: 0644]
include/asm-arm/io.h
include/asm-blackfin/mach-bf548/dma.h
include/asm-blackfin/nand.h [new file with mode: 0644]
include/asm-frv/system.h
include/asm-generic/vmlinux.lds.h
include/asm-ia64/mca.h
include/asm-ia64/sal.h
include/asm-m68k/Kbuild
include/asm-m68k/unistd.h
include/asm-mips/fw/cfe/cfe_api.h
include/asm-mips/mach-au1x00/prom.h [new file with mode: 0644]
include/asm-powerpc/dcr-mmio.h
include/asm-powerpc/dcr-native.h
include/asm-powerpc/io.h
include/asm-sh/cacheflush.h
include/asm-sh/cpu-sh3/cache.h
include/asm-sh/cpu-sh3/dma.h
include/asm-sh/cpu-sh3/gpio.h [new file with mode: 0644]
include/asm-sh/cpu-sh3/mmu_context.h
include/asm-sh/cpu-sh3/timer.h
include/asm-sh/cpu-sh3/ubc.h
include/asm-sh/cpu-sh4/dma.h
include/asm-sh/cpu-sh4/mmu_context.h
include/asm-sh/dma.h
include/asm-sh/dreamcast/maple.h [new file with mode: 0644]
include/asm-sh/gpio.h [new file with mode: 0644]
include/asm-sh/hd64461.h
include/asm-sh/heartbeat.h [new file with mode: 0644]
include/asm-sh/hw_irq.h
include/asm-sh/ilsel.h [new file with mode: 0644]
include/asm-sh/io.h
include/asm-sh/kgdb.h
include/asm-sh/magicpanelr2.h [new file with mode: 0644]
include/asm-sh/page.h
include/asm-sh/pgtable.h
include/asm-sh/processor.h
include/asm-sh/r7780rp.h
include/asm-sh/rtc.h
include/asm-sh/rts7751r2d.h
include/asm-sh/sections.h
include/asm-sh/sh03/io.h
include/asm-sh/smp.h
include/asm-sh/snapgear.h
include/asm-sh/spinlock.h
include/asm-sh/spinlock_types.h
include/asm-sh/system.h
include/asm-sh/voyagergx.h
include/asm-sh64/gpio.h [new file with mode: 0644]
include/asm-sh64/io.h
include/asm-sparc/irqflags.h [new file with mode: 0644]
include/asm-sparc/system.h
include/asm-sparc64/cpudata.h
include/asm-sparc64/irq.h
include/asm-x86/cpufeature_64.h
include/asm-x86/io_apic_32.h
include/asm-x86/irqflags_32.h
include/asm-x86/irqflags_64.h
include/asm-x86/processor-flags.h
include/asm-x86/system_32.h
include/asm-x86/system_64.h
include/linux/agpgart.h
include/linux/clockchips.h
include/linux/fs.h
include/linux/hdlcdrv.h
include/linux/hid.h
include/linux/hidraw.h [new file with mode: 0644]
include/linux/hwmon.h
include/linux/i2c-dev.h
include/linux/i2c.h
include/linux/ide.h
include/linux/inet_lro.h
include/linux/input.h
include/linux/jbd.h
include/linux/jffs2.h
include/linux/jiffies.h
include/linux/kernel_stat.h
include/linux/kvm.h
include/linux/lockdep.h
include/linux/maple.h [new file with mode: 0644]
include/linux/mod_devicetable.h
include/linux/mtd/cfi.h
include/linux/mtd/flashchip.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/onenand.h
include/linux/mtd/onenand_regs.h
include/linux/mutex.h
include/linux/netdevice.h
include/linux/nfs_fs.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/nfsfh.h
include/linux/nfsd/xdr4.h
include/linux/pci_ids.h
include/linux/rcupdate.h
include/linux/reiserfs_fs_sb.h
include/linux/sched.h
include/linux/scx200_gpio.h
include/linux/skbuff.h
include/linux/stallion.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/debug.h
include/linux/sunrpc/msg_prot.h
include/linux/sunrpc/rpc_rdma.h [new file with mode: 0644]
include/linux/sunrpc/xdr.h
include/linux/sunrpc/xprt.h
include/linux/sunrpc/xprtrdma.h [new file with mode: 0644]
include/linux/sunrpc/xprtsock.h [new file with mode: 0644]
include/linux/topology.h
include/linux/writeback.h
include/media/videobuf-core.h
include/scsi/libsrp.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_dbg.h
include/scsi/scsi_driver.h
include/scsi/scsi_eh.h
include/scsi/scsi_host.h
include/scsi/scsi_tgt.h
include/scsi/scsi_tgt_if.h
include/scsi/scsi_transport.h
include/scsi/scsi_transport_fc.h
include/scsi/scsi_transport_iscsi.h
include/scsi/scsi_transport_srp.h [new file with mode: 0644]
include/scsi/sd.h
init/Kconfig
kernel/auditsc.c
kernel/delayacct.c
kernel/exit.c
kernel/fork.c
kernel/ksysfs.c
kernel/lockdep.c
kernel/lockdep_proc.c
kernel/mutex.c
kernel/posix-timers.c
kernel/rcupdate.c
kernel/sched.c
kernel/sched_debug.c
kernel/sched_fair.c
kernel/sched_idletask.c
kernel/sched_rt.c
kernel/sched_stats.h
kernel/sysctl.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/user.c
lib/idr.c
mm/migrate.c
net/core/dev.c
net/core/sock.c
net/ipv4/inet_lro.c
net/sctp/socket.c
net/sunrpc/Makefile
net/sunrpc/auth_gss/gss_krb5_wrap.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sched.c
net/sunrpc/socklib.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svc.c
net/sunrpc/timer.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/Makefile [new file with mode: 0644]
net/sunrpc/xprtrdma/rpc_rdma.c [new file with mode: 0644]
net/sunrpc/xprtrdma/transport.c [new file with mode: 0644]
net/sunrpc/xprtrdma/verbs.c [new file with mode: 0644]
net/sunrpc/xprtrdma/xprt_rdma.h [new file with mode: 0644]
net/sunrpc/xprtsock.c
net/unix/af_unix.c
scripts/mod/file2alias.c
sound/pci/bt87x.c
sound/usb/usbaudio.c

index c917de681ccd7cde61ee94333234cd8ad8b70ecb..361c884d860d3a10f1d14f970ed11edf5761e6d1 100644 (file)
@@ -316,7 +316,7 @@ CPU B:  spin_unlock_irqrestore(&amp;dev_lock, flags)
 
   <chapter id="pubfunctions">
      <title>Public Functions Provided</title>
-!Iinclude/asm-i386/io.h
+!Iinclude/asm-x86/io_32.h
 !Elib/iomap.c
   </chapter>
 
index e5da4f2b7c22cab386261b3139c7ba032a3de159..230cbf7537824d8f91136c9c4e772f2e29871a98 100644 (file)
@@ -45,8 +45,8 @@
      </sect1>
 
      <sect1><title>Atomic and pointer manipulation</title>
-!Iinclude/asm-i386/atomic.h
-!Iinclude/asm-i386/unaligned.h
+!Iinclude/asm-x86/atomic_32.h
+!Iinclude/asm-x86/unaligned_32.h
      </sect1>
 
      <sect1><title>Delaying, scheduling, and timer routines</title>
@@ -119,7 +119,7 @@ X!Ilib/string.c
 !Elib/string.c
      </sect1>
      <sect1><title>Bit Operations</title>
-!Iinclude/asm-i386/bitops.h
+!Iinclude/asm-x86/bitops_32.h
      </sect1>
   </chapter>
 
@@ -155,8 +155,8 @@ X!Ilib/string.c
 !Emm/slab.c
      </sect1>
      <sect1><title>User Space Memory Access</title>
-!Iinclude/asm-i386/uaccess.h
-!Earch/i386/lib/usercopy.c
+!Iinclude/asm-x86/uaccess_32.h
+!Earch/x86/lib/usercopy_32.c
      </sect1>
      <sect1><title>More Memory Management Functions</title>
 !Emm/readahead.c
@@ -293,7 +293,7 @@ X!Ekernel/module.c
      </sect1>
 
      <sect1><title>MTRR Handling</title>
-!Earch/i386/kernel/cpu/mtrr/main.c
+!Earch/x86/kernel/cpu/mtrr/main.c
      </sect1>
 
      <sect1><title>PCI Support Library</title>
@@ -316,14 +316,14 @@ X!Edrivers/pci/hotplug.c
      <sect1><title>MCA Architecture</title>
        <sect2><title>MCA Device Functions</title>
            <para>
-              Refer to the file arch/i386/kernel/mca.c for more information.
+              Refer to the file arch/x86/kernel/mca_32.c for more information.
            </para>
 <!-- FIXME: Removed for now since no structured comments in source
-X!Earch/i386/kernel/mca.c
+X!Earch/x86/kernel/mca_32.c
 -->
        </sect2>
        <sect2><title>MCA Bus DMA</title>
-!Iinclude/asm-i386/mca_dma.h
+!Iinclude/asm-x86/mca_dma.h
        </sect2>
      </sect1>
   </chapter>
index 582032eea87228352079b8b7002117151a79cc41..4c63e5864160f159fd073039ba80efefb161ff68 100644 (file)
@@ -1239,7 +1239,7 @@ static struct block_device_operations opt_fops = {
   </para>
 
   <para>
-   <filename>include/asm-i386/delay.h:</filename>
+   <filename>include/asm-x86/delay_32.h:</filename>
   </para>
   <programlisting>
 #define ndelay(n) (__builtin_constant_p(n) ? \
@@ -1265,7 +1265,7 @@ static struct block_device_operations opt_fops = {
 </programlisting>
 
   <para>
-   <filename>include/asm-i386/uaccess.h:</filename>
+   <filename>include/asm-x86/uaccess_32.h:</filename>
   </para>
 
   <programlisting>
index 42a760cd7467a422142f5f2ea83c3072fcf08481..529a53dc13899e1f780516c2ee80f90f1df58cd6 100644 (file)
 
   <chapter id="dmafunctions">
      <title>DMA Functions Provided</title>
-!Iinclude/asm-i386/mca_dma.h
+!Iinclude/asm-x86/mca_dma.h
   </chapter>
 
 </book>
index a8c8cce506332a2037833d8cc8f7dc54c0791748..6fbc41d98c1eb56a0779499ed6d9dd8ce45235f6 100644 (file)
@@ -275,16 +275,13 @@ int __init board_init (void)
        int err = 0;
 
        /* Allocate memory for MTD device structure and private data */
-       board_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
+       board_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
        if (!board_mtd) {
                printk ("Unable to allocate NAND MTD device structure.\n");
                err = -ENOMEM;
                goto out;
        }
 
-       /* Initialize structures */
-       memset ((char *) board_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip));
-
        /* map physical adress */
        baseaddr = (unsigned long)ioremap(CHIP_PHYSICAL_ADDRESS, 1024);
        if(!baseaddr){
index 870cda9416e90ff0da59df30f101d5a244b4bc66..170bf862437b0b391efd057c13717d0474487f58 100644 (file)
@@ -4,7 +4,7 @@ Kernel driver coretemp
 Supported chips:
   * All Intel Core family
     Prefix: 'coretemp'
-    CPUID: family 0x6, models 0xe, 0xf
+    CPUID: family 0x6, models 0xe, 0xf, 0x16
     Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
                Volume 3A: System Programming Guide
 
index 1a0f3d64ab805404d84519bcba6e77cadac5160c..8f446070e64a56ebc2c19a98c3f5e40688648b06 100644 (file)
@@ -6,6 +6,10 @@ Supported chips:
     Prefix: 'dme1737'
     Addresses scanned: I2C 0x2c, 0x2d, 0x2e
     Datasheet: Provided by SMSC upon request and under NDA
+  * SMSC SCH3112, SCH3114, SCH3116
+    Prefix: 'sch311x'
+    Addresses scanned: none, address read from Super-I/O config space
+    Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
 
 Authors:
     Juerg Haefliger <juergh@gmail.com>
@@ -27,16 +31,25 @@ Description
 -----------
 
 This driver implements support for the hardware monitoring capabilities of the
-SMSC DME1737 and Asus A8000 (which are the same) Super-I/O chips. This chip
-features monitoring of 3 temp sensors temp[1-3] (2 remote diodes and 1
-internal), 7 voltages in[0-6] (6 external and 1 internal) and 6 fan speeds
-fan[1-6]. Additionally, the chip implements 5 PWM outputs pwm[1-3,5-6] for
-controlling fan speeds both manually and automatically.
-
-Fan[3-6] and pwm[3,5-6] are optional features and their availability is
-dependent on the configuration of the chip. The driver will detect which
-features are present during initialization and create the sysfs attributes
-accordingly.
+SMSC DME1737 and Asus A8000 (which are the same) and SMSC SCH311x Super-I/O
+chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote
+diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up
+to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM
+outputs pwm[1-3,5-6] for controlling fan speeds both manually and
+automatically.
+
+For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6]
+and pwm[3,5-6] are optional features and their availability depends on the
+configuration of the chip. The driver will detect which features are present
+during initialization and create the sysfs attributes accordingly.
+
+For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
+pwm[5-6] don't exist.
+
+The hardware monitoring features of the DME1737 and A8000 are only accessible
+via SMBus, while the SCH311x only provides access via the ISA bus. The driver
+will therefore register itself as an I2C client driver if it detects a DME1737
+or A8000 and as a platform driver if it detects a SCH311x chip.
 
 
 Voltage Monitoring
index 94e0d2cbd3d2368996deef0f0e06691bc358ccb4..f0d55976740adfeabfb7258d4109a7d4c930c6ac 100644 (file)
@@ -6,6 +6,10 @@ Supported chips:
     Prefix: 'f71805f'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
+  * Fintek F71806F/FG
+    Prefix: 'f71872f'
+    Addresses scanned: none, address read from Super I/O config space
+    Datasheet: Available from the Fintek website
   * Fintek F71872F/FG
     Prefix: 'f71872f'
     Addresses scanned: none, address read from Super I/O config space
@@ -38,6 +42,9 @@ The Fintek F71872F/FG Super I/O chip is almost the same, with two
 additional internal voltages monitored (VSB and battery). It also features
 6 VID inputs. The VID inputs are not yet supported by this driver.
 
+The Fintek F71806F/FG Super-I/O chip is essentially the same as the
+F71872F/FG, and is undistinguishable therefrom.
+
 The driver assumes that no more than one chip is present, which seems
 reasonable.
 
index 81ecc7e41c5044b049dfe8e4910e12b83e6e8935..5b704a40256b63a2ba896568db72c464e2ab788d 100644 (file)
@@ -90,7 +90,8 @@ upper VID bits share their pins with voltage inputs (in5 and in6) so you
 can't have both on a given board.
 
 The IT8716F, IT8718F and later IT8712F revisions have support for
-2 additional fans. They are not yet supported by the driver.
+2 additional fans. They are supported by the driver for the IT8716F and
+IT8718F but not for the IT8712F
 
 The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
 16-bit tachometer counters for fans 1 to 3. This is better (no more fan
index fd5dc7a19f0e73361ebafb37141071eae77b9c14..dfc318a60fd46dbce33bcdfdb78f2e7639a0fe6f 100644 (file)
@@ -56,16 +56,6 @@ should work with. This is hardcoded by the mainboard and/or processor itself.
 It is a value in volts. When it is unconnected, you will often find the
 value 3.50 V here.
 
-In addition to the alarms described above, there are a couple of additional
-ones. There is a BTI alarm, which gets triggered when an external chip has
-crossed its limits. Usually, this is connected to all LM75 chips; if at
-least one crosses its limits, this bit gets set. The CHAS alarm triggers
-if your computer case is open. The FIFO alarms should never trigger; it
-indicates an internal error. The SMI_IN alarm indicates some other chip
-has triggered an SMI interrupt. As we do not use SMI interrupts at all,
-this condition usually indicates there is a problem with some other
-device.
-
 If an alarm triggers, it will remain triggered until the hardware register
 is read at least once. This means that the cause for the alarm may
 already have disappeared! Note that in the current implementation, all
index 4e4a1dc1d2da98713de94ffacf61f495e5115e17..ac711f357fafb0793d10c3cb31d2cd882647f767 100644 (file)
@@ -7,7 +7,7 @@ Supported chips:
     Addresses scanned: I2C 0x2c-0x2e
     Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf
 
-Author:
+Authors:
        Mark M. Hoffman <mhoffman@lightlink.com>
        Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
        Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
@@ -16,7 +16,6 @@ Author:
 Module Parameters
 -----------------
 
-(specific to LM93)
 * init: integer
   Set to non-zero to force some initializations (default is 0).
 * disable_block: integer
@@ -37,30 +36,13 @@ Module Parameters
   I.e. this parameter controls the VID pin input thresholds; if your VID
   inputs are not working, try changing this.  The default value is "0".
 
-(common among sensor drivers)
-* force: short array (min = 1, max = 48)
-  List of adapter,address pairs to assume to be present.  Autodetection
-  of the target device will still be attempted.  Use one of the more
-  specific force directives below if this doesn't detect the device.
-* force_lm93: short array (min = 1, max = 48)
-  List of adapter,address pairs which are unquestionably assumed to contain
-  a 'lm93' chip
-* ignore: short array (min = 1, max = 48)
-  List of adapter,address pairs not to scan
-* ignore_range: short array (min = 1, max = 48)
-  List of adapter,start-addr,end-addr triples not to scan
-* probe: short array (min = 1, max = 48)
-  List of adapter,address pairs to scan additionally
-* probe_range: short array (min = 1, max = 48)
-  List of adapter,start-addr,end-addr triples to scan additionally
-
 
 Hardware Description
 --------------------
 
 (from the datasheet)
 
-The LM93, hardware monitor, has a two wire digital interface compatible with
+The LM93 hardware monitor has a two wire digital interface compatible with
 SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote
 diode connected transistors as well as its own die and 16 power supply
 voltages. To set fan speed, the LM93 has two PWM outputs that are each
@@ -69,18 +51,12 @@ table based. The LM93 includes a digital filter that can be invoked to smooth
 temperature readings for better control of fan speed. The LM93 has four
 tachometer inputs to measure fan speed. Limit and status registers for all
 measured values are included. The LM93 builds upon the functionality of
-previous motherboard management ASICs and uses some of the LM85 s features
+previous motherboard management ASICs and uses some of the LM85's features
 (i.e. smart tachometer mode). It also adds measurement and control support
 for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual
 processor Xeon class motherboard with a minimum of external components.
 
 
-Driver Description
-------------------
-
-This driver implements support for the National Semiconductor LM93.
-
-
 User Interface
 --------------
 
@@ -101,7 +77,7 @@ These intervals can be found in the sysfs files prochot1_interval and
 prochot2_interval.  The values in these files specify the intervals for
 #P1_PROCHOT and #P2_PROCHOT, respectively.  Selecting a value not in this
 list will cause the driver to use the next largest interval.  The available
-intervals are:
+intervals are (in seconds):
 
 #PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372
 
@@ -111,12 +87,12 @@ assert #P2_PROCHOT, and vice-versa.  This mode is enabled by writing a
 non-zero integer to the sysfs file prochot_short.
 
 The LM93 can also override the #PROCHOT pins by driving a PWM signal onto
-one or both of them.  When overridden, the signal has a period of 3.56 mS,
+one or both of them.  When overridden, the signal has a period of 3.56 ms,
 a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and
 a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle).
 
 The sysfs files prochot1_override and prochot2_override contain boolean
-intgers which enable or disable the override function for #P1_PROCHOT and
+integers which enable or disable the override function for #P1_PROCHOT and
 #P2_PROCHOT, respectively.  The sysfs file prochot_override_duty_cycle
 contains a value controlling the duty cycle for the PWM signal used when
 the override function is enabled.  This value ranges from 0 to 15, with 0
@@ -166,7 +142,7 @@ frequency values are constrained by the hardware.  Selecting a value which is
 not available will cause the driver to use the next largest value.  Also note
 that this parameter has implications for the Smart Tach Mode (see above).
 
-PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 (h/w default)
+PWM Output Frequencies (in Hz): 12, 36, 48, 60, 72, 84, 96, 22500 (default)
 
 Automatic PWM:
 
@@ -178,7 +154,7 @@ individual control sources to which the PWM output is bound.
 The eight control sources are: temp1-temp4 (aka "zones" in the datasheet),
 #PROCHOT 1 & 2, and #VRDHOT 1 & 2.  The bindings are expressed as a bitmask
 in the sysfs files pwm<n>_auto_channels, where a "1" enables the binding, and
- a "0" disables it. The h/w default is 0x0f (all temperatures bound).
+a "0" disables it. The h/w default is 0x0f (all temperatures bound).
 
        0x01 - Temp 1
        0x02 - Temp 2
@@ -324,89 +300,3 @@ LM93 Unique sysfs Files
 
        gpio                    input state of 8 GPIO pins; read-only
 
-
-Sample Configuration File
--------------------------
-
-Here is a sample LM93 chip config for sensors.conf:
-
----------- cut here ----------
-chip "lm93-*"
-
-# VOLTAGE INPUTS
-
-       # labels and scaling based on datasheet recommendations
-       label in1       "+12V1"
-       compute in1     @ * 12.945, @ / 12.945
-       set in1_min     12 * 0.90
-       set in1_max     12 * 1.10
-
-       label in2       "+12V2"
-       compute in2     @ * 12.945, @ / 12.945
-       set in2_min     12 * 0.90
-       set in2_max     12 * 1.10
-
-       label in3       "+12V3"
-       compute in3     @ * 12.945, @ / 12.945
-       set in3_min     12 * 0.90
-       set in3_max     12 * 1.10
-
-       label in4       "FSB_Vtt"
-
-       label in5       "3GIO"
-
-       label in6       "ICH_Core"
-
-       label in7       "Vccp1"
-
-       label in8       "Vccp2"
-
-       label in9       "+3.3V"
-       set in9_min     3.3 * 0.90
-       set in9_max     3.3 * 1.10
-
-       label in10      "+5V"
-       set in10_min    5.0 * 0.90
-       set in10_max    5.0 * 1.10
-
-       label in11      "SCSI_Core"
-
-       label in12      "Mem_Core"
-
-       label in13      "Mem_Vtt"
-
-       label in14      "Gbit_Core"
-
-       # Assuming R1/R2 = 4.1143, and 3.3V reference
-       # -12V = (4.1143 + 1) * (@ - 3.3) + 3.3
-       label in15      "-12V"
-       compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143
-       set in15_min    -12 * 0.90
-       set in15_max    -12 * 1.10
-
-       label in16      "+3.3VSB"
-       set in16_min    3.3 * 0.90
-       set in16_max    3.3 * 1.10
-
-# TEMPERATURE INPUTS
-
-       label temp1     "CPU1"
-       label temp2     "CPU2"
-       label temp3     "LM93"
-
-# TACHOMETER INPUTS
-
-       label fan1      "Fan1"
-       set fan1_min    3000
-       label fan2      "Fan2"
-       set fan2_min    3000
-       label fan3      "Fan3"
-       set fan3_min    3000
-       label fan4      "Fan4"
-       set fan4_min    3000
-
-# PWM OUTPUTS
-
-       label pwm1      "CPU1"
-       label pwm2      "CPU2"
-
index b3a9e1b9dbda9458b5d4215f50b3b217284c3b82..a17b692d2679ca520adfa986d9035a19ea88bd57 100644 (file)
@@ -67,6 +67,10 @@ between readings to be caught and alarmed. The exact definition of an
 alarm (for example, whether a threshold must be met or must be exceeded
 to cause an alarm) is chip-dependent.
 
+When setting values of hwmon sysfs attributes, the string representation of
+the desired value must be written, note that strings which are not a number
+are interpreted as 0! For more on how written strings are interpreted see the
+"sysfs attribute writes interpretation" section at the end of this file.
 
 -------------------------------------------------------------------------
 
@@ -78,8 +82,21 @@ RW   read/write value
 Read/write values may be read-only for some chips, depending on the
 hardware implementation.
 
-All entries are optional, and should only be created in a given driver
-if the chip has the feature.
+All entries (except name) are optional, and should only be created in a
+given driver if the chip has the feature.
+
+
+********
+* Name *
+********
+
+name           The chip name.
+               This should be a short, lowercase string, not containing
+               spaces nor dashes, representing the chip name. This is
+               the only mandatory attribute.
+               I2C devices get this attribute created automatically.
+               RO
+
 
 ************
 * Voltages *
@@ -104,18 +121,17 @@ in[0-*]_input     Voltage input value.
                by the chip driver, and must be done by the application.
                However, some drivers (notably lm87 and via686a)
                do scale, because of internal resistors built into a chip.
-               These drivers will output the actual voltage.
-
-               Typical usage:
-                       in0_*   CPU #1 voltage (not scaled)
-                       in1_*   CPU #2 voltage (not scaled)
-                       in2_*   3.3V nominal (not scaled)
-                       in3_*   5.0V nominal (scaled)
-                       in4_*   12.0V nominal (scaled)
-                       in5_*   -12.0V nominal (scaled)
-                       in6_*   -5.0V nominal (scaled)
-                       in7_*   varies
-                       in8_*   varies
+               These drivers will output the actual voltage. Rule of
+               thumb: drivers should report the voltage values at the
+               "pins" of the chip.
+
+in[0-*]_label  Suggested voltage channel label.
+               Text string
+               Should only be created if the driver has hints about what
+               this voltage channel is being used for, and user-space
+               doesn't. In all other cases, the label is provided by
+               user-space.
+               RO
 
 cpu[0-*]_vid   CPU core reference voltage.
                Unit: millivolt
@@ -159,6 +175,13 @@ fan[1-*]_target
                Only makes sense if the chip supports closed-loop fan speed
                control based on the measured fan speed.
 
+fan[1-*]_label Suggested fan channel label.
+               Text string
+               Should only be created if the driver has hints about what
+               this fan channel is being used for, and user-space doesn't.
+               In all other cases, the label is provided by user-space.
+               RO
+
 Also see the Alarms section for status flags associated with fans.
 
 
@@ -219,12 +242,12 @@ temp[1-*]_auto_point[1-*]_temp_hyst
 ****************
 
 temp[1-*]_type Sensor type selection.
-               Integers 1 to 6 or thermistor Beta value (typically 3435)
+               Integers 1 to 6
                RW
                1: PII/Celeron Diode
                2: 3904 transistor
                3: thermal diode
-               4: thermistor (default/unknown Beta)
+               4: thermistor
                5: AMD AMDSI
                6: Intel PECI
                Not all types are supported by all chips
@@ -260,18 +283,19 @@ temp[1-*]_crit_hyst
                from the critical value.
                RW
 
-temp[1-4]_offset
+temp[1-*]_offset
                Temperature offset which is added to the temperature reading
                by the chip.
                Unit: millidegree Celsius
                Read/Write value.
 
-               If there are multiple temperature sensors, temp1_* is
-               generally the sensor inside the chip itself,
-               reported as "motherboard temperature".  temp2_* to
-               temp4_* are generally sensors external to the chip
-               itself, for example the thermal diode inside the CPU or
-               a thermistor nearby.
+temp[1-*]_label        Suggested temperature channel label.
+               Text string
+               Should only be created if the driver has hints about what
+               this temperature channel is being used for, and user-space
+               doesn't. In all other cases, the label is provided by
+               user-space.
+               RO
 
 Some chips measure temperature using external thermistors and an ADC, and
 report the temperature measurement as a voltage. Converting this voltage
@@ -393,14 +417,53 @@ beep_mask Bitmask for beep.
                RW
 
 
-*********
-* Other *
-*********
-
-eeprom         Raw EEPROM data in binary form.
-               RO
-
-pec            Enable or disable PEC (SMBus only)
-               0: disable
-               1: enable
-               RW
+sysfs attribute writes interpretation
+-------------------------------------
+
+hwmon sysfs attributes always contain numbers, so the first thing to do is to
+convert the input to a number, there are 2 ways todo this depending whether
+the number can be negative or not:
+unsigned long u = simple_strtoul(buf, NULL, 10);
+long s = simple_strtol(buf, NULL, 10);
+
+With buf being the buffer with the user input being passed by the kernel.
+Notice that we do not use the second argument of strto[u]l, and thus cannot
+tell when 0 is returned, if this was really 0 or is caused by invalid input.
+This is done deliberately as checking this everywhere would add a lot of
+code to the kernel.
+
+Notice that it is important to always store the converted value in an
+unsigned long or long, so that no wrap around can happen before any further
+checking.
+
+After the input string is converted to an (unsigned) long, the value should be
+checked if its acceptable. Be careful with further conversions on the value
+before checking it for validity, as these conversions could still cause a wrap
+around before the check. For example do not multiply the result, and only
+add/subtract if it has been divided before the add/subtract.
+
+What to do if a value is found to be invalid, depends on the type of the
+sysfs attribute that is being set. If it is a continuous setting like a
+tempX_max or inX_max attribute, then the value should be clamped to its
+limits using SENSORS_LIMIT(value, min_limit, max_limit). If it is not
+continuous like for example a tempX_type, then when an invalid value is
+written, -EINVAL should be returned.
+
+Example1, temp1_max, register is a signed 8 bit value (-128 - 127 degrees):
+
+       long v = simple_strtol(buf, NULL, 10) / 1000;
+       v = SENSORS_LIMIT(v, -128, 127);
+       /* write v to register */
+
+Example2, fan divider setting, valid values 2, 4 and 8:
+
+       unsigned long v = simple_strtoul(buf, NULL, 10);
+
+       switch (v) {
+       case 2: v = 1; break;
+       case 4: v = 2; break;
+       case 8: v = 3; break;
+       default:
+               return -EINVAL;
+       }
+       /* write v to register */
index db9881df88a54cfe5c8a87965ddca58bb121eb28..f153b2f6d62ca76958c2e80eb42efc3aa4c830be 100644 (file)
@@ -75,46 +75,64 @@ Voltage sensors (also known as IN sensors) report their values in millivolts.
 An alarm is triggered if the voltage has crossed a programmable minimum
 or maximum limit.
 
-The bit ordering for the alarm "realtime status register" and the
-"beep enable registers" are different.
-
-in0 (VCORE)  :  alarms: 0x000001 beep_enable: 0x000001
-in1 (VINR0)  :  alarms: 0x000002 beep_enable: 0x002000 <== mismatch
-in2 (+3.3VIN):  alarms: 0x000004 beep_enable: 0x000004
-in3 (5VDD)   :  alarms: 0x000008 beep_enable: 0x000008
-in4 (+12VIN) :  alarms: 0x000100 beep_enable: 0x000100
-in5 (-12VIN) :  alarms: 0x000200 beep_enable: 0x000200
-in6 (-5VIN)  :  alarms: 0x000400 beep_enable: 0x000400
-in7 (VSB)    :  alarms: 0x080000 beep_enable: 0x010000 <== mismatch
-in8 (VBAT)   :  alarms: 0x100000 beep_enable: 0x020000 <== mismatch
-in9 (VINR1)  :  alarms: 0x004000 beep_enable: 0x004000
-temp1        :  alarms: 0x000010 beep_enable: 0x000010
-temp2        :  alarms: 0x000020 beep_enable: 0x000020
-temp3        :  alarms: 0x002000 beep_enable: 0x000002 <== mismatch
-fan1         :  alarms: 0x000040 beep_enable: 0x000040
-fan2         :  alarms: 0x000080 beep_enable: 0x000080
-fan3         :  alarms: 0x000800 beep_enable: 0x000800
-fan4         :  alarms: 0x200000 beep_enable: 0x200000
-fan5         :  alarms: 0x400000 beep_enable: 0x400000
-tart1        :  alarms: 0x010000 beep_enable: 0x040000 <== mismatch
-tart2        :  alarms: 0x020000 beep_enable: 0x080000 <== mismatch
-tart3        :  alarms: 0x040000 beep_enable: 0x100000 <== mismatch
-case_open    :  alarms: 0x001000 beep_enable: 0x001000
-user_enable  :  alarms: -------- beep_enable: 0x800000
-
-*** NOTE: It is the responsibility of user-space code to handle the fact
-that the beep enable and alarm bits are in different positions when using that
-feature of the chip.
-
-When an alarm goes off, you can be warned by a beeping signal through your
-computer speaker. It is possible to enable all beeping globally, or only
-the beeping for some alarms.
-
-The driver only reads the chip values each 3 seconds; reading them more
-often will do no harm, but will return 'old' values.
+The w83791d has a global bit used to enable beeping from the speaker when an
+alarm is triggered as well as a bitmask to enable or disable the beep for
+specific alarms. You need both the global beep enable bit and the
+corresponding beep bit to be on for a triggered alarm to sound a beep.
+
+The sysfs interface to the gloabal enable is via the sysfs beep_enable file.
+This file is used for both legacy and new code.
+
+The sysfs interface to the beep bitmask has migrated from the original legacy
+method of a single sysfs beep_mask file to a newer method using multiple
+*_beep files as described in .../Documentation/hwmon/sysfs-interface.
+
+A similar change has occured for the bitmap corresponding to the alarms. The
+original legacy method used a single sysfs alarms file containing a bitmap
+of triggered alarms. The newer method uses multiple sysfs *_alarm files
+(again following the pattern described in sysfs-interface).
+
+Since both methods read and write the underlying hardware, they can be used
+interchangeably and changes in one will automatically be reflected by
+the other. If you use the legacy bitmask method, your user-space code is
+responsible for handling the fact that the alarms and beep_mask bitmaps
+are not the same (see the table below).
+
+NOTE: All new code should be written to use the newer sysfs-interface
+specification as that avoids bitmap problems and is the preferred interface
+going forward.
+
+The driver reads the hardware chip values at most once every three seconds.
+User mode code requesting values more often will receive cached values.
+
+Alarms bitmap vs. beep_mask bitmask
+------------------------------------
+For legacy code using the alarms and beep_mask files:
+
+in0 (VCORE)  :  alarms: 0x000001 beep_mask: 0x000001
+in1 (VINR0)  :  alarms: 0x000002 beep_mask: 0x002000 <== mismatch
+in2 (+3.3VIN):  alarms: 0x000004 beep_mask: 0x000004
+in3 (5VDD)   :  alarms: 0x000008 beep_mask: 0x000008
+in4 (+12VIN) :  alarms: 0x000100 beep_mask: 0x000100
+in5 (-12VIN) :  alarms: 0x000200 beep_mask: 0x000200
+in6 (-5VIN)  :  alarms: 0x000400 beep_mask: 0x000400
+in7 (VSB)    :  alarms: 0x080000 beep_mask: 0x010000 <== mismatch
+in8 (VBAT)   :  alarms: 0x100000 beep_mask: 0x020000 <== mismatch
+in9 (VINR1)  :  alarms: 0x004000 beep_mask: 0x004000
+temp1        :  alarms: 0x000010 beep_mask: 0x000010
+temp2        :  alarms: 0x000020 beep_mask: 0x000020
+temp3        :  alarms: 0x002000 beep_mask: 0x000002 <== mismatch
+fan1         :  alarms: 0x000040 beep_mask: 0x000040
+fan2         :  alarms: 0x000080 beep_mask: 0x000080
+fan3         :  alarms: 0x000800 beep_mask: 0x000800
+fan4         :  alarms: 0x200000 beep_mask: 0x200000
+fan5         :  alarms: 0x400000 beep_mask: 0x400000
+tart1        :  alarms: 0x010000 beep_mask: 0x040000 <== mismatch
+tart2        :  alarms: 0x020000 beep_mask: 0x080000 <== mismatch
+tart3        :  alarms: 0x040000 beep_mask: 0x100000 <== mismatch
+case_open    :  alarms: 0x001000 beep_mask: 0x001000
+global_enable:  alarms: -------- beep_mask: 0x800000 (modified via beep_enable)
 
 W83791D TODO:
 ---------------
-Provide a patch for per-file alarms and beep enables as defined in the hwmon
-       documentation (Documentation/hwmon/sysfs-interface)
 Provide a patch for smart-fan control (still need appropriate motherboard/fans)
index fe6406f2f9a66ac9c96216c097f02b0b7b107816..fde4420e3f7557c137de782c84983803afa6f153 100644 (file)
@@ -13,7 +13,8 @@ Supported adapters:
   * Intel 631xESB/632xESB (ESB2)
   * Intel 82801H (ICH8)
   * Intel ICH9
-    Datasheets: Publicly available at the Intel website
+  * Intel Tolapai
+   Datasheets: Publicly available at the Intel website
 
 Authors: 
        Frodo Looijaard <frodol@dds.nl>, 
index 2752c8ce3167c523eaf14bc82d975268cd502515..5c1ad1376b62e5588d1b95b0f573211b39e70851 100644 (file)
@@ -62,8 +62,6 @@ if the corresponding output is set as 1, otherwise the current output
 value, that is to say 0.
 
 The write file is read/write. Writing a value outputs it on the I/O
-port. Reading returns the last written value.
-
-On module initialization the chip is configured as eight inputs (all
-outputs to 1), so you can connect any circuit to the PCF8574(A) without
-being afraid of short-circuit.
+port. Reading returns the last written value. As it is not possible
+to read this value from the chip, you need to write at least once to
+this file before you can read back from it.
index b849ad63658378702cd2f2d1b952e0a4b4682ae7..9dd79123ddd9949de863a0c2c20e98f99269a8c4 100644 (file)
@@ -90,12 +90,15 @@ ioctl(file,I2C_SLAVE,long addr)
 
 ioctl(file,I2C_TENBIT,long select)
   Selects ten bit addresses if select not equals 0, selects normal 7 bit
-  addresses if select equals 0. Default 0.
+  addresses if select equals 0. Default 0.  This request is only valid
+  if the adapter has I2C_FUNC_10BIT_ADDR.
 
 ioctl(file,I2C_PEC,long select)
   Selects SMBus PEC (packet error checking) generation and verification
   if select not equals 0, disables if select equals 0. Default 0.
-  Used only for SMBus transactions.
+  Used only for SMBus transactions.  This request only has an effect if the
+  the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
+  doesn't have any effect.
 
 ioctl(file,I2C_FUNCS,unsigned long *funcs)
   Gets the adapter functionality and puts it in *funcs.
@@ -103,8 +106,10 @@ ioctl(file,I2C_FUNCS,unsigned long *funcs)
 ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
 
   Do combined read/write transaction without stop in between.
-  The argument is a pointer to a struct i2c_rdwr_ioctl_data {
+  Only valid if the adapter has I2C_FUNC_I2C.  The argument is
+  a pointer to a
 
+  struct i2c_rdwr_ioctl_data {
       struct i2c_msg *msgs;  /* ptr to array of simple messages */
       int nmsgs;             /* number of messages to exchange */
   }
index 9cc081e697648ecb3feaadddcc4b8da187294db9..89e69ad3436c6f62443335762797442605b1af1d 100644 (file)
@@ -6,13 +6,14 @@ This module is a very simple fake I2C/SMBus driver.  It implements four
 types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
 (r/w) word data.
 
-You need to provide a chip address as a module parameter when loading
-this driver, which will then only react to SMBus commands to this address.
+You need to provide chip addresses as a module parameter when loading this
+driver, which will then only react to SMBus commands to these addresses.
 
 No hardware is needed nor associated with this module.  It will accept write
-quick commands to one address; it will respond to the other commands (also
-to one address) by reading from or writing to an array in memory.  It will
-also spam the kernel logs for every command it handles.
+quick commands to the specified addresses; it will respond to the other
+commands (also to the specified addresses) by reading from or writing to
+arrays in memory.  It will also spam the kernel logs for every command it
+handles.
 
 A pointer register with auto-increment is implemented for all byte
 operations.  This allows for continuous byte reads like those supported by
@@ -26,8 +27,8 @@ The typical use-case is like this:
 
 PARAMETERS:
 
-int chip_addr:
-       The SMBus address to emulate a chip at.
+int chip_addr[10]:
+       The SMBus addresses to emulate chips at.
 
 CAVEATS:
 
@@ -41,9 +42,6 @@ If the hardware for your driver has banked registers (e.g. Winbond sensors
 chips) this module will not work well - although it could be extended to
 support that pretty easily.
 
-Only one chip address is supported - although this module could be
-extended to support more.
-
 If you spam it hard enough, printk can be lossy.  This module really wants
 something like relayfs.
 
index 01d5c3c5691a437ff77177dd1bd06a3f9397cbc0..085e4a095eaaec661ae46a61dda993af3c3cb060 100644 (file)
@@ -1083,6 +1083,13 @@ and is between 256 and 4096 characters. It is defined in the file
                        [NFS] set the maximum lifetime for idmapper cache
                        entries.
 
+       nfs.enable_ino64=
+                       [NFS] enable 64-bit inode numbers.
+                       If zero, the NFS client will fake up a 32-bit inode
+                       number for the readdir() and stat() syscalls instead
+                       of returning the full 64-bit number.
+                       The default is to return 64-bit inode numbers.
+
        nmi_watchdog=   [KNL,BUGS=X86-32] Debugging features for SMP kernels
 
        no387           [BUGS=X86-32] Tells the kernel to use the 387 maths
index 1da566630831729f47734751ae4677a96e6f2f18..11340625e363cbb122b3b61bea966249ed8dcca2 100644 (file)
@@ -281,6 +281,39 @@ downdelay
        will be rounded down to the nearest multiple.  The default
        value is 0.
 
+fail_over_mac
+
+       Specifies whether active-backup mode should set all slaves to
+       the same MAC address (the traditional behavior), or, when
+       enabled, change the bond's MAC address when changing the
+       active interface (i.e., fail over the MAC address itself).
+
+       Fail over MAC is useful for devices that cannot ever alter
+       their MAC address, or for devices that refuse incoming
+       broadcasts with their own source MAC (which interferes with
+       the ARP monitor).
+
+       The down side of fail over MAC is that every device on the
+       network must be updated via gratuitous ARP, vs. just updating
+       a switch or set of switches (which often takes place for any
+       traffic, not just ARP traffic, if the switch snoops incoming
+       traffic to update its tables) for the traditional method.  If
+       the gratuitous ARP is lost, communication may be disrupted.
+
+       When fail over MAC is used in conjuction with the mii monitor,
+       devices which assert link up prior to being able to actually
+       transmit and receive are particularly susecptible to loss of
+       the gratuitous ARP, and an appropriate updelay setting may be
+       required.
+
+       A value of 0 disables fail over MAC, and is the default.  A
+       value of 1 enables fail over MAC.  This option is enabled
+       automatically if the first slave added cannot change its MAC
+       address.  This option may be modified via sysfs only when no
+       slaves are present in the bond.
+
+       This option was added in bonding version 3.2.0.
+
 lacp_rate
 
        Option specifying the rate in which we'll ask our link partner
index 84901e7c05084e1f767d024b7f06cde1f19d6854..88bcb87673354302737be5bbaac5b8c049941d86 100644 (file)
@@ -117,3 +117,70 @@ Some implementation details:
    iterators of the scheduling modules are used. The balancing code got
    quite a bit simpler as a result.
 
+
+Group scheduler extension to CFS
+================================
+
+Normally the scheduler operates on individual tasks and strives to provide
+fair CPU time to each task. Sometimes, it may be desirable to group tasks
+and provide fair CPU time to each such task group. For example, it may
+be desirable to first provide fair CPU time to each user on the system
+and then to each task belonging to a user.
+
+CONFIG_FAIR_GROUP_SCHED strives to achieve exactly that. It lets
+SCHED_NORMAL/BATCH tasks be be grouped and divides CPU time fairly among such
+groups. At present, there are two (mutually exclusive) mechanisms to group
+tasks for CPU bandwidth control purpose:
+
+       - Based on user id (CONFIG_FAIR_USER_SCHED)
+               In this option, tasks are grouped according to their user id.
+       - Based on "cgroup" pseudo filesystem (CONFIG_FAIR_CGROUP_SCHED)
+               This options lets the administrator create arbitrary groups
+               of tasks, using the "cgroup" pseudo filesystem. See
+               Documentation/cgroups.txt for more information about this
+               filesystem.
+
+Only one of these options to group tasks can be chosen and not both.
+
+Group scheduler tunables:
+
+When CONFIG_FAIR_USER_SCHED is defined, a directory is created in sysfs for
+each new user and a "cpu_share" file is added in that directory.
+
+       # cd /sys/kernel/uids
+       # cat 512/cpu_share             # Display user 512's CPU share
+       1024
+       # echo 2048 > 512/cpu_share     # Modify user 512's CPU share
+       # cat 512/cpu_share             # Display user 512's CPU share
+       2048
+       #
+
+CPU bandwidth between two users are divided in the ratio of their CPU shares.
+For ex: if you would like user "root" to get twice the bandwidth of user
+"guest", then set the cpu_share for both the users such that "root"'s
+cpu_share is twice "guest"'s cpu_share
+
+
+When CONFIG_FAIR_CGROUP_SCHED is defined, a "cpu.shares" file is created
+for each group created using the pseudo filesystem. See example steps
+below to create task groups and modify their CPU share using the "cgroups"
+pseudo filesystem
+
+       # mkdir /dev/cpuctl
+       # mount -t cgroup -ocpu none /dev/cpuctl
+       # cd /dev/cpuctl
+
+       # mkdir multimedia      # create "multimedia" group of tasks
+       # mkdir browser         # create "browser" group of tasks
+
+       # #Configure the multimedia group to receive twice the CPU bandwidth
+       # #that of browser group
+
+       # echo 2048 > multimedia/cpu.shares
+       # echo 1024 > browser/cpu.shares
+
+       # firefox &     # Launch firefox and move it to "browser" group
+       # echo <firefox_pid> > browser/tasks
+
+       # #Launch gmplayer (or your favourite movie player)
+       # echo <movie_player_pid> > multimedia/tasks
index 12354830c6b02d8742c19860bdf1c9a1d88ab70c..aa1f7e927834bf8ad7557b9a98eb40e28e3f69b7 100644 (file)
@@ -2,14 +2,20 @@
        - this file
 53c700.txt
        - info on driver for 53c700 based adapters
-AM53C974.txt
-       - info on driver for AM53c974 based adapters
 BusLogic.txt
        - info on driver for adapters with BusLogic chips
-ChangeLog
+ChangeLog.1992-1997
        - Changes to scsi files, if not listed elsewhere
+ChangeLog.arcmsr
+       - Changes to driver for ARECA's SATA RAID controller cards
 ChangeLog.ips
        - IBM ServeRAID driver Changelog
+ChangeLog.lpfc
+       - Changes to lpfc driver
+ChangeLog.megaraid
+       - Changes to LSI megaraid controller.
+ChangeLog.megaraid_sas
+       - Changes to serial attached scsi version of LSI megaraid controller.
 ChangeLog.ncr53c8xx
        - Changes to ncr53c8xx driver
 ChangeLog.sym53c8xx
@@ -20,26 +26,44 @@ FlashPoint.txt
        - info on driver for BusLogic FlashPoint adapters
 LICENSE.FlashPoint
        - Licence of the Flashpoint driver
+LICENSE.qla2xxx
+       - License for QLogic Linux Fibre Channel HBA Driver firmware.
 Mylex.txt
        - info on driver for Mylex adapters
 NinjaSCSI.txt
        - info on WorkBiT NinjaSCSI-32/32Bi driver
+aacraid.txt
+       - Driver supporting Adaptec RAID controllers
 aha152x.txt
        - info on driver for Adaptec AHA152x based adapters
+aic79xx.txt
+       - Adaptec Ultra320 SCSI host adapters
 aic7xxx.txt
        - info on driver for Adaptec controllers
 aic7xxx_old.txt
        - info on driver for Adaptec controllers, old generation
+arcmsr_spec.txt
+       - ARECA FIRMWARE SPEC (for IOP331 adapter)
+dc395x.txt
+       - README file for the dc395x SCSI driver
 dpti.txt
        - info on driver for DPT SmartRAID and Adaptec I2O RAID based adapters
 dtc3x80.txt
        - info on driver for DTC 2x80 based adapters
 g_NCR5380.txt
        - info on driver for NCR5380 and NCR53c400 based adapters
+hptiop.txt
+       - HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
 ibmmca.txt
        - info on driver for IBM adapters with MCA bus
 in2000.txt
        - info on in2000 driver
+libsas.txt
+       - Serial Attached SCSI management layer.
+lpfc.txt
+       - LPFC driver release notes
+megaraid.txt
+       - Common Management Module, shared code handling ioctls for LSI drivers
 ncr53c7xx.txt
        - info on driver for NCR53c7xx based adapters
 ncr53c8xx.txt
@@ -50,6 +74,8 @@ ppa.txt
        - info on driver for IOmega zip drive
 qlogicfas.txt
        - info on driver for QLogic FASxxx based adapters
+scsi-changer.txt
+       - README for the SCSI media changer driver
 scsi-generic.txt
        - info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
 scsi.txt
@@ -58,6 +84,8 @@ scsi_mid_low_api.txt
        - info on API between SCSI layer and low level drivers
 scsi_eh.txt
        - info on SCSI midlayer error handling infrastructure
+scsi_fc_transport.txt
+       - SCSI Fiber Channel Tansport
 st.txt
        - info on scsi tape driver
 sym53c500_cs.txt
index 162c47fdf45f47cff4c1efb01098b045284b286e..cd8403a33ee64ad118000bbfe816611ae39dfeb6 100644 (file)
 **                                             for linux standard list
 **                                             enable usage of pci message signal interrupt
 **                                             follow Randy.Danlup kindness suggestion cleanup this code
-**************************************************************************
\ No newline at end of file
+** 1.20.00.14   05/02/2007      Erich Chen & Nick Cheng
+**                                             1.implement PCI-Express error recovery function and AER capability
+**                                             2.implement the selection of ARCMSR_MAX_XFER_SECTORS_B=4096
+**                                             if firmware version is newer than 1.42
+**                                             3.modify arcmsr_iop_reset to improve the ability
+**                                             4.modify the ISR, arcmsr_interrupt routine,to prevent the
+**                                             inconsistency with sg_mod driver if application directly calls
+**                                             the arcmsr driver w/o passing through scsi mid layer
+**                                             specially thanks to Yanmin Zhang's openhanded help about AER
+** 1.20.00.15   08/30/2007      Erich Chen & Nick Cheng
+**                                             1. support ARC1200/1201/1202 SATA RAID adapter, which is named
+**                                             ACB_ADAPTER_TYPE_B
+**                                             2. modify the arcmsr_pci_slot_reset function
+**                                             3. modify the arcmsr_pci_ers_disconnect_forepart function
+**                                             4. modify the arcmsr_pci_ers_need_reset_forepart function
+**************************************************************************
index cc12b55d4b3dfc8a544ed8232fa82760b0fecd67..a8257840695ae870828514813cf109f2aa767e5f 100644 (file)
@@ -38,10 +38,8 @@ Supported Cards/Chipsets
        9005:0286:9005:02ac     Adaptec 1800 (Typhoon44)
        9005:0285:9005:02b5     Adaptec 5445 (Voodoo44)
        9005:0285:15d9:02b5     SMC     AOC-USAS-S4i
-       9005:0285:15d9:02c9     SMC     AOC-USAS-S4iR
        9005:0285:9005:02b6     Adaptec 5805 (Voodoo80)
        9005:0285:15d9:02b6     SMC     AOC-USAS-S8i
-       9005:0285:15d9:02ca     SMC     AOC-USAS-S8iR
        9005:0285:9005:02b7     Adaptec 5085 (Voodoo08)
        9005:0285:9005:02bb     Adaptec 3405 (Marauder40LP)
        9005:0285:9005:02bc     Adaptec 3805 (Marauder80LP)
@@ -50,9 +48,14 @@ Supported Cards/Chipsets
        9005:0285:9005:02be     Adaptec 31605 (Marauder160)
        9005:0285:9005:02c3     Adaptec 51205 (Voodoo120)
        9005:0285:9005:02c4     Adaptec 51605 (Voodoo160)
+       9005:0285:15d9:02c9     SMC     AOC-USAS-S4iR
+       9005:0285:15d9:02ca     SMC     AOC-USAS-S8iR
        9005:0285:9005:02ce     Adaptec 51245 (Voodoo124)
        9005:0285:9005:02cf     Adaptec 51645 (Voodoo164)
        9005:0285:9005:02d0     Adaptec 52445 (Voodoo244)
+       9005:0285:9005:02d1     Adaptec 5405 (Voodoo40)
+       9005:0285:15d9:02d2     SMC     AOC-USAS-S8i-LP
+       9005:0285:15d9:02d3     SMC     AOC-USAS-S8iR-LP
        1011:0046:9005:0364     Adaptec 5400S (Mustang)
        9005:0287:9005:0800     Adaptec Themisto (Jupiter)
        9005:0200:9005:0200     Adaptec Themisto (Jupiter)
@@ -103,6 +106,7 @@ Supported Cards/Chipsets
        9005:0285:108e:7aac     SUN     STK RAID REM (Voodoo44 Coyote)
        9005:0285:108e:0286     SUN     STK RAID INT (Cougar)
        9005:0285:108e:0287     SUN     STK RAID EXT (Prometheus)
+       9005:0285:108e:7aae     SUN     STK RAID EM (Narvi)
 
 People
 -------------------------
diff --git a/Documentation/scsi/advansys.txt b/Documentation/scsi/advansys.txt
new file mode 100644 (file)
index 0000000..4a3db62
--- /dev/null
@@ -0,0 +1,243 @@
+AdvanSys (Advanced System Products, Inc.) manufactures the following
+RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
+(8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
+buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
+transfer) SCSI Host Adapters for the PCI bus.
+
+The CDB counts below indicate the number of SCSI CDB (Command
+Descriptor Block) requests that can be stored in the RISC chip
+cache and board LRAM. A CDB is a single SCSI command. The driver
+detect routine will display the number of CDBs available for each
+adapter detected. The number of CDBs used by the driver can be
+lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
+
+Laptop Products:
+   ABP-480 - Bus-Master CardBus (16 CDB)
+
+Connectivity Products:
+   ABP510/5150 - Bus-Master ISA (240 CDB)
+   ABP5140 - Bus-Master ISA PnP (16 CDB)
+   ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+   ABP902/3902 - Bus-Master PCI (16 CDB)
+   ABP3905 - Bus-Master PCI (16 CDB)
+   ABP915 - Bus-Master PCI (16 CDB)
+   ABP920 - Bus-Master PCI (16 CDB)
+   ABP3922 - Bus-Master PCI (16 CDB)
+   ABP3925 - Bus-Master PCI (16 CDB)
+   ABP930 - Bus-Master PCI (16 CDB)
+   ABP930U - Bus-Master PCI Ultra (16 CDB)
+   ABP930UA - Bus-Master PCI Ultra (16 CDB)
+   ABP960 - Bus-Master PCI MAC/PC (16 CDB)
+   ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
+
+Single Channel Products:
+   ABP542 - Bus-Master ISA with floppy (240 CDB)
+   ABP742 - Bus-Master EISA (240 CDB)
+   ABP842 - Bus-Master VL (240 CDB)
+   ABP940 - Bus-Master PCI (240 CDB)
+   ABP940U - Bus-Master PCI Ultra (240 CDB)
+   ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
+   ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+   ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
+   ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
+   ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
+   ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
+   ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
+
+Multi-Channel Products:
+   ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
+   ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
+   ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+   ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
+   ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
+   ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
+   ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
+   ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
+   ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
+
+Driver Compile Time Options and Debugging
+
+The following constants can be defined in the source file.
+
+1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
+
+   Enabling this option adds assertion logic statements to the
+   driver. If an assertion fails a message will be displayed to
+   the console, but the system will continue to operate. Any
+   assertions encountered should be reported to the person
+   responsible for the driver. Assertion statements may proactively
+   detect problems with the driver and facilitate fixing these
+   problems. Enabling assertions will add a small overhead to the
+   execution of the driver.
+
+2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
+
+   Enabling this option adds tracing functions to the driver and the
+   ability to set a driver tracing level at boot time.  This option is
+   very useful for debugging the driver, but it will add to the size
+   of the driver execution image and add overhead to the execution of
+   the driver.
+
+   The amount of debugging output can be controlled with the global
+   variable 'asc_dbglvl'. The higher the number the more output. By
+   default the debug level is 0.
+
+   If the driver is loaded at boot time and the LILO Driver Option
+   is included in the system, the debug level can be changed by
+   specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
+   first three hex digits of the pseudo I/O Port must be set to
+   'deb' and the fourth hex digit specifies the debug level: 0 - F.
+   The following command line will look for an adapter at 0x330
+   and set the debug level to 2.
+
+      linux advansys=0x330,0,0,0,0xdeb2
+
+   If the driver is built as a loadable module this variable can be
+   defined when the driver is loaded. The following insmod command
+   will set the debug level to one.
+
+      insmod advansys.o asc_dbglvl=1
+
+   Debugging Message Levels:
+      0: Errors Only
+      1: High-Level Tracing
+      2-N: Verbose Tracing
+
+   To enable debug output to console, please make sure that:
+
+   a. System and kernel logging is enabled (syslogd, klogd running).
+   b. Kernel messages are routed to console output. Check
+      /etc/syslog.conf for an entry similar to this:
+
+           kern.*                  /dev/console
+
+   c. klogd is started with the appropriate -c parameter
+      (e.g. klogd -c 8)
+
+   This will cause printk() messages to be be displayed on the
+   current console. Refer to the klogd(8) and syslogd(8) man pages
+   for details.
+
+   Alternatively you can enable printk() to console with this
+   program. However, this is not the 'official' way to do this.
+   Debug output is logged in /var/log/messages.
+
+     main()
+     {
+             syscall(103, 7, 0, 0);
+     }
+
+   Increasing LOG_BUF_LEN in kernel/printk.c to something like
+   40960 allows more debug messages to be buffered in the kernel
+   and written to the console or log file.
+
+3. ADVANSYS_STATS - Enable statistics (Def: Enabled)
+
+   Enabling this option adds statistics collection and display
+   through /proc to the driver. The information is useful for
+   monitoring driver and device performance. It will add to the
+   size of the driver execution image and add minor overhead to
+   the execution of the driver.
+
+   Statistics are maintained on a per adapter basis. Driver entry
+   point call counts and transfer size counts are maintained.
+   Statistics are only available for kernels greater than or equal
+   to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
+
+   AdvanSys SCSI adapter files have the following path name format:
+
+      /proc/scsi/advansys/{0,1,2,3,...}
+
+   This information can be displayed with cat. For example:
+
+      cat /proc/scsi/advansys/0
+
+   When ADVANSYS_STATS is not defined the AdvanSys /proc files only
+   contain adapter and device configuration information.
+
+Driver LILO Option
+
+If init/main.c is modified as described in the 'Directions for Adding
+the AdvanSys Driver to Linux' section (B.4.) above, the driver will
+recognize the 'advansys' LILO command line and /etc/lilo.conf option.
+This option can be used to either disable I/O port scanning or to limit
+scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
+PCI boards will still be searched for and detected. This option only
+affects searching for ISA and VL boards.
+
+Examples:
+  1. Eliminate I/O port scanning:
+       boot: linux advansys=
+         or
+       boot: linux advansys=0x0
+  2. Limit I/O port scanning to one I/O port:
+       boot: linux advansys=0x110
+  3. Limit I/O port scanning to four I/O ports:
+       boot: linux advansys=0x110,0x210,0x230,0x330
+
+For a loadable module the same effect can be achieved by setting
+the 'asc_iopflag' variable and 'asc_ioport' array when loading
+the driver, e.g.
+
+      insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
+
+If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
+I/O Port may be added to specify the driver debug level. Refer to
+the 'Driver Compile Time Options and Debugging' section above for
+more information.
+
+Credits (Chronological Order)
+
+Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
+and maintained it up to 3.3F. He continues to answer questions
+and help maintain the driver.
+
+Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
+basis for the Linux v1.3.X changes which were included in the
+1.2 release.
+
+Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
+in advansys_biosparam() which was fixed in the 1.3 release.
+
+Erik Ratcliffe <erik@caldera.com> has done testing of the
+AdvanSys driver in the Caldera releases.
+
+Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
+AscWaitTixISRDone() which he found necessary to make the
+driver work with a SCSI-1 disk.
+
+Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
+support in the 3.1A driver.
+
+Doug Gilbert <dgilbert@interlog.com> has made changes and
+suggestions to improve the driver and done a lot of testing.
+
+Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
+in 3.2K.
+
+Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
+patch and helped with PowerPC wide and narrow board support.
+
+Philip Blundell <philb@gnu.org> provided an
+advansys_interrupts_enabled patch.
+
+Dave Jones <dave@denial.force9.co.uk> reported the compiler
+warnings generated when CONFIG_PROC_FS was not defined in
+the 3.2M driver.
+
+Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
+problems) for wide cards.
+
+Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
+card error handling.
+
+Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
+board support and fixed a bug in AscGetEEPConfig().
+
+Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
+save_flags/restore_flags changes.
+
+Andy Kellner <AKellner@connectcom.net> continued the Advansys SCSI
+driver development for ConnectCom (Version > 3.3F).
+
+Ken Witherow for extensive testing during the development of version 3.4.
index 8418d35484fc850b28ec0744a1b8aa4751d8d2b2..eb1e28ad8822f32421db93dd211f1e2be0084488 100644 (file)
@@ -67,10 +67,12 @@ probe in an SBUS driver under Linux:
        MODULE_DEVICE_TABLE(of, mydevice_match);
 
        static struct of_platform_driver mydevice_driver = {
-               .name           = "mydevice",
                .match_table    = mydevice_match,
                .probe          = mydevice_probe,
                .remove         = __devexit_p(mydevice_remove),
+               .driver         = {
+                       .name           = "mydevice",
+               },
        };
 
        static int __init mydevice_init(void)
index 0fdb8a50b92158f0997990f612d16c861b6085c3..c7355e7f09ff3e2e1bccc93f9d0c06b1484b0442 100644 (file)
@@ -297,6 +297,12 @@ P: Colin Leroy
 M:     colin@colino.net
 S:     Maintained
 
+ADVANSYS SCSI DRIVER
+P:     Matthew Wilcox
+M:     matthew@wil.cx
+L:     linux-scsi@vger.kernel.org
+S:     Maintained
+
 AEDSP16 DRIVER
 P:     Riccardo Facchetti
 M:     fizban@tin.it
@@ -1660,7 +1666,8 @@ P:        Mark M. Hoffman
 M:     mhoffman@lightlink.com
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
-T:     git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git
+T:     git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git testing
+T:     git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git release
 S:     Maintained
 
 HARDWARE RANDOM NUMBER GENERATOR CORE
@@ -1888,6 +1895,11 @@ M:       Gadi Oxman <gadio@netvision.net.il>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+IDE-SCSI DRIVER
+L:     linux-ide@vger.kernel.org
+L:     linux-scsi@vger.kernel.org
+S:     Orphan
+
 IEEE 1394 SUBSYSTEM
 P:     Ben Collins
 M:     ben.collins@ubuntu.com
@@ -2392,6 +2404,15 @@ M:       khali@linux-fr.org
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 
+LOCKDEP AND LOCKSTAT
+P:     Peter Zijlstra
+M:     peterz@infradead.org
+P:     Ingo Molnar
+M:     mingo@redhat.com
+L:     linux-kernel@vger.kernel.org
+T:     git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-lockdep.git
+S:     Maintained
+
 LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks)
 P:     Richard Russon (FlatCap)
 M:     ldm@flatcap.org
@@ -2403,7 +2424,7 @@ LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
 P:     Eric Moore
 M:     Eric.Moore@lsi.com
 M:     support@lsi.com
-L:     mpt_linux_developer@lsi.com
+L:     DL-MPTFusionLinux@lsi.com
 L:     linux-scsi@vger.kernel.org
 W:     http://www.lsilogic.com/support
 S:     Supported
@@ -4177,7 +4198,7 @@ W83791D HARDWARE MONITORING DRIVER
 P:     Charles Spirakis
 M:     bezaur@gmail.com
 L:     lm-sensors@lm-sensors.org
-S:     Maintained
+S:     Odd Fixes
 
 W83793 HARDWARE MONITORING DRIVER
 P:     Rudolf Marek
index 48c8c9195dc3ed339ac26f403f48c59a86fc7733..2f8f6ecf111f3ccbac765c6644e8bc274ee7e0d1 100644 (file)
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/i2c.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/input.h>
-#include <linux/workqueue.h>
 
 #include <asm/hardware.h>
+#include <asm/gpio.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/irda.h>
@@ -277,6 +278,20 @@ static struct platform_device *h2_devices[] __initdata = {
        &h2_mcbsp1_device,
 };
 
+static struct i2c_board_info __initdata h2_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("tps65010", 0x48),
+               .type           = "tps65010",
+               .irq            = OMAP_GPIO_IRQ(58),
+       },
+       /* TODO when driver support is ready:
+        *  - isp1301 OTG transceiver
+        *  - optional ov9640 camera sensor at 0x30
+        *  - pcf9754 for aGPS control
+        *  - ... etc
+        */
+};
+
 static void __init h2_init_smc91x(void)
 {
        if ((omap_request_gpio(0)) < 0) {
@@ -367,6 +382,14 @@ static void __init h2_init(void)
        omap_board_config = h2_config;
        omap_board_config_size = ARRAY_SIZE(h2_config);
        omap_serial_init();
+
+       /* irq for tps65010 chip */
+       omap_cfg_reg(W4_GPIO58);
+       if (gpio_request(58, "tps65010") == 0)
+               gpio_direction_input(58);
+
+       i2c_register_board_info(1, h2_i2c_board_info,
+                       ARRAY_SIZE(h2_i2c_board_info));
 }
 
 static void __init h2_map_io(void)
@@ -374,6 +397,22 @@ static void __init h2_map_io(void)
        omap1_map_common_io();
 }
 
+#ifdef CONFIG_TPS65010
+static int __init h2_tps_init(void)
+{
+       if (!machine_is_omap_h2())
+               return 0;
+
+       /* gpio3 for SD, gpio4 for VDD_DSP */
+       /* FIXME send power to DSP iff it's configured */
+
+       /* Enable LOW_PWR */
+       tps65010_set_low_pwr(ON);
+       return 0;
+}
+fs_initcall(h2_tps_init);
+#endif
+
 MACHINE_START(OMAP_H2, "TI-H2")
        /* Maintainer: Imre Deak <imre.deak@nokia.com> */
        .phys_io        = 0xfff00000,
index 79d4ef4c54d4818918b216db9da312d24e14b0bf..add2f703204fae66cefbe2e8261bed4b63348f93 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/errno.h>
 #include <linux/workqueue.h>
+#include <linux/i2c.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/hardware.h>
+#include <asm/gpio.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
 #include <asm/arch/gpioexpander.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/mux.h>
@@ -413,6 +416,19 @@ static struct omap_board_config_kernel h3_config[] = {
        { OMAP_TAG_LCD,         &h3_lcd_config },
 };
 
+static struct i2c_board_info __initdata h3_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("tps65010", 0x48),
+               .type           = "tps65013",
+               /* .irq         = OMAP_GPIO_IRQ(??), */
+       },
+       /* TODO when driver support is ready:
+        *  - isp1301 OTG transceiver
+        *  - optional ov9640 camera sensor at 0x30
+        *  - ...
+        */
+};
+
 #define H3_NAND_RB_GPIO_PIN    10
 
 static int nand_dev_ready(struct nand_platform_data *data)
@@ -446,6 +462,10 @@ static void __init h3_init(void)
        omap_board_config = h3_config;
        omap_board_config_size = ARRAY_SIZE(h3_config);
        omap_serial_init();
+
+       /* FIXME setup irq for tps65013 chip */
+       i2c_register_board_info(1, h3_i2c_board_info,
+                       ARRAY_SIZE(h3_i2c_board_info));
 }
 
 static void __init h3_init_smc91x(void)
@@ -470,6 +490,23 @@ static void __init h3_map_io(void)
        omap1_map_common_io();
 }
 
+#ifdef CONFIG_TPS65010
+static int __init h3_tps_init(void)
+{
+       if (!machine_is_omap_h3())
+               return 0;
+
+       /* gpio4 for SD, gpio3 for VDD_DSP */
+       /* FIXME send power to DSP iff it's configured */
+
+       /* Enable LOW_PWR */
+       tps65013_set_low_pwr(ON);
+
+       return 0;
+}
+fs_initcall(h3_tps_init);
+#endif
+
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
        /* Maintainer: Texas Instruments, Inc. */
        .phys_io        = 0xfff00000,
index e7130293a03fbc2e96346aeb5d22aa6b7e20ee1a..a61bf455ee02ac3552aebaf2f54e68692456c73e 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/i2c.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/hardware.h>
+#include <asm/gpio.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 
-#include <asm/arch/gpio.h>
 #include <asm/arch/usb.h>
+#include <asm/arch/tps65010.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/common.h>
@@ -179,6 +182,19 @@ static struct platform_device *osk5912_devices[] __initdata = {
        &osk5912_mcbsp1_device,
 };
 
+static struct i2c_board_info __initdata osk_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("tps65010", 0x48),
+               .type           = "tps65010",
+               .irq            = OMAP_GPIO_IRQ(OMAP_MPUIO(1)),
+       },
+       /* TODO when driver support is ready:
+        *  - aic23 audio chip at 0x1a
+        *  - on Mistral, 24c04 eeprom at 0x50
+        *  - optionally on Mistral, ov9640 camera sensor at 0x30
+        */
+};
+
 static void __init osk_init_smc91x(void)
 {
        if ((omap_request_gpio(0)) < 0) {
@@ -397,6 +413,14 @@ static void __init osk_init(void)
        omap_board_config_size = ARRAY_SIZE(osk_config);
        USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
 
+       /* irq for tps65010 chip */
+       /* bootloader effectively does:  omap_cfg_reg(U19_1610_MPUIO1); */
+       if (gpio_request(OMAP_MPUIO(1), "tps65010") == 0)
+               gpio_direction_input(OMAP_MPUIO(1));
+
+       i2c_register_board_info(1, osk_i2c_board_info,
+                       ARRAY_SIZE(osk_i2c_board_info));
+
        omap_serial_init();
        osk_mistral_init();
 }
@@ -406,6 +430,44 @@ static void __init osk_map_io(void)
        omap1_map_common_io();
 }
 
+#ifdef CONFIG_TPS65010
+static int __init osk_tps_init(void)
+{
+       if (!machine_is_omap_osk())
+               return 0;
+
+       /* Let LED1 (D9) blink */
+       tps65010_set_led(LED1, BLINK);
+
+       /* Disable LED 2 (D2) */
+       tps65010_set_led(LED2, OFF);
+
+       /* Set GPIO 1 HIGH to disable VBUS power supply;
+        * OHCI driver powers it up/down as needed.
+        */
+       tps65010_set_gpio_out_value(GPIO1, HIGH);
+
+       /* Set GPIO 2 low to turn on LED D3 */
+       tps65010_set_gpio_out_value(GPIO2, HIGH);
+
+       /* Set GPIO 3 low to take ethernet out of reset */
+       tps65010_set_gpio_out_value(GPIO3, LOW);
+
+       /* gpio4 for VDD_DSP */
+       /* FIXME send power to DSP iff it's configured */
+
+       /* Enable LOW_PWR */
+       tps65010_set_low_pwr(ON);
+
+       /* Switch VLDO2 to 3.0V for AIC23 */
+       tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V
+                       | TPS_LDO1_ENABLE);
+
+       return 0;
+}
+fs_initcall(osk_tps_init);
+#endif
+
 MACHINE_START(OMAP_OSK, "TI-OSK")
        /* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
        .phys_io        = 0xfff00000,
index f1486f8a3e6d3decf4e504e76454ad270bc3c499..bf9aafad49788a49d5dc331a7189eb88ae3eb082 100644 (file)
@@ -214,6 +214,17 @@ config X86_ES7000
 
 endchoice
 
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+       bool "Single-depth WCHAN output"
+       default y
+       help
+         Calculate simpler /proc/<PID>/wchan values. If this option
+         is disabled then wchan values will recurse back to the
+         caller function. This provides more accurate wchan values,
+         at the expense of slightly more scheduling overhead.
+
+         If in doubt, say "Y".
+
 config PARAVIRT
        bool "Paravirtualization support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
index 8c39913d17290c48fc9b60d260c49f58b9ab3d1e..2e6310b8eab71e9eeb3bc61fbfc7b0806f6250b3 100644 (file)
@@ -461,6 +461,16 @@ config IA64_ESI
          firmware extensions, such as the ability to inject memory-errors
          for test-purposes.  If you're unsure, say N.
 
+config IA64_HP_AML_NFW
+       bool "Support ACPI AML calls to native firmware"
+       help
+         This driver installs a global ACPI Operation Region handler for
+         region 0xA1.  AML methods can use this OpRegion to call arbitrary
+         native firmware functions.  The driver installs the OpRegion
+         handler if there is an HPQ5001 device or if the user supplies
+         the "force" module parameter, e.g., with the "aml_nfw.force"
+         kernel command line option.
+
 source "drivers/sn/Kconfig"
 
 config KEXEC
index 9aecfceeb38c6350c8ecae74b735f825ab8310f4..449d3e75bfc29153752a4f732ce1d07ee6719891 100644 (file)
@@ -1,40 +1,40 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc1
-# Mon Oct  9 10:53:59 2006
+# Linux kernel version: 2.6.23-rc6
+# Tue Sep 18 11:24:01 2007
 #
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_TASKSTATS=y
 # CONFIG_TASK_DELAY_ACCT is not set
-# CONFIG_UTS_NS is not set
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=20
 CONFIG_CPUSETS=y
+CONFIG_SYSFS_DEPRECATED=y
 CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_TASK_XACCT=y
 CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
-# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -44,18 +44,20 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLUB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -63,12 +65,9 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_BLK_DEV_BSG=y
 
 #
 # IO Schedulers
@@ -88,12 +87,15 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 #
 CONFIG_IA64=y
 CONFIG_64BIT=y
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
-CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
@@ -116,6 +118,7 @@ CONFIG_IA64_PAGE_SIZE_16KB=y
 CONFIG_PGTABLE_4=y
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_IA64_L1_CACHE_SHIFT=7
@@ -128,7 +131,10 @@ CONFIG_NR_CPUS=1024
 # CONFIG_HOTPLUG_CPU is not set
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_SCHED_SMT=y
-CONFIG_PREEMPT=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
 CONFIG_SELECT_MEMORY_MODEL=y
 # CONFIG_FLATMEM_MANUAL is not set
 CONFIG_DISCONTIGMEM_MANUAL=y
@@ -140,6 +146,9 @@ CONFIG_NEED_MULTIPLE_NODES=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_MIGRATION=y
 CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -154,16 +163,17 @@ CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
 CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
 CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
+CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
+CONFIG_IA64_MC_ERR_INJECT=y
 CONFIG_SGI_SN=y
 # CONFIG_IA64_ESI is not set
 
 #
 # SN Devices
 #
-CONFIG_SGI_IOC4=y
 CONFIG_SGI_IOC3=y
 
 #
@@ -171,6 +181,7 @@ CONFIG_SGI_IOC3=y
 #
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
@@ -180,12 +191,9 @@ CONFIG_BINFMT_ELF=y
 CONFIG_PM=y
 # CONFIG_PM_LEGACY is not set
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
 CONFIG_ACPI=y
+# CONFIG_ACPI_PROCFS is not set
+CONFIG_ACPI_PROC_EVENT=y
 # CONFIG_ACPI_BUTTON is not set
 # CONFIG_ACPI_FAN is not set
 # CONFIG_ACPI_DOCK is not set
@@ -208,17 +216,14 @@ CONFIG_ACPI_SYSTEM=y
 #
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_HOTPLUG_PCI_PCIE=y
 # CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
 CONFIG_PCIEAER=y
+CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
-# CONFIG_PCI_MULTITHREAD_PROBE is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=y
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 # CONFIG_HOTPLUG_PCI_ACPI is not set
@@ -239,13 +244,13 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -261,7 +266,7 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
@@ -270,9 +275,11 @@ CONFIG_INET_TCP_DIAG=m
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 CONFIG_IPV6=m
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 # CONFIG_INET6_IPCOMP is not set
@@ -283,25 +290,13 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
 CONFIG_INET6_XFRM_MODE_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_BEET=m
 # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
 # CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_SUBTREES is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -327,7 +322,17 @@ CONFIG_INET6_XFRM_MODE_BEET=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -340,31 +345,19 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
 
 #
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
+# Protocols
 #
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -379,13 +372,13 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
 CONFIG_ATA_OVER_ETH=m
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_SGI_IOC4=y
+# CONFIG_TIFM_CORE is not set
 CONFIG_IDE=y
 CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
@@ -400,20 +393,23 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_IDEACPI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -428,6 +424,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_BLK_DEV_JMICRON is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
 # CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
@@ -438,10 +435,10 @@ CONFIG_BLK_DEV_SGIIOC4=y
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -449,6 +446,8 @@ CONFIG_IDEDMA_AUTO=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
 
@@ -469,6 +468,8 @@ CONFIG_CHR_DEV_SCH=m
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -478,11 +479,9 @@ CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=y
 CONFIG_SCSI_SAS_LIBSAS=y
+# CONFIG_SCSI_SAS_ATA is not set
 # CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
-
-#
-# SCSI low-level drivers
-#
+CONFIG_SCSI_LOWLEVEL=y
 CONFIG_ISCSI_TCP=m
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
@@ -512,11 +511,10 @@ CONFIG_SCSI_QLA_FC=y
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
+# CONFIG_SCSI_SRP is not set
 CONFIG_ATA=y
+CONFIG_ATA_NONSTANDARD=y
+CONFIG_ATA_ACPI=y
 # CONFIG_SATA_AHCI is not set
 # CONFIG_SATA_SVW is not set
 # CONFIG_ATA_PIIX is not set
@@ -532,10 +530,12 @@ CONFIG_ATA=y
 # CONFIG_SATA_ULI is not set
 # CONFIG_SATA_VIA is not set
 CONFIG_SATA_VITESSE=y
+# CONFIG_SATA_INIC162X is not set
 # CONFIG_PATA_ALI is not set
 # CONFIG_PATA_AMD is not set
 # CONFIG_PATA_ARTOP is not set
 # CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
 # CONFIG_PATA_CMD64X is not set
 # CONFIG_PATA_CS5520 is not set
 # CONFIG_PATA_CS5530 is not set
@@ -547,8 +547,10 @@ CONFIG_SATA_VITESSE=y
 # CONFIG_PATA_HPT3X2N is not set
 # CONFIG_PATA_HPT3X3 is not set
 # CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
 # CONFIG_PATA_JMICRON is not set
 # CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
 # CONFIG_PATA_MPIIX is not set
 # CONFIG_PATA_OLDPIIX is not set
 # CONFIG_PATA_NETCELL is not set
@@ -565,10 +567,6 @@ CONFIG_SATA_VITESSE=y
 # CONFIG_PATA_SIS is not set
 # CONFIG_PATA_VIA is not set
 # CONFIG_PATA_WINBOND is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
@@ -587,6 +585,8 @@ CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 CONFIG_DM_MULTIPATH_EMC=m
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -597,43 +597,25 @@ CONFIG_FUSION_FC=y
 CONFIG_FUSION_SAS=y
 CONFIG_FUSION_MAX_SGE=128
 CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LOGGING=y
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_NET_SB1000 is not set
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
-
-#
-# Ethernet (10 or 100Mbit)
-#
 # CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
@@ -645,32 +627,39 @@ CONFIG_NETDEVICES=y
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
 CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+# CONFIG_CHELSIO_T1_NAPI is not set
+CONFIG_CHELSIO_T3=m
 # CONFIG_IXGB is not set
 CONFIG_S2IO=m
 # CONFIG_S2IO_NAPI is not set
 # CONFIG_MYRI10GE is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -680,18 +669,9 @@ CONFIG_S2IO=m
 # CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -699,6 +679,7 @@ CONFIG_NET_POLL_CONTROLLER=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -718,6 +699,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -741,6 +723,7 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_DIGIEPCA is not set
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
+# CONFIG_MOXA_SMARTIO_NEW is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
 # CONFIG_SYNCLINK_GT is not set
@@ -752,7 +735,6 @@ CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SGI_SNSC=y
 CONFIG_SGI_TIOCX=y
 CONFIG_SGI_MBCS=m
-CONFIG_MSPEC=y
 
 #
 # Serial drivers
@@ -771,28 +753,13 @@ CONFIG_SERIAL_SGI_IOC3=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
 CONFIG_AGP=y
-# CONFIG_AGP_SIS is not set
-# CONFIG_AGP_VIA is not set
 CONFIG_AGP_SGI_TIOCA=y
 # CONFIG_DRM is not set
 CONFIG_RAW_DRIVER=m
@@ -800,16 +767,8 @@ CONFIG_MAX_RAW_DEVS=256
 # CONFIG_HPET is not set
 # CONFIG_HANGCHECK_TIMER is not set
 CONFIG_MMTIMER=y
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -817,37 +776,33 @@ CONFIG_MMTIMER=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
-# Misc devices
+# Multifunction device drivers
 #
-# CONFIG_TIFM_CORE is not set
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
-# CONFIG_USB_DABUSB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 # CONFIG_FB is not set
 
 #
@@ -856,16 +811,29 @@ CONFIG_FIRMWARE_EDID=y
 CONFIG_VGA_CONSOLE=y
 # CONFIG_VGACON_SOFT_SCROLLBACK is not set
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
 #
 # CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
 
 #
-# USB support
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
 #
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -876,9 +844,10 @@ CONFIG_USB=m
 # Miscellaneous USB options
 #
 # CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -890,10 +859,12 @@ CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=m
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -911,48 +882,11 @@ CONFIG_USB_UHCI_HCD=m
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
 CONFIG_USB_MON=y
 
 #
@@ -974,6 +908,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -983,6 +918,8 @@ CONFIG_USB_MON=y
 # CONFIG_USB_APPLEDISPLAY is not set
 # CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
 
 #
 # USB DSL modem support
@@ -992,48 +929,24 @@ CONFIG_USB_MON=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
 CONFIG_INFINIBAND=m
 # CONFIG_INFINIBAND_USER_MAD is not set
 CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_USER_MEM=y
 CONFIG_INFINIBAND_ADDR_TRANS=y
 CONFIG_INFINIBAND_MTHCA=m
 CONFIG_INFINIBAND_MTHCA_DEBUG=y
 # CONFIG_INFINIBAND_AMSO1100 is not set
+# CONFIG_INFINIBAND_CXGB3 is not set
+# CONFIG_MLX4_INFINIBAND is not set
 CONFIG_INFINIBAND_IPOIB=m
+# CONFIG_INFINIBAND_IPOIB_CM is not set
 CONFIG_INFINIBAND_IPOIB_DEBUG=y
 # CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
 CONFIG_INFINIBAND_SRP=m
 # CONFIG_INFINIBAND_ISER is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
 # CONFIG_RTC_CLASS is not set
 
 #
@@ -1049,6 +962,12 @@ CONFIG_INFINIBAND_SRP=m
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+CONFIG_MSPEC=y
+
 #
 # File systems
 #
@@ -1061,6 +980,7 @@ CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
@@ -1161,6 +1081,7 @@ CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
+# CONFIG_SUNRPC_BIND34 is not set
 CONFIG_RPCSEC_GSS_KRB5=m
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
@@ -1174,7 +1095,6 @@ CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1196,6 +1116,7 @@ CONFIG_SGI_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -1244,18 +1165,25 @@ CONFIG_NLS_UTF8=y
 #
 # Distributed Lock Manager
 #
+# CONFIG_DLM is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
 CONFIG_GENERIC_ALLOCATOR=y
 CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
@@ -1274,25 +1202,28 @@ CONFIG_IRQ_PER_CPU=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=20
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_RWSEMS is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 CONFIG_IA64_GRANULE_16MB=y
 # CONFIG_IA64_GRANULE_64MB is not set
 # CONFIG_IA64_PRINT_HAZARDS is not set
@@ -1306,16 +1237,17 @@ CONFIG_SYSVIPC_COMPAT=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=m
 CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=y
@@ -1324,9 +1256,14 @@ CONFIG_CRYPTO_SHA1=m
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
@@ -1340,8 +1277,6 @@ CONFIG_CRYPTO_DES=m
 CONFIG_CRYPTO_DEFLATE=m
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_HW is not set
index f61a60057ff7dd555ed75fba0bf7870f3e919ee3..9e179dd06b8506548454e6fd35a009e7c1bc2d13 100644 (file)
@@ -8,3 +8,4 @@
 obj-y := sba_iommu.o
 obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += hwsw_iommu.o
 obj-$(CONFIG_IA64_GENERIC) += hwsw_iommu.o
+obj-$(CONFIG_IA64_HP_AML_NFW) += aml_nfw.o
diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c
new file mode 100644 (file)
index 0000000..4abd2c7
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * OpRegion handler to allow AML to call native firmware
+ *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver implements HP Open Source Review Board proposal 1842,
+ * which was approved on 9/20/2006.
+ *
+ * For technical documentation, see the HP SPPA Firmware EAS, Appendix F.
+ *
+ * ACPI does not define a mechanism for AML methods to call native firmware
+ * interfaces such as PAL or SAL.  This OpRegion handler adds such a mechanism.
+ * After the handler is installed, an AML method can call native firmware by
+ * storing the arguments and firmware entry point to specific offsets in the
+ * OpRegion.  When AML reads the "return value" offset from the OpRegion, this
+ * handler loads up the arguments, makes the firmware call, and returns the
+ * result.
+ */
+
+#include <linux/module.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <asm/sal.h>
+
+MODULE_AUTHOR("Bjorn Helgaas <bjorn.helgaas@hp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ACPI opregion handler for native firmware calls");
+
+static int force_register;
+module_param_named(force, force_register, bool, 0);
+MODULE_PARM_DESC(force, "Install opregion handler even without HPQ5001 device");
+
+#define AML_NFW_SPACE          0xA1
+
+struct ia64_pdesc {
+       void *ip;
+       void *gp;
+};
+
+/*
+ * N.B.  The layout of this structure is defined in the HP SPPA FW EAS, and
+ *      the member offsets are embedded in AML methods.
+ */
+struct ia64_nfw_context {
+       u64 arg[8];
+       struct ia64_sal_retval ret;
+       u64 ip;
+       u64 gp;
+       u64 pad[2];
+};
+
+static void *virt_map(u64 address)
+{
+       if (address & (1UL << 63))
+               return (void *) (__IA64_UNCACHED_OFFSET | address);
+
+       return __va(address);
+}
+
+static void aml_nfw_execute(struct ia64_nfw_context *c)
+{
+       struct ia64_pdesc virt_entry;
+       ia64_sal_handler entry;
+
+       virt_entry.ip = virt_map(c->ip);
+       virt_entry.gp = virt_map(c->gp);
+
+       entry = (ia64_sal_handler) &virt_entry;
+
+       IA64_FW_CALL(entry, c->ret,
+                    c->arg[0], c->arg[1], c->arg[2], c->arg[3],
+                    c->arg[4], c->arg[5], c->arg[6], c->arg[7]);
+}
+
+static void aml_nfw_read_arg(u8 *offset, u32 bit_width, acpi_integer *value)
+{
+       switch (bit_width) {
+       case 8:
+               *value = *(u8 *)offset;
+               break;
+       case 16:
+               *value = *(u16 *)offset;
+               break;
+       case 32:
+               *value = *(u32 *)offset;
+               break;
+       case 64:
+               *value = *(u64 *)offset;
+               break;
+       }
+}
+
+static void aml_nfw_write_arg(u8 *offset, u32 bit_width, acpi_integer *value)
+{
+       switch (bit_width) {
+       case 8:
+               *(u8 *) offset = *value;
+               break;
+       case 16:
+               *(u16 *) offset = *value;
+               break;
+       case 32:
+               *(u32 *) offset = *value;
+               break;
+       case 64:
+               *(u64 *) offset = *value;
+               break;
+       }
+}
+
+static acpi_status aml_nfw_handler(u32 function, acpi_physical_address address,
+       u32 bit_width, acpi_integer *value, void *handler_context,
+       void *region_context)
+{
+       struct ia64_nfw_context *context = handler_context;
+       u8 *offset = (u8 *) context + address;
+
+       if (bit_width !=  8 && bit_width != 16 &&
+           bit_width != 32 && bit_width != 64)
+               return AE_BAD_PARAMETER;
+
+       if (address + (bit_width >> 3) > sizeof(struct ia64_nfw_context))
+               return AE_BAD_PARAMETER;
+
+       switch (function) {
+       case ACPI_READ:
+               if (address == offsetof(struct ia64_nfw_context, ret))
+                       aml_nfw_execute(context);
+               aml_nfw_read_arg(offset, bit_width, value);
+               break;
+       case ACPI_WRITE:
+               aml_nfw_write_arg(offset, bit_width, value);
+               break;
+       }
+
+       return AE_OK;
+}
+
+static struct ia64_nfw_context global_context;
+static int global_handler_registered;
+
+static int aml_nfw_add_global_handler(void)
+{
+       acpi_status status;
+
+       if (global_handler_registered)
+               return 0;
+
+       status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
+               AML_NFW_SPACE, aml_nfw_handler, NULL, &global_context);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       global_handler_registered = 1;
+       printk(KERN_INFO "Global 0x%02X opregion handler registered\n",
+               AML_NFW_SPACE);
+       return 0;
+}
+
+static int aml_nfw_remove_global_handler(void)
+{
+       acpi_status status;
+
+       if (!global_handler_registered)
+               return 0;
+
+       status = acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
+               AML_NFW_SPACE, aml_nfw_handler);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       global_handler_registered = 0;
+       printk(KERN_INFO "Global 0x%02X opregion handler removed\n",
+               AML_NFW_SPACE);
+       return 0;
+}
+
+static int aml_nfw_add(struct acpi_device *device)
+{
+       /*
+        * We would normally allocate a new context structure and install
+        * the address space handler for the specific device we found.
+        * But the HP-UX implementation shares a single global context
+        * and always puts the handler at the root, so we'll do the same.
+        */
+       return aml_nfw_add_global_handler();
+}
+
+static int aml_nfw_remove(struct acpi_device *device, int type)
+{
+       return aml_nfw_remove_global_handler();
+}
+
+static const struct acpi_device_id aml_nfw_ids[] = {
+       {"HPQ5001", 0},
+       {"", 0}
+};
+
+static struct acpi_driver acpi_aml_nfw_driver = {
+       .name = "native firmware",
+       .ids = aml_nfw_ids,
+       .ops = {
+               .add = aml_nfw_add,
+               .remove = aml_nfw_remove,
+               },
+};
+
+static int __init aml_nfw_init(void)
+{
+       int result;
+
+       if (force_register)
+               aml_nfw_add_global_handler();
+
+       result = acpi_bus_register_driver(&acpi_aml_nfw_driver);
+       if (result < 0) {
+               aml_nfw_remove_global_handler();
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit aml_nfw_exit(void)
+{
+       acpi_bus_unregister_driver(&acpi_aml_nfw_driver);
+       aml_nfw_remove_global_handler();
+}
+
+module_init(aml_nfw_init);
+module_exit(aml_nfw_exit);
index 4552a1cf5b338f5a7aa2f03175a07a6cd5f35959..d62fa76e5a7d05680a3fcf2d1dc75faee35e88dc 100644 (file)
@@ -372,8 +372,13 @@ simscsi_init(void)
                return -ENOMEM;
 
        error = scsi_add_host(host, NULL);
-       if (!error)
-               scsi_scan_host(host);
+       if (error)
+               goto free_host;
+       scsi_scan_host(host);
+       return 0;
+
+ free_host:
+       scsi_host_put(host);
        return error;
 }
 
index 1d64ef478dde9397ec99e5dace2ce9e52ba996d9..f1cf2df97a2d3f2602e2da6432f3e348567fe5f7 100644 (file)
@@ -118,11 +118,6 @@ machine_crash_shutdown(struct pt_regs *pt)
 static void
 machine_kdump_on_init(void)
 {
-       if (!ia64_kimage) {
-               printk(KERN_NOTICE "machine_kdump_on_init(): "
-                               "kdump not configured\n");
-               return;
-       }
        local_irq_disable();
        kexec_disable_iosapic();
        machine_kexec(ia64_kimage);
@@ -156,6 +151,14 @@ kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
        if (!kdump_on_init)
                return NOTIFY_DONE;
 
+       if (!ia64_kimage) {
+               if (val == DIE_INIT_MONARCH_LEAVE)
+                       ia64_mca_printk(KERN_NOTICE
+                                       "%s: kdump not configured\n",
+                                       __FUNCTION__);
+               return NOTIFY_DONE;
+       }
+
        if (val != DIE_INIT_MONARCH_LEAVE &&
            val != DIE_INIT_SLAVE_LEAVE &&
            val != DIE_INIT_MONARCH_PROCESS &&
index 4f0f3b8c1ee2b14cdd6b498fae39bb94fc818f18..58e943a5d95c6256778704e3e4e33de36e5188e6 100644 (file)
@@ -79,7 +79,6 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
        relocate_new_kernel_t rnk;
        void *pal_addr = efi_get_pal_addr();
        unsigned long code_addr = (unsigned long)page_address(image->control_code_page);
-       unsigned long vector;
        int ii;
 
        BUG_ON(!image);
@@ -107,11 +106,8 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
        /* unmask TPR and clear any pending interrupts */
        ia64_setreg(_IA64_REG_CR_TPR, 0);
        ia64_srlz_d();
-       vector = ia64_get_ivr();
-       while (vector != IA64_SPURIOUS_INT_VECTOR) {
+       while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR)
                ia64_eoi();
-               vector = ia64_get_ivr();
-       }
        platform_kernel_launch_event();
        rnk = (relocate_new_kernel_t)&code_addr;
        (*rnk)(image->head, image->start, ia64_boot_param,
index 63b73f3d4c9f9a7a2d0cbb6866c5cc2dfa9d3c26..cc87025e8f54c0d2656584376949a44642432815 100644 (file)
@@ -701,8 +701,7 @@ ia64_mca_cmc_vector_enable_keventd(struct work_struct *unused)
 /*
  * ia64_mca_wakeup
  *
- *     Send an inter-cpu interrupt to wake-up a particular cpu
- *     and mark that cpu to be out of rendez.
+ *     Send an inter-cpu interrupt to wake-up a particular cpu.
  *
  *  Inputs  :   cpuid
  *  Outputs :   None
@@ -711,14 +710,12 @@ static void
 ia64_mca_wakeup(int cpu)
 {
        platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
-       ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
-
 }
 
 /*
  * ia64_mca_wakeup_all
  *
- *     Wakeup all the cpus which have rendez'ed previously.
+ *     Wakeup all the slave cpus which have rendez'ed previously.
  *
  *  Inputs  :   None
  *  Outputs :   None
@@ -741,7 +738,10 @@ ia64_mca_wakeup_all(void)
  *
  *     This is handler used to put slave processors into spinloop
  *     while the monarch processor does the mca handling and later
- *     wake each slave up once the monarch is done.
+ *     wake each slave up once the monarch is done.  The state
+ *     IA64_MCA_RENDEZ_CHECKIN_DONE indicates the cpu is rendez'ed
+ *     in SAL.  The state IA64_MCA_RENDEZ_CHECKIN_NOTDONE indicates
+ *     the cpu has come out of OS rendezvous.
  *
  *  Inputs  :   None
  *  Outputs :   None
@@ -778,6 +778,7 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg)
                       (long)&nd, 0, 0) == NOTIFY_STOP)
                ia64_mca_spin(__FUNCTION__);
 
+       ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
        /* Enable all interrupts */
        local_irq_restore(flags);
        return IRQ_HANDLED;
@@ -1135,30 +1136,27 @@ no_mod:
 static void
 ia64_wait_for_slaves(int monarch, const char *type)
 {
-       int c, wait = 0, missing = 0;
-       for_each_online_cpu(c) {
-               if (c == monarch)
-                       continue;
-               if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) {
-                       udelay(1000);           /* short wait first */
-                       wait = 1;
-                       break;
-               }
-       }
-       if (!wait)
-               goto all_in;
-       for_each_online_cpu(c) {
-               if (c == monarch)
-                       continue;
-               if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) {
-                       udelay(5*1000000);      /* wait 5 seconds for slaves (arbitrary) */
-                       if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE)
-                               missing = 1;
-                       break;
+       int c, i , wait;
+
+       /*
+        * wait 5 seconds total for slaves (arbitrary)
+        */
+       for (i = 0; i < 5000; i++) {
+               wait = 0;
+               for_each_online_cpu(c) {
+                       if (c == monarch)
+                               continue;
+                       if (ia64_mc_info.imi_rendez_checkin[c]
+                                       == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) {
+                               udelay(1000);           /* short wait */
+                               wait = 1;
+                               break;
+                       }
                }
+               if (!wait)
+                       goto all_in;
        }
-       if (!missing)
-               goto all_in;
+
        /*
         * Maybe slave(s) dead. Print buffered messages immediately.
         */
@@ -1224,26 +1222,27 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
        if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, (long)&nd, 0, 0)
                        == NOTIFY_STOP)
                ia64_mca_spin(__FUNCTION__);
+
+       ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
        if (sos->monarch) {
                ia64_wait_for_slaves(cpu, "MCA");
+
+               /* Wakeup all the processors which are spinning in the
+                * rendezvous loop.  They will leave SAL, then spin in the OS
+                * with interrupts disabled until this monarch cpu leaves the
+                * MCA handler.  That gets control back to the OS so we can
+                * backtrace the other cpus, backtrace when spinning in SAL
+                * does not work.
+                */
+               ia64_mca_wakeup_all();
+               if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, (long)&nd, 0, 0)
+                               == NOTIFY_STOP)
+                       ia64_mca_spin(__FUNCTION__);
        } else {
-               ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
                while (cpu_isset(cpu, mca_cpu))
                        cpu_relax();    /* spin until monarch wakes us */
-               ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
         }
 
-       /* Wakeup all the processors which are spinning in the rendezvous loop.
-        * They will leave SAL, then spin in the OS with interrupts disabled
-        * until this monarch cpu leaves the MCA handler.  That gets control
-        * back to the OS so we can backtrace the other cpus, backtrace when
-        * spinning in SAL does not work.
-        */
-       ia64_mca_wakeup_all();
-       if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, (long)&nd, 0, 0)
-                       == NOTIFY_STOP)
-               ia64_mca_spin(__FUNCTION__);
-
        /* Get the MCA error record and log it */
        ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
 
@@ -1277,21 +1276,22 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
                /* wake up the next monarch cpu,
                 * and put this cpu in the rendez loop.
                 */
-               ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
                for_each_online_cpu(i) {
                        if (cpu_isset(i, mca_cpu)) {
                                monarch_cpu = i;
                                cpu_clear(i, mca_cpu);  /* wake next cpu */
                                while (monarch_cpu != -1)
                                        cpu_relax();    /* spin until last cpu leaves */
-                               ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
                                set_curr_task(cpu, previous_current);
+                               ia64_mc_info.imi_rendez_checkin[cpu]
+                                               = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
                                return;
                        }
                }
        }
        set_curr_task(cpu, previous_current);
-       monarch_cpu = -1;
+       ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+       monarch_cpu = -1;       /* This frees the slaves and previous monarchs */
 }
 
 static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd);
index c85e943ba5fd93017a305b34aef00da0b56689f9..485e34d0b199333c3ff763f1c22c919628b09575 100644 (file)
@@ -118,7 +118,5 @@ struct mca_table_entry {
 
 extern const struct mca_table_entry *search_mca_tables (unsigned long addr);
 extern int mca_recover_range(unsigned long);
-extern void ia64_mca_printk(const char * fmt, ...)
-        __attribute__ ((format (printf, 1, 2)));
 extern void ia64_mlogbuf_dump(void);
 
index 85829e27785c74912a04a153b163674f38549de0..6ef6ffb943a0cd368c1d11c9dc79888bc4f7674c 100644 (file)
@@ -907,7 +907,7 @@ palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, voi
        return len;
 }
 
-static void
+static void __cpuinit
 create_palinfo_proc_entries(unsigned int cpu)
 {
 #      define CPUSTR   "cpu%d"
@@ -968,7 +968,7 @@ remove_palinfo_proc_entries(unsigned int hcpu)
        }
 }
 
-static int palinfo_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int hotcpu = (unsigned long)hcpu;
@@ -986,7 +986,7 @@ static int palinfo_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block palinfo_cpu_notifier =
+static struct notifier_block palinfo_cpu_notifier __cpuinitdata =
 {
        .notifier_call = palinfo_cpu_callback,
        .priority = 0,
index 14b8e5a6222bca9f0ab18f15e3b78c28a4c7e104..f55fa07849c4c4383182d8b2acd6abfa62067d41 100644 (file)
@@ -1538,13 +1538,6 @@ init_pfm_fs(void)
        return err;
 }
 
-static void __exit
-exit_pfm_fs(void)
-{
-       unregister_filesystem(&pfm_fs_type);
-       mntput(pfmfs_mnt);
-}
-
 static ssize_t
 pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
 {
index 25cd75f50ab10606c5337d91ec0fe6525fc95b2c..779c3cca206c524ea1ad0caf0d17b9a202db4f64 100644 (file)
@@ -574,7 +574,7 @@ static const struct file_operations salinfo_data_fops = {
        .write   = salinfo_log_write,
 };
 
-static int __devinit
+static int __cpuinit
 salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 {
        unsigned int i, cpu = (unsigned long)hcpu;
@@ -615,7 +615,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
        return NOTIFY_OK;
 }
 
-static struct notifier_block salinfo_cpu_notifier =
+static struct notifier_block salinfo_cpu_notifier __cpuinitdata =
 {
        .notifier_call = salinfo_cpu_callback,
        .priority = 0,
index 94ae3c87d828c5d251d78eceff617d4dc08494e0..14261fee5f4dbdb1ef88beb9b02c2dbf41906151 100644 (file)
@@ -118,11 +118,11 @@ struct cpu_cache_info {
        struct kobject kobj;
 };
 
-static struct cpu_cache_info   all_cpu_cache_info[NR_CPUS];
+static struct cpu_cache_info   all_cpu_cache_info[NR_CPUS] __cpuinitdata;
 #define LEAF_KOBJECT_PTR(x,y)    (&all_cpu_cache_info[x].cache_leaves[y])
 
 #ifdef CONFIG_SMP
-static void cache_shared_cpu_map_setup( unsigned int cpu,
+static void __cpuinit cache_shared_cpu_map_setup( unsigned int cpu,
                struct cache_info * this_leaf)
 {
        pal_cache_shared_info_t csi;
@@ -157,7 +157,7 @@ static void cache_shared_cpu_map_setup( unsigned int cpu,
                                &csi) == PAL_STATUS_SUCCESS);
 }
 #else
-static void cache_shared_cpu_map_setup(unsigned int cpu,
+static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu,
                struct cache_info * this_leaf)
 {
        cpu_set(cpu, this_leaf->shared_cpu_map);
@@ -428,13 +428,13 @@ static struct notifier_block __cpuinitdata cache_cpu_notifier =
        .notifier_call = cache_cpu_callback
 };
 
-static int __cpuinit cache_sysfs_init(void)
+static int __init cache_sysfs_init(void)
 {
        int i;
 
        for_each_online_cpu(i) {
-               cache_cpu_callback(&cache_cpu_notifier, CPU_ONLINE,
-                               (void *)(long)i);
+               struct sys_device *sys_dev = get_cpu_sysdev((unsigned int)i);
+               cache_add_dev(sys_dev);
        }
 
        register_hotcpu_notifier(&cache_cpu_notifier);
index 2b5f64726a2e88ff851c4c02119f5729e7947d80..880add120eb3208715cb51a82bbd286ccbed877b 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/atari/atakeyb.c
- *
  * Atari Keyboard driver for 680x0 Linux
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -11,6 +9,9 @@
 /*
  * Atari support by Robert de Vries
  * enhanced by Bjoern Brauel and Roman Hodek
+ *
+ * 2.6 and input cleanup (removed autorepeat stuff) for 2.6.21
+ * 06/07 Michael Schmitz
  */
 
 #include <linux/module.h>
@@ -32,7 +33,6 @@
 #include <asm/atari_joystick.h>
 #include <asm/irq.h>
 
-static void atakeyb_rep(unsigned long ignore);
 extern unsigned int keymap_count;
 
 /* Hook for MIDI serial driver */
@@ -104,25 +104,6 @@ static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
  *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
  */
 
-static u_short ataplain_map[NR_KEYS] __initdata = {
-       0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
-       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
-       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-       0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
-       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
-       0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
-       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
-       0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
-       0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-       0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-       0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-       0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
 typedef enum kb_state_t {
        KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
 } KB_STATE_T;
@@ -137,41 +118,6 @@ typedef struct keyboard_state {
 
 KEYBOARD_STATE kb_state;
 
-#define        DEFAULT_KEYB_REP_DELAY  (HZ/4)
-#define        DEFAULT_KEYB_REP_RATE   (HZ/25)
-
-/* These could be settable by some ioctl() in future... */
-static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
-static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
-
-static unsigned char rep_scancode;
-static struct timer_list atakeyb_rep_timer = {
-       .function = atakeyb_rep,
-};
-
-static void atakeyb_rep(unsigned long ignore)
-{
-       /* Disable keyboard for the time we call handle_scancode(), else a race
-        * in the keyboard tty queue may happen */
-       atari_disable_irq(IRQ_MFP_ACIA);
-       del_timer(&atakeyb_rep_timer);
-
-       /* A keyboard int may have come in before we disabled the irq, so
-        * double-check whether rep_scancode is still != 0 */
-       if (rep_scancode) {
-               init_timer(&atakeyb_rep_timer);
-               atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
-               add_timer(&atakeyb_rep_timer);
-
-               //handle_scancode(rep_scancode, 1);
-               if (atari_input_keyboard_interrupt_hook)
-                       atari_input_keyboard_interrupt_hook(rep_scancode, 1);
-       }
-
-       atari_enable_irq(IRQ_MFP_ACIA);
-}
-
-
 /* ++roman: If a keyboard overrun happened, we can't tell in general how much
  * bytes have been lost and in which state of the packet structure we are now.
  * This usually causes keyboards bytes to be interpreted as mouse movements
@@ -209,9 +155,6 @@ repeat:
                /* ...happens often if interrupts were disabled for too long */
                printk(KERN_DEBUG "Keyboard overrun\n");
                scancode = acia.key_data;
-               /* Turn off autorepeating in case a break code has been lost */
-               del_timer(&atakeyb_rep_timer);
-               rep_scancode = 0;
                if (ikbd_self_test)
                        /* During self test, don't do resyncing, just process the code */
                        goto interpret_scancode;
@@ -281,11 +224,12 @@ repeat:
                                         * make codes instead. Therefore, simply ignore
                                         * break_flag...
                                         */
-                                       int keyval = plain_map[scancode], keytyp;
+                                       int keyval, keytyp;
 
                                        set_bit(scancode, broken_keys);
                                        self_test_last_rcv = jiffies;
-                                       keyval = plain_map[scancode];
+                                       /* new Linux scancodes; approx. */
+                                       keyval = scancode;
                                        keytyp = KTYP(keyval) - 0xf0;
                                        keyval = KVAL(keyval);
 
@@ -301,19 +245,6 @@ repeat:
                                } else if (test_bit(scancode, broken_keys))
                                        break;
 
-#if 0  // FIXME; hangs at boot
-                               if (break_flag) {
-                                       del_timer(&atakeyb_rep_timer);
-                                       rep_scancode = 0;
-                               } else {
-                                       del_timer(&atakeyb_rep_timer);
-                                       rep_scancode = scancode;
-                                       atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
-                                       add_timer(&atakeyb_rep_timer);
-                               }
-#endif
-
-                               // handle_scancode(scancode, !break_flag);
                                if (atari_input_keyboard_interrupt_hook)
                                        atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
                                break;
@@ -639,9 +570,6 @@ int __init atari_keyb_init(void)
        if (atari_keyb_done)
                return 0;
 
-       /* setup key map */
-       memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
-
        kb_state.state = KEYBOARD;
        kb_state.len = 0;
 
@@ -704,26 +632,6 @@ int __init atari_keyb_init(void)
        return 0;
 }
 
-int atari_kbdrate(struct kbd_repeat *k)
-{
-       if (k->delay > 0) {
-               /* convert from msec to jiffies */
-               key_repeat_delay = (k->delay * HZ + 500) / 1000;
-               if (key_repeat_delay < 1)
-                       key_repeat_delay = 1;
-       }
-       if (k->period > 0) {
-               key_repeat_rate = (k->period * HZ + 500) / 1000;
-               if (key_repeat_rate < 1)
-                       key_repeat_rate = 1;
-       }
-
-       k->delay  = key_repeat_delay * 1000 / HZ;
-       k->period = key_repeat_rate  * 1000 / HZ;
-
-       return 0;
-}
-
 int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
 {
 #ifdef CONFIG_MAGIC_SYSRQ
index a8637cdb5b4b076a580e98ead98599e25bfa1650..90d70695aa60fc0c7c0f30e7fc0eb46def5483ca 100644 (file)
@@ -33,7 +33,6 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 
 #include <asm/bootinfo.h>
 
-/* #define DEBUG_CMDLINE */
-
-extern int prom_argc;
-extern char **prom_argv, **prom_envp;
-
+int prom_argc;
+char **prom_argv;
+char **prom_envp;
 
 char * __init_or_module prom_getcmdline(void)
 {
        return &(arcs_cmdline[0]);
 }
 
-void  prom_init_cmdline(void)
+void prom_init_cmdline(void)
 {
        char *cp;
        int actr;
@@ -61,7 +58,7 @@ void  prom_init_cmdline(void)
 
        cp = &(arcs_cmdline[0]);
        while(actr < prom_argc) {
-               strcpy(cp, prom_argv[actr]);
+               strcpy(cp, prom_argv[actr]);
                cp += strlen(prom_argv[actr]);
                *cp++ = ' ';
                actr++;
@@ -70,10 +67,8 @@ void  prom_init_cmdline(void)
                --cp;
        if (prom_argc > 1)
                *cp = '\0';
-
 }
 
-
 char *prom_getenv(char *envname)
 {
        /*
@@ -95,21 +90,23 @@ char *prom_getenv(char *envname)
                }
                env++;
        }
+
        return NULL;
 }
 
-inline unsigned char str2hexnum(unsigned char c)
+static inline unsigned char str2hexnum(unsigned char c)
 {
-       if(c >= '0' && c <= '9')
+       if (c >= '0' && c <= '9')
                return c - '0';
-       if(c >= 'a' && c <= 'f')
+       if (c >= 'a' && c <= 'f')
                return c - 'a' + 10;
-       if(c >= 'A' && c <= 'F')
+       if (c >= 'A' && c <= 'F')
                return c - 'A' + 10;
+
        return 0; /* foo */
 }
 
-inline void str2eaddr(unsigned char *ea, unsigned char *str)
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
 {
        int i;
 
@@ -124,35 +121,29 @@ inline void str2eaddr(unsigned char *ea, unsigned char *str)
        }
 }
 
-int get_ethernet_addr(char *ethernet_addr)
+int prom_get_ethernet_addr(char *ethernet_addr)
 {
-        char *ethaddr_str;
+       char *ethaddr_str;
+       char *argptr;
 
-        ethaddr_str = prom_getenv("ethaddr");
+       /* Check the environment variables first */
+       ethaddr_str = prom_getenv("ethaddr");
        if (!ethaddr_str) {
-               printk("ethaddr not set in boot prom\n");
-               return -1;
-       }
-       str2eaddr(ethernet_addr, ethaddr_str);
-
-#if 0
-       {
-               int i;
+               /* Check command line */
+               argptr = prom_getcmdline();
+               ethaddr_str = strstr(argptr, "ethaddr=");
+               if (!ethaddr_str)
+                       return -1;
 
-       printk("get_ethernet_addr: ");
-       for (i=0; i<5; i++)
-               printk("%02x:", (unsigned char)*(ethernet_addr+i));
-       printk("%02x\n", *(ethernet_addr+i));
+               ethaddr_str += strlen("ethaddr=");
        }
-#endif
+
+       str2eaddr(ethernet_addr, ethaddr_str);
 
        return 0;
 }
+EXPORT_SYMBOL(prom_get_ethernet_addr);
 
 void __init prom_free_prom_memory(void)
 {
 }
-
-EXPORT_SYMBOL(prom_getcmdline);
-EXPORT_SYMBOL(get_ethernet_addr);
-EXPORT_SYMBOL(str2eaddr);
index b212c072612537d260ed396f7371e7930c67accc..a90d425d4651a66c0e805d47511ecb86d0b866db 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
 #include <asm/pgtable.h>
-#include <asm/mach-au1x00/au1000.h>
 #include <asm/time.h>
 
-extern char * prom_getcmdline(void);
+#include <au1000.h>
+#include <prom.h>
+
 extern void __init board_setup(void);
 extern void au1000_restart(char *);
 extern void au1000_halt(void);
index 4d7bcfc8cf7391bb334ca1cda69e203b310885bf..43298fd9459ca20da50124cb9e0920e8132b0818 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index 2aa7b2ed6a8c5559e8447e36daf2b3bf0bb0eb74..cdeae3212a2d5e48dabfc7f17d7dfe3a1f26a84c 100644 (file)
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/bootmem.h>
+
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index 4535f7208e18eab1a6c04e49b4ad1ddc830652e8..ddccaf6997d0924a8ef0b2098c3af621b70c8c97 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index 7ba6852de7cd57a51e782940332f55576233f134..c93fd39b4abae21e44cbf5e3835e622dbea99d6a 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index 2122515f79d7844824cecc8c12780e9fdcea9572..5dbc9868f598594031354abc4a690b54c8e01e88 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
 #include <asm/pgtable.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#include <au1000.h>
+#include <au1xxx_dbdma.h>
+#include <prom.h>
 
 #ifdef CONFIG_MIPS_PB1200
 #include <asm/mach-pb1x00/pb1200.h>
index 5a70029d53886c2a3c52c17cbdb65666c0105199..c251570749ee3cf668ff27123c3f172147087bc3 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index e58a9d6c502100086162ac8288afe0c1273dba85..507d4b20416175cccf728c38d8af225be162a27b 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index fad53bf5aad1b2e622c43305e03361e0fd379de0..b03eee601e360525b9afd65096d4d1228025bb62 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index 9f839c36f69eb99aa62feb3dc8e1bdee9a97b1e8..6532939f377aac0ac0a096a6352b5ddf59938d31 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
-extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
index 432f2e376aea10cb3560ada1d1b80cc05086c636..63989e9df4f97099b73889d3610b6111d2447b0c 100644 (file)
@@ -379,7 +379,7 @@ void flush_tlb_mm(struct mm_struct *mm)
                unsigned int cpu;
 
                cpu_clear(smp_processor_id(), mask);
-               for_each_online_cpu(cpu)
+               for_each_cpu_mask(cpu, mask)
                        if (cpu_context(cpu, mm))
                                cpu_context(cpu, mm) = 0;
        }
@@ -419,7 +419,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l
                unsigned int cpu;
 
                cpu_clear(smp_processor_id(), mask);
-               for_each_online_cpu(cpu)
+               for_each_cpu_mask(cpu, mask)
                        if (cpu_context(cpu, mm))
                                cpu_context(cpu, mm) = 0;
        }
@@ -466,7 +466,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
                unsigned int cpu;
 
                cpu_clear(smp_processor_id(), mask);
-               for_each_online_cpu(cpu)
+               for_each_cpu_mask(cpu, mask)
                        if (cpu_context(cpu, vma->vm_mm))
                                cpu_context(cpu, vma->vm_mm) = 0;
        }
index 01b0961acfb6f84de9fc2f2b39c3b475f621c576..a61246d3533dd6695ddcbef329cf40ab27800882 100644 (file)
@@ -66,7 +66,7 @@ static inline int __maybe_unused r10000_llsc_war(void)
  * why; it's not an issue caused by the core RTL.
  *
  */
-static int __init m4kc_tlbp_war(void)
+static __init int __attribute__((unused)) m4kc_tlbp_war(void)
 {
        return (current_cpu_data.processor_id & 0xffff00) ==
               (PRID_COMP_MIPS | PRID_IMP_4KC);
@@ -140,7 +140,7 @@ struct insn {
         | (e) << RE_SH                                         \
         | (f) << FUNC_SH)
 
-static struct insn insn_table[] __initdata = {
+static __initdata struct insn insn_table[] = {
        { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
        { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
        { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
@@ -193,7 +193,7 @@ static struct insn insn_table[] __initdata = {
 
 #undef M
 
-static u32 __init build_rs(u32 arg)
+static __init u32 build_rs(u32 arg)
 {
        if (arg & ~RS_MASK)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -201,7 +201,7 @@ static u32 __init build_rs(u32 arg)
        return (arg & RS_MASK) << RS_SH;
 }
 
-static u32 __init build_rt(u32 arg)
+static __init u32 build_rt(u32 arg)
 {
        if (arg & ~RT_MASK)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -209,7 +209,7 @@ static u32 __init build_rt(u32 arg)
        return (arg & RT_MASK) << RT_SH;
 }
 
-static u32 __init build_rd(u32 arg)
+static __init u32 build_rd(u32 arg)
 {
        if (arg & ~RD_MASK)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -217,7 +217,7 @@ static u32 __init build_rd(u32 arg)
        return (arg & RD_MASK) << RD_SH;
 }
 
-static u32 __init build_re(u32 arg)
+static __init u32 build_re(u32 arg)
 {
        if (arg & ~RE_MASK)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -225,7 +225,7 @@ static u32 __init build_re(u32 arg)
        return (arg & RE_MASK) << RE_SH;
 }
 
-static u32 __init build_simm(s32 arg)
+static __init u32 build_simm(s32 arg)
 {
        if (arg > 0x7fff || arg < -0x8000)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -233,7 +233,7 @@ static u32 __init build_simm(s32 arg)
        return arg & 0xffff;
 }
 
-static u32 __init build_uimm(u32 arg)
+static __init u32 build_uimm(u32 arg)
 {
        if (arg & ~IMM_MASK)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -241,7 +241,7 @@ static u32 __init build_uimm(u32 arg)
        return arg & IMM_MASK;
 }
 
-static u32 __init build_bimm(s32 arg)
+static __init u32 build_bimm(s32 arg)
 {
        if (arg > 0x1ffff || arg < -0x20000)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -252,7 +252,7 @@ static u32 __init build_bimm(s32 arg)
        return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
 }
 
-static u32 __init build_jimm(u32 arg)
+static __init u32 build_jimm(u32 arg)
 {
        if (arg & ~((JIMM_MASK) << 2))
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -260,7 +260,7 @@ static u32 __init build_jimm(u32 arg)
        return (arg >> 2) & JIMM_MASK;
 }
 
-static u32 __init build_func(u32 arg)
+static __init u32 build_func(u32 arg)
 {
        if (arg & ~FUNC_MASK)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -268,7 +268,7 @@ static u32 __init build_func(u32 arg)
        return arg & FUNC_MASK;
 }
 
-static u32 __init build_set(u32 arg)
+static __init u32 build_set(u32 arg)
 {
        if (arg & ~SET_MASK)
                printk(KERN_WARNING "TLB synthesizer field overflow\n");
@@ -315,69 +315,69 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...)
 }
 
 #define I_u1u2u3(op)                                           \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                unsigned int b, unsigned int c)                 \
        {                                                       \
                build_insn(buf, insn##op, a, b, c);             \
        }
 
 #define I_u2u1u3(op)                                           \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                unsigned int b, unsigned int c)                 \
        {                                                       \
                build_insn(buf, insn##op, b, a, c);             \
        }
 
 #define I_u3u1u2(op)                                           \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                unsigned int b, unsigned int c)                 \
        {                                                       \
                build_insn(buf, insn##op, b, c, a);             \
        }
 
 #define I_u1u2s3(op)                                           \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                unsigned int b, signed int c)                   \
        {                                                       \
                build_insn(buf, insn##op, a, b, c);             \
        }
 
 #define I_u2s3u1(op)                                           \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                signed int b, unsigned int c)                   \
        {                                                       \
                build_insn(buf, insn##op, c, a, b);             \
        }
 
 #define I_u2u1s3(op)                                           \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                unsigned int b, signed int c)                   \
        {                                                       \
                build_insn(buf, insn##op, b, a, c);             \
        }
 
 #define I_u1u2(op)                                             \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                unsigned int b)                                 \
        {                                                       \
                build_insn(buf, insn##op, a, b);                \
        }
 
 #define I_u1s2(op)                                             \
-       static inline void i##op(u32 **buf, unsigned int a,     \
+       static inline void __init i##op(u32 **buf, unsigned int a,      \
                signed int b)                                   \
        {                                                       \
                build_insn(buf, insn##op, a, b);                \
        }
 
 #define I_u1(op)                                               \
-       static inline void i##op(u32 **buf, unsigned int a)     \
+       static inline void __init i##op(u32 **buf, unsigned int a)      \
        {                                                       \
                build_insn(buf, insn##op, a);                   \
        }
 
 #define I_0(op)                                                        \
-       static inline void i##op(u32 **buf)             \
+       static inline void __init i##op(u32 **buf)              \
        {                                                       \
                build_insn(buf, insn##op);                      \
        }
@@ -457,7 +457,7 @@ struct label {
        enum label_id lab;
 };
 
-static void __init build_label(struct label **lab, u32 *addr,
+static __init void build_label(struct label **lab, u32 *addr,
                               enum label_id l)
 {
        (*lab)->addr = addr;
@@ -526,34 +526,34 @@ L_LA(_r3000_write_probe_fail)
 #define i_ehb(buf) i_sll(buf, 0, 0, 3)
 
 #ifdef CONFIG_64BIT
-static int __init __maybe_unused in_compat_space_p(long addr)
+static __init int __maybe_unused in_compat_space_p(long addr)
 {
        /* Is this address in 32bit compat space? */
        return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
 }
 
-static int __init __maybe_unused rel_highest(long val)
+static __init int __maybe_unused rel_highest(long val)
 {
        return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
 }
 
-static int __init __maybe_unused rel_higher(long val)
+static __init int __maybe_unused rel_higher(long val)
 {
        return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
 }
 #endif
 
-static int __init rel_hi(long val)
+static __init int rel_hi(long val)
 {
        return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
 }
 
-static int __init rel_lo(long val)
+static __init int rel_lo(long val)
 {
        return ((val & 0xffff) ^ 0x8000) - 0x8000;
 }
 
-static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr)
+static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr)
 {
 #ifdef CONFIG_64BIT
        if (!in_compat_space_p(addr)) {
@@ -571,7 +571,7 @@ static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr)
                i_lui(buf, rs, rel_hi(addr));
 }
 
-static void __init __maybe_unused i_LA(u32 **buf, unsigned int rs,
+static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs,
                                             long addr)
 {
        i_LA_mostly(buf, rs, addr);
@@ -589,7 +589,7 @@ struct reloc {
        enum label_id lab;
 };
 
-static void __init r_mips_pc16(struct reloc **rel, u32 *addr,
+static __init void r_mips_pc16(struct reloc **rel, u32 *addr,
                               enum label_id l)
 {
        (*rel)->addr = addr;
@@ -614,7 +614,7 @@ static inline void __resolve_relocs(struct reloc *rel, struct label *lab)
        }
 }
 
-static void __init resolve_relocs(struct reloc *rel, struct label *lab)
+static __init void resolve_relocs(struct reloc *rel, struct label *lab)
 {
        struct label *l;
 
@@ -624,7 +624,7 @@ static void __init resolve_relocs(struct reloc *rel, struct label *lab)
                                __resolve_relocs(rel, l);
 }
 
-static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end,
+static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end,
                               long off)
 {
        for (; rel->lab != label_invalid; rel++)
@@ -632,7 +632,7 @@ static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end,
                        rel->addr += off;
 }
 
-static void __init move_labels(struct label *lab, u32 *first, u32 *end,
+static __init void move_labels(struct label *lab, u32 *first, u32 *end,
                               long off)
 {
        for (; lab->lab != label_invalid; lab++)
@@ -640,7 +640,7 @@ static void __init move_labels(struct label *lab, u32 *first, u32 *end,
                        lab->addr += off;
 }
 
-static void __init copy_handler(struct reloc *rel, struct label *lab,
+static __init void copy_handler(struct reloc *rel, struct label *lab,
                                u32 *first, u32 *end, u32 *target)
 {
        long off = (long)(target - first);
@@ -651,7 +651,7 @@ static void __init copy_handler(struct reloc *rel, struct label *lab,
        move_labels(lab, first, end, off);
 }
 
-static int __init __maybe_unused insn_has_bdelay(struct reloc *rel,
+static __init int __maybe_unused insn_has_bdelay(struct reloc *rel,
                                                       u32 *addr)
 {
        for (; rel->lab != label_invalid; rel++) {
@@ -743,11 +743,11 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
  * We deliberately chose a buffer size of 128, so we won't scribble
  * over anything important on overflow before we panic.
  */
-static u32 tlb_handler[128] __initdata;
+static __initdata u32 tlb_handler[128];
 
 /* simply assume worst case size for labels and relocs */
-static struct label labels[128] __initdata;
-static struct reloc relocs[128] __initdata;
+static __initdata struct label labels[128];
+static __initdata struct reloc relocs[128];
 
 /*
  * The R3000 TLB handler is simple.
@@ -801,7 +801,7 @@ static void __init build_r3000_tlb_refill_handler(void)
  * other one.To keep things simple, we first assume linear space,
  * then we relocate it to the final handler layout as needed.
  */
-static u32 final_handler[64] __initdata;
+static __initdata u32 final_handler[64];
 
 /*
  * Hazards
@@ -825,7 +825,7 @@ static u32 final_handler[64] __initdata;
  *
  * As if we MIPS hackers wouldn't know how to nop pipelines happy ...
  */
-static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
+static __init void __maybe_unused build_tlb_probe_entry(u32 **p)
 {
        switch (current_cpu_type()) {
        /* Found by experiment: R4600 v2.0 needs this, too.  */
@@ -849,7 +849,7 @@ static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
  */
 enum tlb_write_entry { tlb_random, tlb_indexed };
 
-static void __init build_tlb_write_entry(u32 **p, struct label **l,
+static __init void build_tlb_write_entry(u32 **p, struct label **l,
                                         struct reloc **r,
                                         enum tlb_write_entry wmode)
 {
@@ -993,7 +993,7 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
  * TMP and PTR are scratch.
  * TMP will be clobbered, PTR will hold the pmd entry.
  */
-static void __init
+static __init void
 build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
                 unsigned int tmp, unsigned int ptr)
 {
@@ -1054,7 +1054,7 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
  * BVADDR is the faulting address, PTR is scratch.
  * PTR will hold the pgd for vmalloc.
  */
-static void __init
+static __init void
 build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
                        unsigned int bvaddr, unsigned int ptr)
 {
@@ -1118,7 +1118,7 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
  * TMP and PTR are scratch.
  * TMP will be clobbered, PTR will hold the pgd entry.
  */
-static void __init __maybe_unused
+static __init void __maybe_unused
 build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
 {
        long pgdc = (long)pgd_current;
@@ -1153,7 +1153,7 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
 
 #endif /* !CONFIG_64BIT */
 
-static void __init build_adjust_context(u32 **p, unsigned int ctx)
+static __init void build_adjust_context(u32 **p, unsigned int ctx)
 {
        unsigned int shift = 4 - (PTE_T_LOG2 + 1) + PAGE_SHIFT - 12;
        unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1);
@@ -1179,7 +1179,7 @@ static void __init build_adjust_context(u32 **p, unsigned int ctx)
        i_andi(p, ctx, ctx, mask);
 }
 
-static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
+static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
 {
        /*
         * Bug workaround for the Nevada. It seems as if under certain
@@ -1204,7 +1204,7 @@ static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
        i_ADDU(p, ptr, ptr, tmp); /* add in offset */
 }
 
-static void __init build_update_entries(u32 **p, unsigned int tmp,
+static __init void build_update_entries(u32 **p, unsigned int tmp,
                                        unsigned int ptep)
 {
        /*
index 0caa3d955c3b2b6948c620104c21f63fe5589ccc..65b7ae4262381a2b9830dd1ecbb5a487a6a56063 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/of.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
 #include <asm/time.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
@@ -156,18 +158,6 @@ static void __init lite5200_setup_arch(void)
                of_node_put(np);
        }
 #endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-#endif
-#ifdef  CONFIG_ROOT_NFS
-               ROOT_DEV = Root_NFS;
-#else
-               ROOT_DEV = Root_HDA1;
-#endif
-
 }
 
 /*
index 1245b2f517bb669eb0cec7bcbd6d641ba57f1d73..095988f13bf4de8eca56f1c16457751dfb198a72 100644 (file)
@@ -77,12 +77,7 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
 {
        pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
 
-       dcr_write(msic->dcr_host, msic->dcr_host.base + dcr_n, val);
-}
-
-static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
-{
-       return dcr_read(msic->dcr_host, msic->dcr_host.base + dcr_n);
+       dcr_write(msic->dcr_host, dcr_n, val);
 }
 
 static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
@@ -91,7 +86,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
        u32 write_offset, msi;
        int idx;
 
-       write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+       write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
        pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
 
        /* write_offset doesn't wrap properly, so we have to mask it */
@@ -306,7 +301,7 @@ static int axon_msi_notify_reboot(struct notifier_block *nb,
        list_for_each_entry(msic, &axon_msic_list, list) {
                pr_debug("axon_msi: disabling %s\n",
                          msic->irq_host->of_node->full_name);
-               tmp  = msic_dcr_read(msic, MSIC_CTRL_REG);
+               tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
                tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
                msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
        }
index ea0b2c790412483b29438f5b18b8d6693370b2d0..190ff4b59a557bd5be11d34d3e069b0425bb7572 100644 (file)
@@ -440,7 +440,6 @@ static void ps3_system_bus_shutdown(struct device *_dev)
 static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
 {
        struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
-       int i = 0, length = 0;
 
        if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
                return -ENOMEM;
index ab11c0b2902459a7434e0331f6741d7b82765c78..427027c7ea0f61fbeeb7192f2c1125cb64246d22 100644 (file)
@@ -126,13 +126,13 @@ dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
 }
 EXPORT_SYMBOL_GPL(dcr_map);
 
-void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c)
+void dcr_unmap(dcr_host_t host, unsigned int dcr_c)
 {
        dcr_host_t h = host;
 
        if (h.token == NULL)
                return;
-       h.token += dcr_n * h.stride;
+       h.token += host.base * h.stride;
        iounmap(h.token);
        h.token = NULL;
 }
index 893e65439e851584c0e0b46d3248de1e1fa97f00..e47938899a9268c3e926979f7f15e73394810c3d 100644 (file)
@@ -156,7 +156,7 @@ static inline u32 _mpic_read(enum mpic_reg_type type,
        switch(type) {
 #ifdef CONFIG_PPC_DCR
        case mpic_access_dcr:
-               return dcr_read(rb->dhost, rb->dhost.base + reg);
+               return dcr_read(rb->dhost, reg);
 #endif
        case mpic_access_mmio_be:
                return in_be32(rb->base + (reg >> 2));
@@ -173,7 +173,7 @@ static inline void _mpic_write(enum mpic_reg_type type,
        switch(type) {
 #ifdef CONFIG_PPC_DCR
        case mpic_access_dcr:
-               return dcr_write(rb->dhost, rb->dhost.base + reg, value);
+               return dcr_write(rb->dhost, reg, value);
 #endif
        case mpic_access_mmio_be:
                return out_be32(rb->base + (reg >> 2), value);
index f3bceb165321e2bb3d57430a1b5fd8c90e7fbd9e..139ca153d5cc1dece7d4ac3679946d29a9baada9 100644 (file)
@@ -68,9 +68,15 @@ STACK_SIZE  = 1 << STACK_SHIFT
        l       %r1,BASED(.Ltrace_irq_off)
        basr    %r14,%r1
        .endm
+
+       .macro  LOCKDEP_SYS_EXIT
+       l       %r1,BASED(.Llockdep_sys_exit)
+       basr    %r14,%r1
+       .endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
+#define LOCKDEP_SYS_EXIT
 #endif
 
 /*
@@ -260,6 +266,7 @@ sysc_return:
        bno     BASED(sysc_leave)
        tm      __TI_flags+3(%r9),_TIF_WORK_SVC
        bnz     BASED(sysc_work)  # there is work to do (signals etc.)
+       LOCKDEP_SYS_EXIT
 sysc_leave:
        RESTORE_ALL __LC_RETURN_PSW,1
 
@@ -283,6 +290,7 @@ sysc_work:
        bo      BASED(sysc_restart)
        tm      __TI_flags+3(%r9),_TIF_SINGLE_STEP
        bo      BASED(sysc_singlestep)
+       LOCKDEP_SYS_EXIT
        b       BASED(sysc_leave)
 
 #
@@ -572,6 +580,7 @@ io_return:
 #endif
        tm      __TI_flags+3(%r9),_TIF_WORK_INT
        bnz     BASED(io_work)          # there is work to do (signals etc.)
+       LOCKDEP_SYS_EXIT
 io_leave:
        RESTORE_ALL __LC_RETURN_PSW,0
 io_done:
@@ -618,6 +627,7 @@ io_work_loop:
        bo      BASED(io_reschedule)
        tm      __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
        bnz     BASED(io_sigpending)
+       LOCKDEP_SYS_EXIT
        b       BASED(io_leave)
 
 #
@@ -1040,6 +1050,8 @@ cleanup_io_leave_insn:
 .Ltrace_irq_on: .long  trace_hardirqs_on
 .Ltrace_irq_off:
                .long   trace_hardirqs_off
+.Llockdep_sys_exit:
+               .long   lockdep_sys_exit
 #endif
 .Lcritical_start:
                .long   __critical_start + 0x80000000
index 9c0d5cc8269dd321a17da58a8046f2a20a2621ce..05e26d1fdf405dc21696b35aabb0217a6164d8d4 100644 (file)
@@ -66,9 +66,14 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
        .macro  TRACE_IRQS_OFF
         brasl  %r14,trace_hardirqs_off
        .endm
+
+       .macro  LOCKDEP_SYS_EXIT
+        brasl  %r14,lockdep_sys_exit
+       .endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
+#define LOCKDEP_SYS_EXIT
 #endif
 
        .macro  STORE_TIMER lc_offset
@@ -255,6 +260,7 @@ sysc_return:
        jno     sysc_leave
        tm      __TI_flags+7(%r9),_TIF_WORK_SVC
        jnz     sysc_work       # there is work to do (signals etc.)
+       LOCKDEP_SYS_EXIT
 sysc_leave:
        RESTORE_ALL __LC_RETURN_PSW,1
 
@@ -278,6 +284,7 @@ sysc_work:
        jo      sysc_restart
        tm      __TI_flags+7(%r9),_TIF_SINGLE_STEP
        jo      sysc_singlestep
+       LOCKDEP_SYS_EXIT
        j       sysc_leave
 
 #
@@ -558,6 +565,7 @@ io_return:
 #endif
        tm      __TI_flags+7(%r9),_TIF_WORK_INT
        jnz     io_work                 # there is work to do (signals etc.)
+       LOCKDEP_SYS_EXIT
 io_leave:
        RESTORE_ALL __LC_RETURN_PSW,0
 io_done:
@@ -605,6 +613,7 @@ io_work_loop:
        jo      io_reschedule
        tm      __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
        jnz     io_sigpending
+       LOCKDEP_SYS_EXIT
        j       io_leave
 
 #
index 54878f07cf0c0f05615af30a3e99e7fc21e0e1be..44982c1dfa23c7adc28b422d8b2d35fa6b6c92b4 100644 (file)
@@ -118,7 +118,7 @@ endchoice
 
 config SH_FPU
        bool "FPU support"
-       depends on CPU_SH4
+       depends on CPU_HAS_FPU
        default y
        help
          Selecting this option will enable support for SH processors that
@@ -178,12 +178,6 @@ config CPU_HAS_INTEVT
 config CPU_HAS_MASKREG_IRQ
        bool
 
-config CPU_HAS_INTC_IRQ
-       bool
-
-config CPU_HAS_INTC2_IRQ
-       bool
-
 config CPU_HAS_IPR_IRQ
        bool
 
@@ -205,6 +199,9 @@ config CPU_HAS_PTEA
 config CPU_HAS_DSP
        bool
 
+config CPU_HAS_FPU
+       bool
+
 endmenu
 
 menu "Board support"
@@ -258,7 +255,6 @@ config SH_7780_SOLUTION_ENGINE
        bool "SolutionEngine7780"
        select SOLUTION_ENGINE
        select SYS_SUPPORTS_PCI
-       select CPU_HAS_INTC2_IRQ
        depends on CPU_SUBTYPE_SH7780
        help
          Select 7780 SolutionEngine if configuring for a Renesas SH7780
@@ -309,7 +305,7 @@ config SH_MPC1211
 
 config SH_SH03
        bool "Interface CTP/PCI-SH03"
-       depends on CPU_SUBTYPE_SH7751 && BROKEN
+       depends on CPU_SUBTYPE_SH7751
        select CPU_HAS_IPR_IRQ
        select SYS_SUPPORTS_PCI
        help
@@ -395,11 +391,22 @@ config SH_LBOX_RE2
        help
          Select L-BOX RE2 if configuring for the NTT COMWARE L-BOX RE2.
 
+config SH_X3PROTO
+       bool "SH-X3 Prototype board"
+       depends on CPU_SUBTYPE_SHX3
+
+config SH_MAGIC_PANEL_R2
+       bool "Magic Panel R2"
+       depends on CPU_SUBTYPE_SH7720
+       help
+         Select Magic Panel R2 if configuring for Magic Panel R2.
+
 endmenu
 
 source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
 source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
 source "arch/sh/boards/renesas/r7780rp/Kconfig"
+source "arch/sh/boards/magicpanelr2/Kconfig"
 
 menu "Timer and clock configuration"
 
@@ -563,10 +570,19 @@ config NR_CPUS
 
 source "kernel/Kconfig.preempt"
 
-config NODES_SHIFT
-       int
-       default "1"
-       depends on NEED_MULTIPLE_NODES
+config GUSA
+       def_bool y
+       depends on !SMP
+       help
+         This enables support for gUSA (general UserSpace Atomicity).
+         This is the default implementation for both UP and non-ll/sc
+         CPUs, and is used by the libc, amongst others.
+
+         For additional information, design information can be found 
+         in <http://lc.linux.or.jp/lc2002/papers/niibe0919p.pdf>.
+
+         This should only be disabled for special cases where alternate
+         atomicity implementations exist.
 
 endmenu
 
@@ -659,6 +675,17 @@ config SUPERHYWAY
        tristate "SuperHyway Bus support"
        depends on CPU_SUBTYPE_SH4_202
 
+config MAPLE
+       bool "Maple Bus support"
+       depends on SH_DREAMCAST
+       help
+         The Maple Bus is SEGA's serial communication bus for peripherals
+         on the Dreamcast. Without this bus support you won't be able to
+         get your Dreamcast keyboard etc to work, so most users
+         probably want to say 'Y' here, unless you are only using the
+         Dreamcast with a serial line terminal or a remote network
+         connection.
+
 config CF_ENABLER
        bool "Compact Flash Enabler support"
        depends on SOLUTION_ENGINE || SH_SH03
index 52f6a99c8ecc6064ebbe6b50dfd2d262d2d15cd5..b507b501f0cf2f4b24190945eb2742f8babdb261 100644 (file)
@@ -28,13 +28,17 @@ config EARLY_SCIF_CONSOLE
          serial I/O.
 
 config EARLY_SCIF_CONSOLE_PORT
-       hex "SCIF port for early console"
+       hex
        depends on EARLY_SCIF_CONSOLE
        default "0xffe00000" if CPU_SUBTYPE_SH7780
+       default "0xffea0000" if CPU_SUBTYPE_SH7785
        default "0xfffe9800" if CPU_SUBTYPE_SH7206
        default "0xf8420000" if CPU_SUBTYPE_SH7619
        default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705
+       default "0xa4430000" if CPU_SUBTYPE_SH7720
+       default "0xffc30000" if CPU_SUBTYPE_SHX3
        default "0xffe80000" if CPU_SH4
+       default "0x00000000"
 
 config EARLY_PRINTK
        bool "Early printk support"
index 97ac58682d0fc10726b292093a92e1d5c99e3450..a0a2083aad3e58e9c43312f13ee039d41b7fb971 100644 (file)
@@ -118,6 +118,7 @@ machdir-$(CONFIG_SH_7751_SYSTEMH)           += renesas/systemh
 machdir-$(CONFIG_SH_EDOSK7705)                 += renesas/edosk7705
 machdir-$(CONFIG_SH_HIGHLANDER)                        += renesas/r7780rp
 machdir-$(CONFIG_SH_7710VOIPGW)                        += renesas/sh7710voipgw
+machdir-$(CONFIG_SH_X3PROTO)                   += renesas/x3proto
 machdir-$(CONFIG_SH_SH4202_MICRODEV)           += superh/microdev
 machdir-$(CONFIG_SH_LANDISK)                   += landisk
 machdir-$(CONFIG_SH_TITAN)                     += titan
@@ -125,6 +126,7 @@ machdir-$(CONFIG_SH_SHMIN)                  += shmin
 machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE)      += se/7206
 machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE)      += se/7619
 machdir-$(CONFIG_SH_LBOX_RE2)                  += lboxre2
+machdir-$(CONFIG_SH_MAGIC_PANEL_R2)            += magicpanelr2
 
 incdir-y       := $(notdir $(machdir-y))
 
@@ -135,7 +137,7 @@ endif
 
 # Companion chips
 core-$(CONFIG_HD6446X_SERIES)  += arch/sh/cchips/hd6446x/
-core-$(CONFIG_VOYAGERGX)       += arch/sh/cchips/voyagergx/
+core-$(CONFIG_MFD_SM501)       += arch/sh/cchips/voyagergx/
 
 cpuincdir-$(CONFIG_CPU_SH2)    := cpu-sh2
 cpuincdir-$(CONFIG_CPU_SH2A)   := cpu-sh2a
index d1c1460c8a06ecf7905fe303f62ce9af03eb6f1f..640ca2a74f163c07ef42ac570e11cb254da76e0f 100644 (file)
@@ -20,9 +20,9 @@
 #define APM_CRITICAL                   10
 #define APM_LOW                                30
 
-#define HP680_BATTERY_MAX              875
-#define HP680_BATTERY_MIN              600
-#define HP680_BATTERY_AC_ON            900
+#define HP680_BATTERY_MAX              898
+#define HP680_BATTERY_MIN              486
+#define HP680_BATTERY_AC_ON            1023
 
 #define MODNAME "hp6x0_apm"
 
@@ -65,7 +65,7 @@ static void hp6x0_apm_get_power_status(struct apm_power_info *info)
 
 static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev)
 {
-       if (!apm_suspended)
+       if (!APM_DISABLED)
                apm_queue_event(APM_USER_SUSPEND);
 
        return IRQ_HANDLED;
@@ -91,7 +91,6 @@ static int __init hp6x0_apm_init(void)
 static void __exit hp6x0_apm_exit(void)
 {
        free_irq(HP680_BTN_IRQ, 0);
-       apm_get_info = NULL;
 }
 
 module_init(hp6x0_apm_init);
index 7ae708930bacfa4e7f6ff607b8197248e1c7c96a..2f414ac3c69090161717c85e55435e8110995f36 100644 (file)
@@ -7,7 +7,7 @@
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
- * Setup code for an HP680  (internal peripherials only)
+ * Setup code for HP620/HP660/HP680/HP690 (internal peripherials only)
  */
 #include <linux/types.h>
 #include <linux/init.h>
@@ -19,7 +19,7 @@
 #include <asm/cpu/dac.h>
 
 #define        SCPCR   0xa4000116
-#define SCPDR  0xa4000136
+#define        SCPDR   0xa4000136
 
 /* CF Slot */
 static struct resource cf_ide_resources[] = {
@@ -34,7 +34,7 @@ static struct resource cf_ide_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        [2] = {
-               .start = 93,
+               .start = 77,
                .flags = IORESOURCE_IRQ,
        },
 };
@@ -46,10 +46,22 @@ static struct platform_device cf_ide_device = {
        .resource       = cf_ide_resources,
 };
 
+static struct platform_device jornadakbd_device = {
+       .name           = "jornada680_kbd",
+       .id             = -1,
+};
+
 static struct platform_device *hp6xx_devices[] __initdata = {
-       &cf_ide_device,
+       &cf_ide_device,
+       &jornadakbd_device,
 };
 
+static void __init hp6xx_init_irq(void)
+{
+       /* Gets touchscreen and powerbutton IRQ working */
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
 static int __init hp6xx_devices_setup(void)
 {
        return platform_add_devices(hp6xx_devices, ARRAY_SIZE(hp6xx_devices));
@@ -61,11 +73,11 @@ static void __init hp6xx_setup(char **cmdline_p)
        u16 v;
 
        v = inw(HD64461_STBCR);
-       v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
-           HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
-           HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST |
-           HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST |
-           HD64461_STBCR_SAFECKE_IST;
+       v |=    HD64461_STBCR_SURTST | HD64461_STBCR_SIRST      |
+               HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST     |
+               HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST     |
+               HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST|
+               HD64461_STBCR_SAFECKE_IST;
 #ifndef CONFIG_HD64461_ENABLER
        v |= HD64461_STBCR_SPC1ST;
 #endif
@@ -101,6 +113,9 @@ device_initcall(hp6xx_devices_setup);
 static struct sh_machine_vector mv_hp6xx __initmv = {
        .mv_name = "hp6xx",
        .mv_setup = hp6xx_setup,
-       .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
+       /* IRQ's : CPU(64) + CCHIP(16) + FREE_TO_USE(6) */
+       .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM + 6,
        .mv_irq_demux = hd64461_irq_demux,
+       /* Enable IRQ0 -> IRQ3 in IRQ_MODE */
+       .mv_init_irq = hp6xx_init_irq,
 };
diff --git a/arch/sh/boards/magicpanelr2/Kconfig b/arch/sh/boards/magicpanelr2/Kconfig
new file mode 100644 (file)
index 0000000..b0abddc
--- /dev/null
@@ -0,0 +1,13 @@
+if SH_MAGIC_PANEL_R2
+
+menu "Magic Panel R2 options"
+
+config SH_MAGIC_PANEL_R2_VERSION
+       int SH_MAGIC_PANEL_R2_VERSION
+       default "3"
+       help
+         Set the version of the Magic Panel R2
+
+endmenu
+
+endif
diff --git a/arch/sh/boards/magicpanelr2/Makefile b/arch/sh/boards/magicpanelr2/Makefile
new file mode 100644 (file)
index 0000000..7a6d586
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the Magic Panel specific parts
+#
+
+obj-y   := setup.o
\ No newline at end of file
diff --git a/arch/sh/boards/magicpanelr2/setup.c b/arch/sh/boards/magicpanelr2/setup.c
new file mode 100644 (file)
index 0000000..f3b8b07
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * linux/arch/sh/boards/magicpanel/setup.c
+ *
+ *  Copyright (C) 2007  Markus Brunner, Mark Jonas
+ *
+ *  Magic Panel Release 2 board setup
+ *
+ * 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 more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/map.h>
+#include <asm/magicpanelr2.h>
+#include <asm/heartbeat.h>
+
+#define LAN9115_READY  (ctrl_inl(0xA8000084UL) & 0x00000001UL)
+
+/* Prefer cmdline over RedBoot */
+static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
+
+/* Wait until reset finished. Timeout is 100ms. */
+static int __init ethernet_reset_finished(void)
+{
+       int i;
+
+       if (LAN9115_READY)
+               return 1;
+
+       for (i = 0; i < 10; ++i) {
+               mdelay(10);
+               if (LAN9115_READY)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static void __init reset_ethernet(void)
+{
+       /* PMDR: LAN_RESET=on */
+       CLRBITS_OUTB(0x10, PORT_PMDR);
+
+       udelay(200);
+
+       /* PMDR: LAN_RESET=off */
+       SETBITS_OUTB(0x10, PORT_PMDR);
+}
+
+static void __init setup_chip_select(void)
+{
+       /* CS2: LAN (0x08000000 - 0x0bffffff) */
+       /* no idle cycles, normal space, 8 bit data bus */
+       ctrl_outl(0x36db0400, CS2BCR);
+       /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+       ctrl_outl(0x000003c0, CS2WCR);
+
+       /* CS4: CAN1 (0xb0000000 - 0xb3ffffff) */
+       /* no idle cycles, normal space, 8 bit data bus */
+       ctrl_outl(0x00000200, CS4BCR);
+       /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+       ctrl_outl(0x00100981, CS4WCR);
+
+       /* CS5a: CAN2 (0xb4000000 - 0xb5ffffff) */
+       /* no idle cycles, normal space, 8 bit data bus */
+       ctrl_outl(0x00000200, CS5ABCR);
+       /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+       ctrl_outl(0x00100981, CS5AWCR);
+
+       /* CS5b: CAN3 (0xb6000000 - 0xb7ffffff) */
+       /* no idle cycles, normal space, 8 bit data bus */
+       ctrl_outl(0x00000200, CS5BBCR);
+       /* (SW:1.5 WR:3 HW:1.5), ext. wait */
+       ctrl_outl(0x00100981, CS5BWCR);
+
+       /* CS6a: Rotary (0xb8000000 - 0xb9ffffff) */
+       /* no idle cycles, normal space, 8 bit data bus */
+       ctrl_outl(0x00000200, CS6ABCR);
+       /* (SW:1.5 WR:3 HW:1.5), no ext. wait */
+       ctrl_outl(0x001009C1, CS6AWCR);
+}
+
+static void __init setup_port_multiplexing(void)
+{
+       /* A7 GPO(LED8);     A6 GPO(LED7);     A5 GPO(LED6);      A4 GPO(LED5);
+        * A3 GPO(LED4);     A2 GPO(LED3);     A1 GPO(LED2);      A0 GPO(LED1);
+        */
+       ctrl_outw(0x5555, PORT_PACR);   /* 01 01 01 01 01 01 01 01 */
+
+       /* B7 GPO(RST4);   B6 GPO(RST3);  B5 GPO(RST2);    B4 GPO(RST1);
+        * B3 GPO(PB3);    B2 GPO(PB2);   B1 GPO(PB1);     B0 GPO(PB0);
+        */
+       ctrl_outw(0x5555, PORT_PBCR);   /* 01 01 01 01 01 01 01 01 */
+
+       /* C7 GPO(PC7);   C6 GPO(PC6);    C5 GPO(PC5);     C4 GPO(PC4);
+        * C3 LCD_DATA3;  C2 LCD_DATA2;   C1 LCD_DATA1;    C0 LCD_DATA0;
+        */
+       ctrl_outw(0x5500, PORT_PCCR);   /* 01 01 01 01 00 00 00 00 */
+
+       /* D7 GPO(PD7); D6 GPO(PD6);    D5 GPO(PD5);       D4 GPO(PD4);
+        * D3 GPO(PD3); D2 GPO(PD2);    D1 GPO(PD1);       D0 GPO(PD0);
+        */
+       ctrl_outw(0x5555, PORT_PDCR);   /* 01 01 01 01 01 01 01 01 */
+
+       /* E7 (x);        E6 GPI(nu);    E5 GPI(nu);      E4 LCD_M_DISP;
+        * E3 LCD_CL1;    E2 LCD_CL2;    E1 LCD_DON;      E0 LCD_FLM;
+        */
+       ctrl_outw(0x3C00, PORT_PECR);   /* 00 11 11 00 00 00 00 00 */
+
+       /* F7 (x);           F6 DA1(VLCD);     F5 DA0(nc);        F4 AN3;
+        * F3 AN2(MID_AD);   F2 AN1(EARTH_AD); F1 AN0(TEMP);      F0 GPI+(nc);
+        */
+       ctrl_outw(0x0002, PORT_PFCR);   /* 00 00 00 00 00 00 00 10 */
+
+       /* G7 (x);        G6 IRQ5(TOUCH_BUSY); G5 IRQ4(TOUCH_IRQ); G4 GPI(KEY2);
+        * G3 GPI(KEY1);  G2 GPO(LED11);        G1 GPO(LED10);     G0 GPO(LED9);
+        */
+       ctrl_outw(0x03D5, PORT_PGCR);   /* 00 00 00 11 11 01 01 01 */
+
+       /* H7 (x);            H6 /RAS(BRAS);      H5 /CAS(BCAS); H4 CKE(BCKE);
+        * H3 GPO(EARTH_OFF); H2 GPO(EARTH_TEST); H1 USB2_PWR;   H0 USB1_PWR;
+        */
+       ctrl_outw(0x0050, PORT_PHCR);   /* 00 00 00 00 01 01 00 00 */
+
+       /* J7 (x);        J6 AUDCK;        J5 ASEBRKAK;     J4 AUDATA3;
+        * J3 AUDATA2;    J2 AUDATA1;      J1 AUDATA0;      J0 AUDSYNC;
+        */
+       ctrl_outw(0x0000, PORT_PJCR);   /* 00 00 00 00 00 00 00 00 */
+
+       /* K7 (x);          K6 (x);          K5 (x);       K4 (x);
+        * K3 PINT7(/PWR2); K2 PINT6(/PWR1); K1 PINT5(nu); K0 PINT4(FLASH_READY)
+        */
+       ctrl_outw(0x00FF, PORT_PKCR);   /* 00 00 00 00 11 11 11 11 */
+
+       /* L7 TRST;        L6 TMS;           L5 TDO;              L4 TDI;
+        * L3 TCK;         L2 (x);           L1 (x);              L0 (x);
+        */
+       ctrl_outw(0x0000, PORT_PLCR);   /* 00 00 00 00 00 00 00 00 */
+
+       /* M7 GPO(CURRENT_SINK);    M6 GPO(PWR_SWITCH);     M5 GPO(LAN_SPEED);
+        * M4 GPO(LAN_RESET);       M3 GPO(BUZZER);         M2 GPO(LCD_BL);
+        * M1 CS5B(CAN3_CS);        M0 GPI+(nc);
+        */
+       ctrl_outw(0x5552, PORT_PMCR);      /* 01 01 01 01 01 01 00 10 */
+
+       /* CURRENT_SINK=off,    PWR_SWITCH=off, LAN_SPEED=100MBit,
+        * LAN_RESET=off,       BUZZER=off,     LCD_BL=off
+        */
+#if CONFIG_SH_MAGIC_PANEL_R2_VERSION == 2
+       ctrl_outb(0x30, PORT_PMDR);
+#elif CONFIG_SH_MAGIC_PANEL_R2_VERSION == 3
+       ctrl_outb(0xF0, PORT_PMDR);
+#else
+#error Unknown revision of PLATFORM_MP_R2
+#endif
+
+       /* P7 (x);             P6 (x);            P5 (x);
+        * P4 GPO(nu);         P3 IRQ3(LAN_IRQ);  P2 IRQ2(CAN3_IRQ);
+        * P1 IRQ1(CAN2_IRQ);  P0 IRQ0(CAN1_IRQ)
+        */
+       ctrl_outw(0x0100, PORT_PPCR);   /* 00 00 00 01 00 00 00 00 */
+       ctrl_outb(0x10, PORT_PPDR);
+
+       /* R7 A25;           R6 A24;         R5 A23;              R4 A22;
+        * R3 A21;           R2 A20;         R1 A19;              R0 A0;
+        */
+       ctrl_outw(0x0000, PORT_PRCR);   /* 00 00 00 00 00 00 00 00 */
+
+       /* S7 (x);              S6 (x);        S5 (x);       S4 GPO(EEPROM_CS2);
+        * S3 GPO(EEPROM_CS1);  S2 SIOF0_TXD;  S1 SIOF0_RXD; S0 SIOF0_SCK;
+        */
+       ctrl_outw(0x0140, PORT_PSCR);   /* 00 00 00 01 01 00 00 00 */
+
+       /* T7 (x);         T6 (x);        T5 (x);         T4 COM1_CTS;
+        * T3 COM1_RTS;    T2 COM1_TXD;   T1 COM1_RXD;    T0 GPO(WDOG)
+        */
+       ctrl_outw(0x0001, PORT_PTCR);   /* 00 00 00 00 00 00 00 01 */
+
+       /* U7 (x);           U6 (x);       U5 (x);        U4 GPI+(/AC_FAULT);
+        * U3 GPO(TOUCH_CS); U2 TOUCH_TXD; U1 TOUCH_RXD;  U0 TOUCH_SCK;
+        */
+       ctrl_outw(0x0240, PORT_PUCR);   /* 00 00 00 10 01 00 00 00 */
+
+       /* V7 (x);        V6 (x);       V5 (x);           V4 GPO(MID2);
+        * V3 GPO(MID1);  V2 CARD_TxD;  V1 CARD_RxD;      V0 GPI+(/BAT_FAULT);
+        */
+       ctrl_outw(0x0142, PORT_PVCR);   /* 00 00 00 01 01 00 00 10 */
+}
+
+static void __init mpr2_setup(char **cmdline_p)
+{
+       __set_io_port_base(0xa0000000);
+
+       /* set Pin Select Register A:
+        * /PCC_CD1, /PCC_CD2,  PCC_BVD1, PCC_BVD2,
+        * /IOIS16,  IRQ4,      IRQ5,     USB1d_SUSPEND
+        */
+       ctrl_outw(0xAABC, PORT_PSELA);
+       /* set Pin Select Register B:
+        * /SCIF0_RTS, /SCIF0_CTS, LCD_VCPWC,
+        * LCD_VEPWC,  IIC_SDA,    IIC_SCL, Reserved
+        */
+       ctrl_outw(0x3C00, PORT_PSELB);
+       /* set Pin Select Register C:
+        * SIOF1_SCK, SIOF1_RxD, SCIF1_RxD, SCIF1_TxD, Reserved
+        */
+       ctrl_outw(0x0000, PORT_PSELC);
+       /* set Pin Select Register D: Reserved, SIOF1_TxD, Reserved, SIOF1_MCLK,
+        * Reserved, SIOF1_SYNC, Reserved, SCIF1_SCK, Reserved
+        */
+       ctrl_outw(0x0000, PORT_PSELD);
+       /* set USB TxRx Control: Reserved, DRV, Reserved, USB_TRANS, USB_SEL */
+       ctrl_outw(0x0101, PORT_UTRCTL);
+       /* set USB Clock Control: USSCS, USSTB, Reserved (HighByte always A5) */
+       ctrl_outw(0xA5C0, PORT_UCLKCR_W);
+
+       setup_chip_select();
+
+       setup_port_multiplexing();
+
+       reset_ethernet();
+
+       printk(KERN_INFO "Magic Panel Release 2 A.%i\n",
+                               CONFIG_SH_MAGIC_PANEL_R2_VERSION);
+
+       if (ethernet_reset_finished() == 0)
+               printk(KERN_WARNING "Ethernet not ready\n");
+}
+
+static struct resource smc911x_resources[] = {
+       [0] = {
+               .start          = 0xa8000000,
+               .end            = 0xabffffff,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = 35,
+               .end            = 35,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smc911x_device = {
+       .name           = "smc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc911x_resources),
+       .resource       = smc911x_resources,
+};
+
+static struct resource heartbeat_resources[] = {
+       [0] = {
+               .start  = PA_LED,
+               .end    = PA_LED,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct heartbeat_data heartbeat_data = {
+       .flags          = HEARTBEAT_INVERTED,
+};
+
+static struct platform_device heartbeat_device = {
+       .name           = "heartbeat",
+       .id             = -1,
+       .dev    = {
+               .platform_data  = &heartbeat_data,
+       },
+       .num_resources  = ARRAY_SIZE(heartbeat_resources),
+       .resource       = heartbeat_resources,
+};
+
+static struct mtd_partition *parsed_partitions;
+
+static struct mtd_partition mpr2_partitions[] = {
+       /* Reserved for bootloader, read-only */
+       {
+               .name = "Bootloader",
+               .offset = 0x00000000UL,
+               .size = MPR2_MTD_BOOTLOADER_SIZE,
+               .mask_flags = MTD_WRITEABLE,
+       },
+       /* Reserved for kernel image */
+       {
+               .name = "Kernel",
+               .offset = MTDPART_OFS_NXTBLK,
+               .size = MPR2_MTD_KERNEL_SIZE,
+       },
+       /* Rest is used for Flash FS */
+       {
+               .name = "Flash_FS",
+               .offset = MTDPART_OFS_NXTBLK,
+               .size = MTDPART_SIZ_FULL,
+       }
+};
+
+static struct physmap_flash_data flash_data = {
+       .width          = 2,
+};
+
+static struct resource flash_resource = {
+       .start          = 0x00000000,
+       .end            = 0x2000000UL,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+       .name           = "physmap-flash",
+       .id             = -1,
+       .resource       = &flash_resource,
+       .num_resources  = 1,
+       .dev            = {
+               .platform_data = &flash_data,
+       },
+};
+
+static struct mtd_info *flash_mtd;
+
+static struct map_info mpr2_flash_map = {
+       .name = "Magic Panel R2 Flash",
+       .size = 0x2000000UL,
+       .bankwidth = 2,
+};
+
+static void __init set_mtd_partitions(void)
+{
+       int nr_parts = 0;
+
+       simple_map_init(&mpr2_flash_map);
+       flash_mtd = do_map_probe("cfi_probe", &mpr2_flash_map);
+       nr_parts = parse_mtd_partitions(flash_mtd, probes,
+                                       &parsed_partitions, 0);
+       /* If there is no partition table, used the hard coded table */
+       if (nr_parts <= 0) {
+               flash_data.parts = mpr2_partitions;
+               flash_data.nr_parts = ARRAY_SIZE(mpr2_partitions);
+       } else {
+               flash_data.nr_parts = nr_parts;
+               flash_data.parts = parsed_partitions;
+       }
+}
+
+/*
+ * Add all resources to the platform_device
+ */
+
+static struct platform_device *mpr2_devices[] __initdata = {
+       &heartbeat_device,
+       &smc911x_device,
+       &flash_device,
+};
+
+
+static int __init mpr2_devices_setup(void)
+{
+       set_mtd_partitions();
+       return platform_add_devices(mpr2_devices, ARRAY_SIZE(mpr2_devices));
+}
+device_initcall(mpr2_devices_setup);
+
+/*
+ * Initialize IRQ setting
+ */
+static void __init init_mpr2_IRQ(void)
+{
+       plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-5 */
+
+       set_irq_type(32, IRQ_TYPE_LEVEL_LOW);    /* IRQ0 CAN1 */
+       set_irq_type(33, IRQ_TYPE_LEVEL_LOW);    /* IRQ1 CAN2 */
+       set_irq_type(34, IRQ_TYPE_LEVEL_LOW);    /* IRQ2 CAN3 */
+       set_irq_type(35, IRQ_TYPE_LEVEL_LOW);    /* IRQ3 SMSC9115 */
+       set_irq_type(36, IRQ_TYPE_EDGE_RISING);  /* IRQ4 touchscreen */
+       set_irq_type(37, IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
+
+       intc_set_priority(32, 13);              /* IRQ0 CAN1 */
+       intc_set_priority(33, 13);              /* IRQ0 CAN2 */
+       intc_set_priority(34, 13);              /* IRQ0 CAN3 */
+       intc_set_priority(35, 6);               /* IRQ3 SMSC9115 */
+}
+
+/*
+ * The Machine Vector
+ */
+
+static struct sh_machine_vector mv_mpr2 __initmv = {
+       .mv_name                = "mpr2",
+       .mv_setup               = mpr2_setup,
+       .mv_init_irq            = init_mpr2_IRQ,
+};
index 8ce03e00b0ae34a97a939e4c9a1d250fdce6b309..fede36361dc78065c7999014ac3e61be16bf1b95 100644 (file)
@@ -285,7 +285,7 @@ static int put_smb_blk(unsigned char *p, int address, int command, int no)
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = 0xa2000000,
-               .end    = 0xa2000000 + 8 - 1,
+               .end    = 0xa2000000,
                .flags  = IORESOURCE_MEM,
        },
 };
index b1d20afb4eb3b6d4f3de512e13b62cf40d51851a..dd26182fbf58a223f56a95cf72a25a37b312a3f1 100644 (file)
@@ -1,9 +1,10 @@
 #
 # Makefile for the R7780RP-1 specific parts of the kernel
 #
-irqinit-y                      := irq-r7780rp.o
+irqinit-$(CONFIG_SH_R7780MP)   := irq-r7780mp.o
 irqinit-$(CONFIG_SH_R7785RP)   := irq-r7785rp.o
-obj-y                          := setup.o irq.o $(irqinit-y)
+irqinit-$(CONFIG_SH_R7780RP)   := irq-r7780rp.o irq.o
+obj-y                          := setup.o $(irqinit-y)
 
 ifneq ($(CONFIG_SH_R7785RP),y)
 obj-$(CONFIG_PUSH_SWITCH)      += psw.o
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
new file mode 100644 (file)
index 0000000..59b47fe
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Renesas Solutions Highlander R7780MP Support.
+ *
+ * Copyright (C) 2002  Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2006  Paul Mundt
+ * Copyright (C) 2007  Magnus Damm
+ *
+ * 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 more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/r7780rp.h>
+
+enum {
+       UNUSED = 0,
+
+       /* board specific interrupt sources */
+       AX88796,          /* Ethernet controller */
+       CF,               /* Compact Flash */
+       PSW,              /* Push Switch */
+       EXT1,             /* EXT1n IRQ */
+       EXT4,             /* EXT4n IRQ */
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_IRQ(CF, IRQ_CF),
+       INTC_IRQ(PSW, IRQ_PSW),
+       INTC_IRQ(AX88796, IRQ_AX88796),
+       INTC_IRQ(EXT1, IRQ_EXT1),
+       INTC_IRQ(EXT4, IRQ_EXT4),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xa4000000, 0, 16, /* IRLMSK */
+         { 0, 0, 0, 0, CF, 0, 0, 0,
+           0, 0, 0, EXT4, 0, EXT1, PSW, AX88796 } },
+};
+
+static unsigned char irl2irq[HL_NR_IRL] __initdata = {
+       0, IRQ_CF, 0, 0,
+       0, 0, 0, 0,
+       0, IRQ_EXT4, 0, IRQ_EXT1,
+       0, IRQ_AX88796, IRQ_PSW,
+};
+
+static DECLARE_INTC_DESC(intc_desc, "r7780mp", vectors,
+                        NULL, NULL, mask_registers, NULL, NULL);
+
+unsigned char * __init highlander_init_irq_r7780mp(void)
+{
+       if ((ctrl_inw(0xa4000700) & 0xf000) == 0x2000) {
+               printk(KERN_INFO "Using r7780mp interrupt controller.\n");
+               register_intc_controller(&intc_desc);
+               return irl2irq;
+       }
+
+       return NULL;
+}
index f5f358746c9e03c2450c65948f7e2021ada2eb9a..fa4a534cade924d7bfaf502bf5e6af0997c32ed1 100644 (file)
@@ -9,13 +9,15 @@
  * for more details.
  */
 #include <linux/init.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/r7780rp.h>
 
-void __init highlander_init_irq(void)
+unsigned char * __init highlander_init_irq_r7780rp(void)
 {
        int i;
 
        for (i = 0; i < 15; i++)
                make_r7780rp_irq(i);
+
+       return NULL;
 }
index dd6ec4ce44dcae9fb7f6d1c8ed9fb3ba28e54f95..b2c6a84673bdc702462ca7ca19f6fece6f643a29 100644 (file)
@@ -1,19 +1,55 @@
 /*
- * Renesas Solutions Highlander R7780RP-1 Support.
+ * Renesas Solutions Highlander R7785RP Support.
  *
  * Copyright (C) 2002  Atom Create Engineering Co., Ltd.
  * Copyright (C) 2006  Paul Mundt
+ * Copyright (C) 2007  Magnus Damm
  *
  * 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 more details.
  */
 #include <linux/init.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/io.h>
 #include <asm/r7780rp.h>
 
-void __init highlander_init_irq(void)
+enum {
+       UNUSED = 0,
+
+       /* board specific interrupt sources */
+       AX88796,          /* Ethernet controller */
+       CF,               /* Compact Flash */
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_IRQ(CF, IRQ_CF),
+       INTC_IRQ(AX88796, IRQ_AX88796),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xa4000010, 0, 16, /* IRLMCR1 */
+         { 0, 0, 0, 0, CF, AX88796, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0 } },
+};
+
+static unsigned char irl2irq[HL_NR_IRL] __initdata = {
+       0, IRQ_CF, 0, 0,
+       0, 0, 0, 0,
+       0, 0, IRQ_AX88796, 0,
+       0, 0, 0,
+};
+
+static DECLARE_INTC_DESC(intc_desc, "r7785rp", vectors,
+                        NULL, NULL, mask_registers, NULL, NULL);
+
+unsigned char * __init highlander_init_irq_r7785rp(void)
 {
+       if ((ctrl_inw(0xa4000158) & 0xf000) != 0x1000)
+               return NULL;
+
+       printk(KERN_INFO "Using r7785rp interrupt controller.\n");
+
        ctrl_outw(0x0000, PA_IRLSSR1);  /* FPGA IRLSSR1(CF_CD clear) */
 
        /* Setup the FPGA IRL */
@@ -24,6 +60,6 @@ void __init highlander_init_irq(void)
        ctrl_outw(0x4321, PA_IRLPRE);   /* FPGA IRLE */
        ctrl_outw(0x0000, PA_IRLPRF);   /* FPGA IRLF */
 
-       make_r7780rp_irq(1);    /* CF card */
-       make_r7780rp_irq(10);   /* On-board ethernet */
+       register_intc_controller(&intc_desc);
+       return irl2irq;
 }
index adb529d01bae302ce06cfeb3064952670ee31877..afe9de73666ad8117f8e63b4abd054c16e012427 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/machvec.h>
 #include <asm/r7780rp.h>
 #include <asm/clock.h>
+#include <asm/heartbeat.h>
 #include <asm/io.h>
 
 static struct resource r8a66597_usb_host_resources[] = {
@@ -30,8 +31,8 @@ static struct resource r8a66597_usb_host_resources[] = {
        },
        [1] = {
                .name   = "r8a66597_hcd",
-               .start  = 11,           /* irq number */
-               .end    = 11,
+               .start  = IRQ_EXT1,             /* irq number */
+               .end    = IRQ_EXT1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -56,8 +57,8 @@ static struct resource m66592_usb_peripheral_resources[] = {
        },
        [1] = {
                .name   = "m66592_udc",
-               .start  = 9,            /* irq number */
-               .end    = 9,
+               .start  = IRQ_EXT4,             /* irq number */
+               .end    = IRQ_EXT4,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -85,11 +86,7 @@ static struct resource cf_ide_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
-#ifdef CONFIG_SH_R7780RP
-               .start  = 4,
-#else
-               .start  = 1,
-#endif
+               .start  = IRQ_CF,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -108,16 +105,23 @@ static struct platform_device cf_ide_device  = {
        },
 };
 
-static unsigned char heartbeat_bit_pos[] = { 2, 1, 0, 3, 6, 5, 4, 7 };
-
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = PA_OBLED,
-               .end    = PA_OBLED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+               .end    = PA_OBLED,
                .flags  = IORESOURCE_MEM,
        },
 };
 
+#ifndef CONFIG_SH_R7785RP
+static unsigned char heartbeat_bit_pos[] = { 2, 1, 0, 3, 6, 5, 4, 7 };
+
+static struct heartbeat_data heartbeat_data = {
+       .bit_pos        = heartbeat_bit_pos,
+       .nr_bits        = ARRAY_SIZE(heartbeat_bit_pos),
+};
+#endif
+
 static struct platform_device heartbeat_device = {
        .name           = "heartbeat",
        .id             = -1,
@@ -125,7 +129,7 @@ static struct platform_device heartbeat_device = {
        /* R7785RP has a slightly more sensible FPGA.. */
 #ifndef CONFIG_SH_R7785RP
        .dev    = {
-               .platform_data  = heartbeat_bit_pos,
+               .platform_data  = &heartbeat_data,
        },
 #endif
        .num_resources  = ARRAY_SIZE(heartbeat_resources),
@@ -217,12 +221,50 @@ static void __init highlander_setup(char **cmdline_p)
        pm_power_off = r7780rp_power_off;
 }
 
+static unsigned char irl2irq[HL_NR_IRL];
+
+int highlander_irq_demux(int irq)
+{
+       if (irq >= HL_NR_IRL || !irl2irq[irq])
+               return irq;
+
+       return irl2irq[irq];
+}
+
+void __init highlander_init_irq(void)
+{
+       unsigned char *ucp = NULL;
+
+       do {
+#ifdef CONFIG_SH_R7780MP
+               ucp = highlander_init_irq_r7780mp();
+               if (ucp)
+                       break;
+#endif
+#ifdef CONFIG_SH_R7785RP
+               ucp = highlander_init_irq_r7785rp();
+               if (ucp)
+                       break;
+#endif
+#ifdef CONFIG_SH_R7780RP
+               highlander_init_irq_r7780rp();
+               ucp = irl2irq;
+               break;
+#endif
+       } while (0);
+
+       if (ucp) {
+               plat_irq_setup_pins(IRQ_MODE_IRL3210);
+               memcpy(irl2irq, ucp, HL_NR_IRL);
+       }
+}
+
 /*
  * The Machine Vector
  */
 static struct sh_machine_vector mv_highlander __initmv = {
        .mv_name                = "Highlander",
-       .mv_nr_irqs             = 109,
        .mv_setup               = highlander_setup,
        .mv_init_irq            = highlander_init_irq,
+       .mv_irq_demux           = highlander_irq_demux,
 };
index 7780d1fb13fff8e3f842f6c4758b1dec76bbb028..8122a9667fc9a080183dce100f5a7e5656c88177 100644 (file)
@@ -1,11 +1,22 @@
 if SH_RTS7751R2D
 
-menu "RTS7751R2D options"
+menu "RTS7751R2D Board Revision"
 
-config RTS7751R2D_REV11
-       bool "RTS7751R2D Rev. 1.1 board support"
+config RTS7751R2D_PLUS
+       bool "R2D-PLUS"
        help
-         Selecting this option will support version rev. 1.1.
+         Selecting this option will configure the kernel for R2D-PLUS.
+
+         R2D-PLUS is the smaller of the two R2D board versions, equipped
+         with a single PCI slot.
+
+config RTS7751R2D_1
+       bool "R2D-1"
+       help
+         Selecting this option will configure the kernel for R2D-1.
+
+         R2D-1 is the larger of the two R2D board versions, equipped
+         with two PCI slots.
 endmenu
 
 endif
index 0bae9041acebaa04e9a9dede1593096267bb2750..7cc2813adfe4bb172a97d32b9d2f3cd8fa08d95f 100644 (file)
 /*
  * linux/arch/sh/boards/renesas/rts7751r2d/irq.c
  *
+ * Copyright (C) 2007  Magnus Damm
  * Copyright (C) 2000  Kazumoto Kojima
  *
- * Renesas Technology Sales RTS7751R2D Support.
+ * Renesas Technology Sales RTS7751R2D Support, R2D-PLUS and R2D-1.
  *
  * Modified for RTS7751R2D by
  * Atom Create Engineering Co., Ltd. 2002.
  */
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <asm/voyagergx.h>
 #include <asm/rts7751r2d.h>
 
-#if defined(CONFIG_RTS7751R2D_REV11)
-static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0};
-#else
-static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0};
-#endif
+#define R2D_NR_IRL 13
 
-extern int voyagergx_irq_demux(int irq);
-extern void setup_voyagergx_irq(void);
+enum {
+       UNUSED = 0,
 
-static void enable_rts7751r2d_irq(unsigned int irq)
-{
-       /* Set priority in IPR back to original value */
-       ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1);
-}
+       /* board specific interrupt sources (R2D-1 and R2D-PLUS) */
+       EXT,              /* EXT_INT0-3 */
+       RTC_T, RTC_A,     /* Real Time Clock */
+       AX88796,          /* Ethernet controller (R2D-1 board) */
+       KEY,              /* Key input (R2D-PLUS board) */
+       SDCARD,           /* SD Card */
+       CF_CD, CF_IDE,    /* CF Card Detect + CF IDE */
+       SM501,            /* SM501 aka Voyager */
+       PCI_INTD_RTL8139, /* Ethernet controller */
+       PCI_INTC_PCI1520, /* Cardbus/PCMCIA bridge */
+       PCI_INTB_RTL8139, /* Ethernet controller with HUB (R2D-PLUS board) */
+       PCI_INTB_SLOT,    /* PCI Slot 3.3v (R2D-1 board) */
+       PCI_INTA_SLOT,    /* PCI Slot 3.3v */
+       TP,               /* Touch Panel */
+};
 
-static void disable_rts7751r2d_irq(unsigned int irq)
-{
-       /* Set the priority in IPR to 0 */
-       ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])),
-                 IRLCNTR1);
-}
+#ifdef CONFIG_RTS7751R2D_1
+
+/* Vectors for R2D-1 */
+static struct intc_vect vectors_r2d_1[] __initdata = {
+       INTC_IRQ(EXT, IRQ_EXT),
+       INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A),
+       INTC_IRQ(AX88796, IRQ_AX88796), INTC_IRQ(SDCARD, IRQ_SDCARD),
+       INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE), /* ng */
+       INTC_IRQ(SM501, IRQ_VOYAGER),
+       INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD),
+       INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC),
+       INTC_IRQ(PCI_INTB_SLOT, IRQ_PCI_INTB),
+       INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA),
+       INTC_IRQ(TP, IRQ_TP),
+};
+
+/* IRLMSK mask register layout for R2D-1 */
+static struct intc_mask_reg mask_registers_r2d_1[] __initdata = {
+       { 0xa4000000, 0, 16, /* IRLMSK */
+         { TP, PCI_INTA_SLOT, PCI_INTB_SLOT,
+           PCI_INTC_PCI1520, PCI_INTD_RTL8139,
+           SM501, CF_IDE, CF_CD, SDCARD, AX88796,
+           RTC_A, RTC_T, 0, 0, 0, EXT } },
+};
+
+/* IRLn to IRQ table for R2D-1 */
+static unsigned char irl2irq_r2d_1[R2D_NR_IRL] __initdata = {
+       IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC,
+       IRQ_VOYAGER, IRQ_AX88796, IRQ_RTC_A, IRQ_RTC_T,
+       IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT,
+       IRQ_TP,
+};
+
+static DECLARE_INTC_DESC(intc_desc_r2d_1, "r2d-1", vectors_r2d_1,
+                        NULL, NULL, mask_registers_r2d_1, NULL, NULL);
+
+#endif /* CONFIG_RTS7751R2D_1 */
+
+#ifdef CONFIG_RTS7751R2D_PLUS
+
+/* Vectors for R2D-PLUS */
+static struct intc_vect vectors_r2d_plus[] __initdata = {
+       INTC_IRQ(EXT, IRQ_EXT),
+       INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A),
+       INTC_IRQ(KEY, IRQ_KEY), INTC_IRQ(SDCARD, IRQ_SDCARD),
+       INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE),
+       INTC_IRQ(SM501, IRQ_VOYAGER),
+       INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD),
+       INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC),
+       INTC_IRQ(PCI_INTB_RTL8139, IRQ_PCI_INTB),
+       INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA),
+       INTC_IRQ(TP, IRQ_TP),
+};
+
+/* IRLMSK mask register layout for R2D-PLUS */
+static struct intc_mask_reg mask_registers_r2d_plus[] __initdata = {
+       { 0xa4000000, 0, 16, /* IRLMSK */
+         { TP, PCI_INTA_SLOT, PCI_INTB_RTL8139,
+           PCI_INTC_PCI1520, PCI_INTD_RTL8139,
+           SM501, CF_IDE, CF_CD, SDCARD, KEY,
+           RTC_A, RTC_T, 0, 0, 0, EXT } },
+};
+
+/* IRLn to IRQ table for R2D-PLUS */
+static unsigned char irl2irq_r2d_plus[R2D_NR_IRL] __initdata = {
+       IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC,
+       IRQ_VOYAGER, IRQ_KEY, IRQ_RTC_A, IRQ_RTC_T,
+       IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT,
+       IRQ_TP,
+};
+
+static DECLARE_INTC_DESC(intc_desc_r2d_plus, "r2d-plus", vectors_r2d_plus,
+                        NULL, NULL, mask_registers_r2d_plus, NULL, NULL);
+
+#endif /* CONFIG_RTS7751R2D_PLUS */
+
+static unsigned char irl2irq[R2D_NR_IRL];
 
 int rts7751r2d_irq_demux(int irq)
 {
-       return voyagergx_irq_demux(irq);
-}
+       if (irq >= R2D_NR_IRL || !irl2irq[irq])
+               return irq;
 
-static struct irq_chip rts7751r2d_irq_chip __read_mostly = {
-       .name           = "rts7751r2d",
-       .mask           = disable_rts7751r2d_irq,
-       .unmask         = enable_rts7751r2d_irq,
-       .mask_ack       = disable_rts7751r2d_irq,
-};
+       return irl2irq[irq];
+}
 
 /*
  * Initialize IRQ setting
  */
 void __init init_rts7751r2d_IRQ(void)
 {
-       int i;
-
-       /* IRL0=KEY Input
-        * IRL1=Ethernet
-        * IRL2=CF Card
-        * IRL3=CF Card Insert
-        * IRL4=PCMCIA
-        * IRL5=VOYAGER
-        * IRL6=RTC Alarm
-        * IRL7=RTC Timer
-        * IRL8=SD Card
-        * IRL9=PCI Slot #1
-        * IRL10=PCI Slot #2
-        * IRL11=Extention #0
-        * IRL12=Extention #1
-        * IRL13=Extention #2
-        * IRL14=Extention #3
-        */
-
-       for (i=0; i<15; i++) {
-               disable_irq_nosync(i);
-               set_irq_chip_and_handler_name(i, &rts7751r2d_irq_chip,
-                                             handle_level_irq, "level");
-               enable_rts7751r2d_irq(i);
+       struct intc_desc *d;
+
+       switch (ctrl_inw(PA_VERREG) & 0xf0) {
+#ifdef CONFIG_RTS7751R2D_PLUS
+       case 0x10:
+               printk(KERN_INFO "Using R2D-PLUS interrupt controller.\n");
+               d = &intc_desc_r2d_plus;
+               memcpy(irl2irq, irl2irq_r2d_plus, R2D_NR_IRL);
+               break;
+#endif
+#ifdef CONFIG_RTS7751R2D_1
+       case 0x00: /* according to manual */
+       case 0x30: /* in reality */
+               printk(KERN_INFO "Using R2D-1 interrupt controller.\n");
+               d = &intc_desc_r2d_1;
+               memcpy(irl2irq, irl2irq_r2d_1, R2D_NR_IRL);
+               break;
+#endif
+       default:
+               printk(KERN_INFO "Unknown R2D interrupt controller 0x%04x\n",
+                      ctrl_inw(PA_VERREG));
+               return;
        }
 
+       register_intc_controller(d);
+#ifdef CONFIG_MFD_SM501
        setup_voyagergx_irq();
+#endif
 }
index 6f7029d33241db4beeb46395968c24b81e0403e0..37f2c0b447fe48798b64e07fd2a28d626bcfea02 100644 (file)
@@ -45,20 +45,16 @@ static void __init voyagergx_serial_init(void)
 static struct resource cf_ide_resources[] = {
        [0] = {
                .start  = PA_AREA5_IO + 0x1000,
-               .end    = PA_AREA5_IO + 0x1000 + 0x08 - 1,
+               .end    = PA_AREA5_IO + 0x1000 + 0x10 - 0x2,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
                .start  = PA_AREA5_IO + 0x80c,
-               .end    = PA_AREA5_IO + 0x80c + 0x16 - 1,
+               .end    = PA_AREA5_IO + 0x80c,
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
-#ifdef CONFIG_RTS7751R2D_REV11
-               .start  = 1,
-#else
-               .start  = 2,
-#endif
+               .start  = IRQ_CF_IDE,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -77,12 +73,28 @@ static struct platform_device cf_ide_device  = {
        },
 };
 
+static struct resource heartbeat_resources[] = {
+       [0] = {
+               .start  = PA_OUTPORT,
+               .end    = PA_OUTPORT,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device heartbeat_device = {
+       .name           = "heartbeat",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(heartbeat_resources),
+       .resource       = heartbeat_resources,
+};
+
+#ifdef CONFIG_MFD_SM501
 static struct plat_serial8250_port uart_platform_data[] = {
        {
                .membase        = (void __iomem *)VOYAGER_UART_BASE,
                .mapbase        = VOYAGER_UART_BASE,
                .iotype         = UPIO_MEM,
-               .irq            = VOYAGER_UART0_IRQ,
+               .irq            = IRQ_SM501_U0,
                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
                .regshift       = 2,
                .uartclk        = (9600 * 16),
@@ -98,21 +110,6 @@ static struct platform_device uart_device = {
        },
 };
 
-static struct resource heartbeat_resources[] = {
-       [0] = {
-               .start  = PA_OUTPORT,
-               .end    = PA_OUTPORT + 8 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device heartbeat_device = {
-       .name           = "heartbeat",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(heartbeat_resources),
-       .resource       = heartbeat_resources,
-};
-
 static struct resource sm501_resources[] = {
        [0]     = {
                .start  = 0x10000000,
@@ -125,7 +122,7 @@ static struct resource sm501_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [2]     = {
-               .start  = 32,
+               .start  = IRQ_SM501_CV,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -137,22 +134,19 @@ static struct platform_device sm501_device = {
        .resource       = sm501_resources,
 };
 
+#endif /* CONFIG_MFD_SM501 */
+
 static struct platform_device *rts7751r2d_devices[] __initdata = {
+#ifdef CONFIG_MFD_SM501
        &uart_device,
-       &heartbeat_device,
        &sm501_device,
+#endif
+       &cf_ide_device,
+       &heartbeat_device,
 };
 
 static int __init rts7751r2d_devices_setup(void)
 {
-       int ret;
-
-       if (ctrl_inw(PA_BVERREG) == 0x10) { /* only working on R2D-PLUS */
-               ret = platform_device_register(&cf_ide_device);
-               if (ret)
-                       return ret;
-       }
-
        return platform_add_devices(rts7751r2d_devices,
                                    ARRAY_SIZE(rts7751r2d_devices));
 }
@@ -163,6 +157,34 @@ static void rts7751r2d_power_off(void)
        ctrl_outw(0x0001, PA_POWOFF);
 }
 
+static inline unsigned char is_ide_ioaddr(unsigned long addr)
+{
+       return ((cf_ide_resources[0].start <= addr &&
+                addr <= cf_ide_resources[0].end) ||
+               (cf_ide_resources[1].start <= addr &&
+                addr <= cf_ide_resources[1].end));
+}
+
+void rts7751r2d_writeb(u8 b, void __iomem *addr)
+{
+       unsigned long tmp = (unsigned long __force)addr;
+
+       if (is_ide_ioaddr(tmp))
+               ctrl_outw((u16)b, tmp);
+       else
+               ctrl_outb(b, tmp);
+}
+
+u8 rts7751r2d_readb(void __iomem *addr)
+{
+       unsigned long tmp = (unsigned long __force)addr;
+
+       if (is_ide_ioaddr(tmp))
+               return ctrl_inw(tmp) & 0xff;
+       else
+               return ctrl_inb(tmp);
+}
+
 /*
  * Initialize the board
  */
@@ -187,12 +209,11 @@ static void __init rts7751r2d_setup(char **cmdline_p)
 static struct sh_machine_vector mv_rts7751r2d __initmv = {
        .mv_name                = "RTS7751R2D",
        .mv_setup               = rts7751r2d_setup,
-       .mv_nr_irqs             = 72,
-
        .mv_init_irq            = init_rts7751r2d_IRQ,
        .mv_irq_demux           = rts7751r2d_irq_demux,
-
-#ifdef CONFIG_USB_SM501
+       .mv_writeb              = rts7751r2d_writeb,
+       .mv_readb               = rts7751r2d_readb,
+#if defined(CONFIG_MFD_SM501) && defined(CONFIG_USB_OHCI_HCD)
        .mv_consistent_alloc    = voyagergx_consistent_alloc,
        .mv_consistent_free     = voyagergx_consistent_free,
 #endif
diff --git a/arch/sh/boards/renesas/x3proto/Makefile b/arch/sh/boards/renesas/x3proto/Makefile
new file mode 100644 (file)
index 0000000..983e455
--- /dev/null
@@ -0,0 +1 @@
+obj-y += setup.o ilsel.o
diff --git a/arch/sh/boards/renesas/x3proto/ilsel.c b/arch/sh/boards/renesas/x3proto/ilsel.c
new file mode 100644 (file)
index 0000000..6d4454f
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * arch/sh/boards/renesas/x3proto/ilsel.c
+ *
+ * Helper routines for SH-X3 proto board ILSEL.
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * 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 more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitmap.h>
+#include <linux/io.h>
+#include <asm/ilsel.h>
+
+/*
+ * ILSEL is split across:
+ *
+ *     ILSEL0 - 0xb8100004 [ Levels  1 -  4 ]
+ *     ILSEL1 - 0xb8100006 [ Levels  5 -  8 ]
+ *     ILSEL2 - 0xb8100008 [ Levels  9 - 12 ]
+ *     ILSEL3 - 0xb810000a [ Levels 13 - 15 ]
+ *
+ * With each level being relative to an ilsel_source_t.
+ */
+#define ILSEL_BASE     0xb8100004
+#define ILSEL_LEVELS   15
+
+/*
+ * ILSEL level map, in descending order from the highest level down.
+ *
+ * Supported levels are 1 - 15 spread across ILSEL0 - ILSEL4, mapping
+ * directly to IRLs. As the IRQs are numbered in reverse order relative
+ * to the interrupt level, the level map is carefully managed to ensure a
+ * 1:1 mapping between the bit position and the IRQ number.
+ *
+ * This careful constructions allows ilsel_enable*() to be referenced
+ * directly for hooking up an ILSEL set and getting back an IRQ which can
+ * subsequently be used for internal accounting in the (optional) disable
+ * path.
+ */
+static unsigned long ilsel_level_map;
+
+static inline unsigned int ilsel_offset(unsigned int bit)
+{
+       return ILSEL_LEVELS - bit - 1;
+}
+
+static inline unsigned long mk_ilsel_addr(unsigned int bit)
+{
+       return ILSEL_BASE + ((ilsel_offset(bit) >> 1) & ~0x1);
+}
+
+static inline unsigned int mk_ilsel_shift(unsigned int bit)
+{
+       return (ilsel_offset(bit) & 0x3) << 2;
+}
+
+static void __ilsel_enable(ilsel_source_t set, unsigned int bit)
+{
+       unsigned int tmp, shift;
+       unsigned long addr;
+
+       addr = mk_ilsel_addr(bit);
+       shift = mk_ilsel_shift(bit);
+
+       pr_debug("%s: bit#%d: addr - 0x%08lx (shift %d, set %d)\n",
+                __FUNCTION__, bit, addr, shift, set);
+
+       tmp = ctrl_inw(addr);
+       tmp &= ~(0xf << shift);
+       tmp |= set << shift;
+       ctrl_outw(tmp, addr);
+}
+
+/**
+ * ilsel_enable - Enable an ILSEL set.
+ * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h).
+ *
+ * Enables a given non-aliased ILSEL source (<= ILSEL_KEY) at the highest
+ * available interrupt level. Callers should take care to order callsites
+ * noting descending interrupt levels. Aliasing FPGA and external board
+ * IRQs need to use ilsel_enable_fixed().
+ *
+ * The return value is an IRQ number that can later be taken down with
+ * ilsel_disable().
+ */
+int ilsel_enable(ilsel_source_t set)
+{
+       unsigned int bit;
+
+       /* Aliased sources must use ilsel_enable_fixed() */
+       BUG_ON(set > ILSEL_KEY);
+
+       do {
+               bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
+       } while (test_and_set_bit(bit, &ilsel_level_map));
+
+       __ilsel_enable(set, bit);
+
+       return bit;
+}
+EXPORT_SYMBOL_GPL(ilsel_enable);
+
+/**
+ * ilsel_enable_fixed - Enable an ILSEL set at a fixed interrupt level
+ * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h).
+ * @level: Interrupt level (1 - 15)
+ *
+ * Enables a given ILSEL source at a fixed interrupt level. Necessary
+ * both for level reservation as well as for aliased sources that only
+ * exist on special ILSEL#s.
+ *
+ * Returns an IRQ number (as ilsel_enable()).
+ */
+int ilsel_enable_fixed(ilsel_source_t set, unsigned int level)
+{
+       unsigned int bit = ilsel_offset(level - 1);
+
+       if (test_and_set_bit(bit, &ilsel_level_map))
+               return -EBUSY;
+
+       __ilsel_enable(set, bit);
+
+       return bit;
+}
+EXPORT_SYMBOL_GPL(ilsel_enable_fixed);
+
+/**
+ * ilsel_disable - Disable an ILSEL set
+ * @irq: Bit position for ILSEL set value (retval from enable routines)
+ *
+ * Disable a previously enabled ILSEL set.
+ */
+void ilsel_disable(unsigned int irq)
+{
+       unsigned long addr;
+       unsigned int tmp;
+
+       addr = mk_ilsel_addr(irq);
+
+       tmp = ctrl_inw(addr);
+       tmp &= ~(0xf << mk_ilsel_shift(irq));
+       ctrl_outw(tmp, addr);
+
+       clear_bit(irq, &ilsel_level_map);
+}
+EXPORT_SYMBOL_GPL(ilsel_disable);
diff --git a/arch/sh/boards/renesas/x3proto/setup.c b/arch/sh/boards/renesas/x3proto/setup.c
new file mode 100644 (file)
index 0000000..abc5b6d
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * arch/sh/boards/renesas/x3proto/setup.c
+ *
+ * Renesas SH-X3 Prototype Board Support.
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * 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 more details.
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/ilsel.h>
+
+static struct resource heartbeat_resources[] = {
+       [0] = {
+               .start  = 0xb8140020,
+               .end    = 0xb8140020,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device heartbeat_device = {
+       .name           = "heartbeat",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(heartbeat_resources),
+       .resource       = heartbeat_resources,
+};
+
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .start          = 0x18000300,
+               .end            = 0x18000300 + 0x10 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               /* Filled in by ilsel */
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smc91x_device = {
+       .name           = "smc91x",
+       .id             = -1,
+       .resource       = smc91x_resources,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+       [0] = {
+               .name   = "r8a66597_hcd",
+               .start  = 0x18040000,
+               .end    = 0x18080000 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = "r8a66597_hcd",
+               /* Filled in by ilsel */
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+       .name           = "r8a66597_hcd",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = NULL,         /* don't use dma */
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
+       .resource       = r8a66597_usb_host_resources,
+};
+
+static struct resource m66592_usb_peripheral_resources[] = {
+       [0] = {
+               .name   = "m66592_udc",
+               .start  = 0x18080000,
+               .end    = 0x180c0000 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = "m66592_udc",
+               /* Filled in by ilsel */
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m66592_usb_peripheral_device = {
+       .name           = "m66592_udc",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = NULL,         /* don't use dma */
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(m66592_usb_peripheral_resources),
+       .resource       = m66592_usb_peripheral_resources,
+};
+
+static struct platform_device *x3proto_devices[] __initdata = {
+       &heartbeat_device,
+       &smc91x_device,
+       &r8a66597_usb_host_device,
+       &m66592_usb_peripheral_device,
+};
+
+static int __init x3proto_devices_setup(void)
+{
+       r8a66597_usb_host_resources[1].start =
+               r8a66597_usb_host_resources[1].end = ilsel_enable(ILSEL_USBH_I);
+
+       m66592_usb_peripheral_resources[1].start =
+               m66592_usb_peripheral_resources[1].end = ilsel_enable(ILSEL_USBP_I);
+
+       smc91x_resources[1].start =
+               smc91x_resources[1].end = ilsel_enable(ILSEL_LAN);
+
+       return platform_add_devices(x3proto_devices,
+                                   ARRAY_SIZE(x3proto_devices));
+}
+device_initcall(x3proto_devices_setup);
+
+static void __init x3proto_init_irq(void)
+{
+       plat_irq_setup_pins(IRQ_MODE_IRL3210);
+
+       /* Set ICR0.LVLMODE */
+       ctrl_outl(ctrl_inl(0xfe410000) | (1 << 21), 0xfe410000);
+}
+
+static struct sh_machine_vector mv_x3proto __initmv = {
+       .mv_name                = "x3proto",
+       .mv_init_irq            = x3proto_init_irq,
+};
index b557273e0cbe490c753e7e60f125a5b4f22c1a07..1308e618e044d1a5aaa996ac934e26cb15201163 100644 (file)
@@ -26,22 +26,24 @@ static inline void delay(void)
 static inline volatile __u16 *
 port2adr(unsigned int port)
 {
-       if (port >= 0x2000)
+       if (port >= 0x2000 && port < 0x2020)
                return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x300 || port < 0x310)
+       else if (port >= 0x300 && port < 0x310)
                return (volatile __u16 *) (PA_SMSC + (port - 0x300));
+
+       return (volatile __u16 *)port;
 }
 
 unsigned char se7206_inb(unsigned long port)
 {
-       return (*port2adr(port))&0xff; 
+       return (*port2adr(port)) & 0xff;
 }
 
 unsigned char se7206_inb_p(unsigned long port)
 {
        unsigned long v;
 
-       v = (*port2adr(port))&0xff; 
+       v = (*port2adr(port)) & 0xff;
        delay();
        return v;
 }
@@ -51,12 +53,6 @@ unsigned short se7206_inw(unsigned long port)
        return *port2adr(port);;
 }
 
-unsigned int se7206_inl(unsigned long port)
-{
-       maybebadio(port);
-       return 0;
-}
-
 void se7206_outb(unsigned char value, unsigned long port)
 {
        *(port2adr(port)) = value;
@@ -73,11 +69,6 @@ void se7206_outw(unsigned short value, unsigned long port)
        *port2adr(port) = value;
 }
 
-void se7206_outl(unsigned int value, unsigned long port)
-{
-       maybebadio(port);
-}
-
 void se7206_insb(unsigned long port, void *addr, unsigned long count)
 {
        volatile __u16 *p = port2adr(port);
@@ -95,11 +86,6 @@ void se7206_insw(unsigned long port, void *addr, unsigned long count)
                *ap++ = *p;
 }
 
-void se7206_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
 void se7206_outsb(unsigned long port, const void *addr, unsigned long count)
 {
        volatile __u16 *p = port2adr(port);
@@ -116,8 +102,3 @@ void se7206_outsw(unsigned long port, const void *addr, unsigned long count)
        while (count--)
                *p = *ap++;
 }
-
-void se7206_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index a074b62505ef1db0acce7eae1d4dd62961e30cb7..5b3ee089d91de3acc943cc3ef142dac056072b60 100644 (file)
@@ -6,14 +6,13 @@
  * Copyright (C) 2007  Paul Mundt
  *
  * Hitachi 7206 SolutionEngine Support.
- *
  */
-
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <asm/se7206.h>
 #include <asm/io.h>
 #include <asm/machvec.h>
+#include <asm/heartbeat.h>
 
 static struct resource smc91x_resources[] = {
        [0] = {
@@ -37,10 +36,16 @@ static struct platform_device smc91x_device = {
 
 static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
 
+static struct heartbeat_data heartbeat_data = {
+       .bit_pos        = heartbeat_bit_pos,
+       .nr_bits        = ARRAY_SIZE(heartbeat_bit_pos),
+       .regsize        = 32,
+};
+
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = PA_LED,
-               .end    = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+               .end    = PA_LED,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -49,7 +54,7 @@ static struct platform_device heartbeat_device = {
        .name           = "heartbeat",
        .id             = -1,
        .dev    = {
-               .platform_data  = heartbeat_bit_pos,
+               .platform_data  = &heartbeat_data,
        },
        .num_resources  = ARRAY_SIZE(heartbeat_resources),
        .resource       = heartbeat_resources,
@@ -75,24 +80,18 @@ static struct sh_machine_vector mv_se __initmv = {
        .mv_nr_irqs             = 256,
        .mv_inb                 = se7206_inb,
        .mv_inw                 = se7206_inw,
-       .mv_inl                 = se7206_inl,
        .mv_outb                = se7206_outb,
        .mv_outw                = se7206_outw,
-       .mv_outl                = se7206_outl,
 
        .mv_inb_p               = se7206_inb_p,
        .mv_inw_p               = se7206_inw,
-       .mv_inl_p               = se7206_inl,
        .mv_outb_p              = se7206_outb_p,
        .mv_outw_p              = se7206_outw,
-       .mv_outl_p              = se7206_outl,
 
        .mv_insb                = se7206_insb,
        .mv_insw                = se7206_insw,
-       .mv_insl                = se7206_insl,
        .mv_outsb               = se7206_outsb,
        .mv_outsw               = se7206_outsw,
-       .mv_outsl               = se7206_outsl,
 
        .mv_init_irq            = init_se7206_IRQ,
 };
index 360153ecc55b53dd3249d2cea9be96e39d9b2f99..763f6deba814cdc748314ca116e2492c35646bdf 100644 (file)
@@ -99,8 +99,11 @@ shmse_irq_demux(int irq)
  *
  * We configure IRQ5 as a cascade IRQ.
  */
-static struct irqaction irq5 = { no_action, 0, CPU_MASK_NONE, "IRQ5-cascade",
-                               NULL, NULL};
+static struct irqaction irq5 = {
+       .handler = no_action,
+       .mask = CPU_MASK_NONE,
+       .name = "IRQ5-cascade",
+};
 
 static struct ipr_data se7343_irq5_ipr_map[] = {
        { IRQ5_IRQ, IRQ5_IPR_ADDR+2, IRQ5_IPR_POS, IRQ5_PRIORITY },
index 8fec155e2ff7f86816c8e90264906381fc766f6b..c9431b3a051b48694fd24771e8b662a103c24f10 100644 (file)
@@ -33,7 +33,7 @@ static struct platform_device smc91x_device = {
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = PA_LED,
-               .end    = PA_LED + 8 - 1,
+               .end    = PA_LED,
                .flags  = IORESOURCE_MEM,
        },
 };
index 2962da148f3ff8a5cb89cfc8717b68f712df7d14..d07a3368f5462d4253ac1d4b6ca6c5ce6cfbab6d 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/se.h>
 #include <asm/io.h>
 #include <asm/smc37c93x.h>
+#include <asm/heartbeat.h>
 
 void init_se_IRQ(void);
 
@@ -90,10 +91,15 @@ static struct platform_device cf_ide_device  = {
 
 static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
 
+static struct heartbeat_data heartbeat_data = {
+       .bit_pos        = heartbeat_bit_pos,
+       .nr_bits        = ARRAY_SIZE(heartbeat_bit_pos),
+};
+
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = PA_LED,
-               .end    = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+               .end    = PA_LED,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -102,7 +108,7 @@ static struct platform_device heartbeat_device = {
        .name           = "heartbeat",
        .id             = -1,
        .dev    = {
-               .platform_data  = heartbeat_bit_pos,
+               .platform_data  = &heartbeat_data,
        },
        .num_resources  = ARRAY_SIZE(heartbeat_resources),
        .resource       = heartbeat_resources,
index 495fc7e2b60f4e9663c5ffe9c1d1e275b2356840..03b63457e1780c9fb3c77ec5bf185eaa4abfd7f0 100644 (file)
 #include <asm/io.h>
 
 /* Heartbeat */
-static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
-
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = PA_LED,
-               .end    = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+               .end    = PA_LED,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -31,9 +29,6 @@ static struct resource heartbeat_resources[] = {
 static struct platform_device heartbeat_device = {
        .name           = "heartbeat",
        .id             = -1,
-       .dev    = {
-               .platform_data  = heartbeat_bit_pos,
-       },
        .num_resources  = ARRAY_SIZE(heartbeat_resources),
        .resource       = heartbeat_resources,
 };
@@ -109,7 +104,7 @@ static void __init se7722_setup(char **cmdline_p)
        ctrl_outl(0x00051001, MSTPCR0);
        ctrl_outl(0x00000000, MSTPCR1);
        /* KEYSC, VOU, BEU, CEU, VEU, VPU, LCDC */
-       ctrl_outl(0xffffbfC0, MSTPCR2); 
+       ctrl_outl(0xffffbfC0, MSTPCR2);
 
        ctrl_outw(0x0000, PORT_PECR);   /* PORT E 1 = IRQ5 ,E 0 = BS */
        ctrl_outw(0x1000, PORT_PJCR);   /* PORT J 1 = IRQ1,J 0 =IRQ0 */
index 7873d07e40c1cbac50e9a62d453c8dc87447e20c..deefbfd92591a388e5ab3c22d247337bcfa30bbf 100644 (file)
 #include <asm/machvec.h>
 #include <asm/se7751.h>
 #include <asm/io.h>
+#include <asm/heartbeat.h>
 
 static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
 
+static struct heartbeat_data heartbeat_data = {
+       .bit_pos        = heartbeat_bit_pos,
+       .nr_bits        = ARRAY_SIZE(heartbeat_bit_pos),
+};
+
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = PA_LED,
-               .end    = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+               .end    = PA_LED,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -28,14 +34,13 @@ static struct platform_device heartbeat_device = {
        .name           = "heartbeat",
        .id             = -1,
        .dev    = {
-               .platform_data  = heartbeat_bit_pos,
+               .platform_data  = &heartbeat_data,
        },
        .num_resources  = ARRAY_SIZE(heartbeat_resources),
        .resource       = heartbeat_resources,
 };
 
 static struct platform_device *se7751_devices[] __initdata = {
-       &smc91x_device,
        &heartbeat_device,
 };
 
index 87491474600907cec7ced860f9ac5a7f284ca68c..6bd70da6bb47e1d991f6a6e464dff9308df344df 100644 (file)
 #include <asm/io.h>
 #include <asm/se7780.h>
 
-static struct intc2_data intc2_irq_table[] = {
-       { 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT1 */
-       { 4,  0, 30, 0, 30, 3 }, /* daughter board EXTINT2 */
-       { 6,  0, 29, 0, 29, 3 }, /* daughter board EXTINT3 */
-       { 8,  0, 28, 0, 28, 3 }, /* SMC 91C111 (LAN) */
-       { 10, 0, 27, 0, 27, 3 }, /* daughter board EXTINT4 */
-       { 4,  0, 30, 0, 30, 3 }, /* daughter board EXTINT5 */
-       { 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT6 */
-       { 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT7 */
-       { 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT8 */
-       { 0 , 0, 24, 0, 24, 3 }, /* SM501 */
-};
-
-static struct intc2_desc intc2_irq_desc __read_mostly = {
-       .prio_base      = 0, /* N/A */
-       .msk_base       = 0xffd00044,
-       .mskclr_base    = 0xffd00064,
-
-       .intc2_data     = intc2_irq_table,
-       .nr_irqs        = ARRAY_SIZE(intc2_irq_table),
-
-       .chip = {
-               .name   = "INTC2-se7780",
-       },
-};
-
 /*
  * Initialize IRQ setting
  */
@@ -68,5 +42,5 @@ void __init init_se7780_IRQ(void)
        /* FPGA + 0x0A */
        ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3);
 
-       register_intc2_controller(&intc2_irq_desc);
+       plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-7 */
 }
index 723f2fd4d55bfabf57c22cc11befc71f2c949b78..76e53b26a808d4a8dc976acd87d7e6711c41951d 100644 (file)
 #include <asm/io.h>
 
 /* Heartbeat */
-static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
-
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = PA_LED,
-               .end    = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+               .end    = PA_LED,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -29,9 +27,6 @@ static struct resource heartbeat_resources[] = {
 static struct platform_device heartbeat_device = {
        .name           = "heartbeat",
        .id             = -1,
-       .dev    = {
-               .platform_data  = heartbeat_bit_pos,
-       },
        .num_resources  = ARRAY_SIZE(heartbeat_resources),
        .resource       = heartbeat_resources,
 };
index 9c031a8c0a1cafb54e55baef8456fe8c60ee4a74..934ac4f1c48f2039ccf47e113150eaa7ce7fba39 100644 (file)
 #include <asm/sh03/sh03.h>
 #include <asm/addrspace.h>
 
-static struct ipr_data ipr_irq_table[] = {
-       { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY },
-       { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY },
-       { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY },
-       { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY },
-};
-
-static unsigned long ipr_offsets[] = {
-       INTC_IPRD,
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh03",
-       },
-};
-
 static void __init init_sh03_IRQ(void)
 {
-       ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
-       register_ipr_controller(&ipr_irq_desc);
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
 }
 
 extern void *cf_io_base;
@@ -68,7 +44,7 @@ static void __init sh03_setup(char **cmdline_p)
 static struct resource heartbeat_resources[] = {
        [0] = {
                .start  = 0xa0800000,
-               .end    = 0xa0800000 + 8 - 1,
+               .end    = 0xa0800000,
                .flags  = IORESOURCE_MEM,
        },
 };
index dfd124509f42c2cd25f8898f164d0df8f86e2453..16e5dae8ecfb409702deff42cab3149d04c75898 100644 (file)
 
 #define PFC_PHCR       0xa400010eUL
 #define INTC_ICR1      0xa4000010UL
-#define INTC_IPRC      0xa4000016UL
-
-static struct ipr_data ipr_irq_table[] = {
-       { 32, 0, 0, 0 },
-       { 33, 0, 4, 0 },
-       { 34, 0, 8, 8 },
-       { 35, 0, 12, 0 },
-};
-
-static unsigned long ipr_offsets[] = {
-       INTC_IPRC,
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-shmin",
-       },
-};
 
 static void __init init_shmin_irq(void)
 {
        ctrl_outw(0x2a00, PFC_PHCR);    // IRQ0-3=IRQ
        ctrl_outw(0x0aaa, INTC_ICR1);   // IRQ0-3=IRQ-mode,Low-active.
-       register_ipr_controller(&ipr_irq_desc);
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
 }
 
 static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size)
index 84271d85a8dd42d158dea593c3c5525c78af4517..2b594f6000022c9904ea9df0a9ab1aabb8483328 100644 (file)
@@ -68,37 +68,11 @@ module_init(eraseconfig_init);
  * IRL3 = crypto
  */
 
-static struct ipr_data ipr_irq_table[] = {
-       { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY },
-       { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY },
-       { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY },
-       { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY },
-};
-
-static unsigned long ipr_offsets[] = {
-       INTC_IPRD,
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-snapgear",
-       },
-};
-
 static void __init init_snapgear_IRQ(void)
 {
-       /* enable individual interrupt mode for externals */
-       ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
-
        printk("Setup SnapGear IRQ/IPR ...\n");
-
-       register_ipr_controller(&ipr_irq_desc);
+       /* enable individual interrupt mode for externals */
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
 }
 
 /*
index 606d25a4b870098698fc409c0cb81ddc68ebea4d..5de3b2ad71af86fc4d2e6dbe956e373ca0d05a22 100644 (file)
 #include <asm/titan.h>
 #include <asm/io.h>
 
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR idx, shift, prio */
-       { TITAN_IRQ_WAN,   3, 12, 8 },  /* eth0 (WAN) */
-       { TITAN_IRQ_LAN,   3,  8, 8 },  /* eth1 (LAN) */
-       { TITAN_IRQ_MPCIA, 3,  4, 8 },  /* mPCI A (top) */
-       { TITAN_IRQ_USB,   3,  0, 8 },  /* mPCI B (bottom), USB */
-};
-
-static unsigned long ipr_offsets[] = { /* stolen from setup-sh7750.c */
-       0xffd00004UL,   /* 0: IPRA */
-       0xffd00008UL,   /* 1: IPRB */
-       0xffd0000cUL,   /* 2: IPRC */
-       0xffd00010UL,   /* 3: IPRD */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-titan",
-       },
-};
 static void __init init_titan_irq(void)
 {
        /* enable individual interrupt mode for externals */
-       ipr_irq_enable_irlm();
-       /* register ipr irqs */
-       register_ipr_controller(&ipr_irq_desc);
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
 }
 
 static struct sh_machine_vector mv_titan __initmv = {
index 2e516e9a6ede5bf7be19ce8a8cf9dd449458eb1e..7892361eedc8fb6a414a566b093d49c6a7f8c7cf 100644 (file)
@@ -1,18 +1,5 @@
 menu "Companion Chips"
 
-config VOYAGERGX
-       bool "VoyagerGX chip support"
-       depends on SH_RTS7751R2D
-       help
-         Selecting this option will support Silicon Motion, Inc. SM501.
-         Designed to complement needs for the embedded industry, it
-         provides video and 2D capability. To reduce system cost a
-         wide variety of include I/O is supported, including analog RGB
-         and digital LCD Panel interface, 8-bit parallel interface, USB,
-         UART, IrDA, Zoom Video, AC97 or I2S, SSP, PWM, and I2C. There
-         are additional GPIO bits that can be used to interface to
-         external as well.
-
 config HD6446X_SERIES
        bool
 
index 97f6512aa1b7c565a1aa3e2bd04ba777b84ac5b6..f1a4a0763c5991dac9e150007c37bbc8c3a1789f 100644 (file)
@@ -14,6 +14,9 @@
 #include <asm/irq.h>
 #include <asm/hd64461.h>
 
+/* This belongs in cpu specific */
+#define INTC_ICR1 0xA4140010UL
+
 static void disable_hd64461_irq(unsigned int irq)
 {
        unsigned short nimr;
@@ -121,10 +124,15 @@ int hd64461_irq_demux(int irq)
                        }
                }
        }
-       return __irq_demux(irq);
+       return irq;
 }
 
-static struct irqaction irq0 = { hd64461_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "HD64461", NULL, NULL };
+static struct irqaction irq0 = {
+       .handler = hd64461_interrupt,
+       .flags = IRQF_DISABLED,
+       .mask = CPU_MASK_NONE,
+       .name = "HD64461",
+};
 
 int __init setup_hd64461(void)
 {
@@ -143,6 +151,7 @@ int __init setup_hd64461(void)
 #endif
        outw(0xffff, HD64461_NIMR);
 
+       /*  IRQ 80 -> 95 belongs to HD64461  */
        for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) {
                irq_desc[i].chip = &hd64461_irq_type;
        }
index d126e1f30dee60b99f0f959bd8755516c3618086..5cef0db4018b78eb00cbc5c285c18a66bc687be0 100644 (file)
@@ -147,7 +147,12 @@ int hd64465_irq_demux(int irq)
        return irq;
 }
 
-static struct irqaction irq0  = { hd64465_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "HD64465", NULL, NULL};
+static struct irqaction irq0  = {
+       .handler = hd64465_interrupt,
+       .flags = IRQF_DISABLED,
+       .mask = CPU_MASK_NONE,
+       .name = "HD64465",
+};
 
 
 static int __init setup_hd64465(void)
index d70e5c8461b56e4b60c72c43ae9204c4b0637a8e..ade3038768411b32bf0c8af8a5fc081b76eaf489 100644 (file)
 #include <asm/voyagergx.h>
 #include <asm/rts7751r2d.h>
 
-static void disable_voyagergx_irq(unsigned int irq)
-{
-       unsigned long val;
-       unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
-
-       pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
-       val = readl((void __iomem *)VOYAGER_INT_MASK);
-       val &= ~mask;
-       writel(val, (void __iomem *)VOYAGER_INT_MASK);
-}
-
-static void enable_voyagergx_irq(unsigned int irq)
-{
-       unsigned long val;
-       unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
-
-       pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
-       val = readl((void __iomem *)VOYAGER_INT_MASK);
-       val |= mask;
-       writel(val, (void __iomem *)VOYAGER_INT_MASK);
-}
-
-static void mask_and_ack_voyagergx(unsigned int irq)
-{
-       disable_voyagergx_irq(irq);
-}
-
-static void end_voyagergx_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_voyagergx_irq(irq);
-}
-
-static unsigned int startup_voyagergx_irq(unsigned int irq)
-{
-       enable_voyagergx_irq(irq);
-       return 0;
-}
-
-static void shutdown_voyagergx_irq(unsigned int irq)
-{
-       disable_voyagergx_irq(irq);
-}
-
-static struct hw_interrupt_type voyagergx_irq_type = {
-       .typename       = "VOYAGERGX-IRQ",
-       .startup        = startup_voyagergx_irq,
-       .shutdown       = shutdown_voyagergx_irq,
-       .enable         = enable_voyagergx_irq,
-       .disable        = disable_voyagergx_irq,
-       .ack            = mask_and_ack_voyagergx,
-       .end            = end_voyagergx_irq,
+enum {
+       UNUSED = 0,
+
+       /* voyager specific interrupt sources */
+       UP, G54, G53, G52, G51, G50, G49, G48,
+       I2C, PW, DMA, PCI, I2S, AC, US,
+       U1, U0, CV, MC, S1, S0,
+       UH, TWOD, ZD, PV, CI,
 };
 
-static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
-{
-       printk(KERN_INFO
-              "VoyagerGX: spurious interrupt, status: 0x%x\n",
-                       (unsigned int)readl((void __iomem *)INT_STATUS));
-       return IRQ_HANDLED;
-}
-
-static struct {
-       int (*func)(int, void *);
-       void *dev;
-} voyagergx_demux[VOYAGER_IRQ_NUM];
+static struct intc_vect vectors[] __initdata = {
+       INTC_IRQ(UP, IRQ_SM501_UP), INTC_IRQ(G54, IRQ_SM501_G54),
+       INTC_IRQ(G53, IRQ_SM501_G53), INTC_IRQ(G52, IRQ_SM501_G52),
+       INTC_IRQ(G51, IRQ_SM501_G51), INTC_IRQ(G50, IRQ_SM501_G50),
+       INTC_IRQ(G49, IRQ_SM501_G49), INTC_IRQ(G48, IRQ_SM501_G48),
+       INTC_IRQ(I2C, IRQ_SM501_I2C), INTC_IRQ(PW, IRQ_SM501_PW),
+       INTC_IRQ(DMA, IRQ_SM501_DMA), INTC_IRQ(PCI, IRQ_SM501_PCI),
+       INTC_IRQ(I2S, IRQ_SM501_I2S), INTC_IRQ(AC, IRQ_SM501_AC),
+       INTC_IRQ(US, IRQ_SM501_US), INTC_IRQ(U1, IRQ_SM501_U1),
+       INTC_IRQ(U0, IRQ_SM501_U0), INTC_IRQ(CV, IRQ_SM501_CV),
+       INTC_IRQ(MC, IRQ_SM501_MC), INTC_IRQ(S1, IRQ_SM501_S1),
+       INTC_IRQ(S0, IRQ_SM501_S0), INTC_IRQ(UH, IRQ_SM501_UH),
+       INTC_IRQ(TWOD, IRQ_SM501_2D), INTC_IRQ(ZD, IRQ_SM501_ZD),
+       INTC_IRQ(PV, IRQ_SM501_PV), INTC_IRQ(CI, IRQ_SM501_CI),
+};
 
-void voyagergx_register_irq_demux(int irq,
-               int (*demux)(int irq, void *dev), void *dev)
-{
-       voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux;
-       voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev;
-}
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { VOYAGER_INT_MASK, 0, 32, /* "Interrupt Mask", MMIO_base + 0x30 */
+         { UP, G54, G53, G52, G51, G50, G49, G48,
+           I2C, PW, 0, DMA, PCI, I2S, AC, US,
+           0, 0, U1, U0, CV, MC, S1, S0,
+           0, UH, 0, 0, TWOD, ZD, PV, CI } },
+};
 
-void voyagergx_unregister_irq_demux(int irq)
-{
-       voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
-}
+static DECLARE_INTC_DESC(intc_desc, "voyagergx", vectors,
+                        NULL, NULL, mask_registers, NULL, NULL);
+
+static unsigned int voyagergx_stat2irq[32] = {
+       IRQ_SM501_CI, IRQ_SM501_PV, IRQ_SM501_ZD, IRQ_SM501_2D,
+       0, 0, IRQ_SM501_UH, 0,
+       IRQ_SM501_S0, IRQ_SM501_S1, IRQ_SM501_MC, IRQ_SM501_CV,
+       IRQ_SM501_U0, IRQ_SM501_U1, 0, 0,
+       IRQ_SM501_US, IRQ_SM501_AC, IRQ_SM501_I2S, IRQ_SM501_PCI,
+       IRQ_SM501_DMA, 0, IRQ_SM501_PW, IRQ_SM501_I2C,
+       IRQ_SM501_G48, IRQ_SM501_G49, IRQ_SM501_G50, IRQ_SM501_G51,
+       IRQ_SM501_G52, IRQ_SM501_G53, IRQ_SM501_G54, IRQ_SM501_UP
+};
 
-int voyagergx_irq_demux(int irq)
+static void voyagergx_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
-
-       if (irq == IRQ_VOYAGER ) {
-               unsigned long i = 0, bit __attribute__ ((unused));
-               unsigned long val  = readl((void __iomem *)INT_STATUS);
-
-               if (val & (1 << 1))
-                       i = 1;
-               else if (val & (1 << 2))
-                       i = 2;
-               else if (val & (1 << 6))
-                       i = 6;
-               else if (val & (1 << 10))
-                       i = 10;
-               else if (val & (1 << 11))
-                       i = 11;
-               else if (val & (1 << 12))
-                       i = 12;
-               else if (val & (1 << 17))
-                       i = 17;
-               else
-                       printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
-               pr_debug("voyagergx_irq_demux %ld \n", i);
-               if (i < VOYAGER_IRQ_NUM) {
-                       irq = VOYAGER_IRQ_BASE + i;
-                       if (voyagergx_demux[i].func != 0)
-                               irq = voyagergx_demux[i].func(irq,
-                                               voyagergx_demux[i].dev);
+       unsigned long intv = ctrl_inl(INT_STATUS);
+       struct irq_desc *ext_desc;
+       unsigned int ext_irq;
+       unsigned int k = 0;
+
+       while (intv) {
+               ext_irq = voyagergx_stat2irq[k];
+               if (ext_irq && (intv & 1)) {
+                       ext_desc = irq_desc + ext_irq;
+                       handle_level_irq(ext_irq, ext_desc);
                }
+               intv >>= 1;
+               k++;
        }
-       return irq;
 }
 
-static struct irqaction irq0  = {
-       .name           = "voyagergx",
-       .handler        = voyagergx_interrupt,
-       .flags          = IRQF_DISABLED,
-       .mask           = CPU_MASK_NONE,
-};
-
 void __init setup_voyagergx_irq(void)
 {
-       int i, flag;
-
-       printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
-              VOYAGER_BASE,
+       printk(KERN_INFO "VoyagerGX on irq %d (mapped into %d to %d)\n",
               IRQ_VOYAGER,
               VOYAGER_IRQ_BASE,
               VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
 
-       for (i=0; i<VOYAGER_IRQ_NUM; i++) {
-               flag = 0;
-               switch (VOYAGER_IRQ_BASE + i) {
-               case VOYAGER_USBH_IRQ:
-               case VOYAGER_8051_IRQ:
-               case VOYAGER_UART0_IRQ:
-               case VOYAGER_UART1_IRQ:
-               case VOYAGER_AC97_IRQ:
-                       flag = 1;
-               }
-               if (flag == 1)
-                       irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
-       }
-
-       setup_irq(IRQ_VOYAGER, &irq0);
+       register_intc_controller(&intc_desc);
+       set_irq_chained_handler(IRQ_VOYAGER, voyagergx_irq_demux);
 }
index 3fdd270eecf71b9fa5680df7d0ef2b34a2524fd7..57728788b7531ad83b0d1193da4113ee4daa17fe 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc4
-# Sat Jul  7 03:47:45 2007
+# Linux kernel version: 2.6.23-rc7
+# Fri Sep 21 15:46:27 2007
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -18,30 +18,26 @@ CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
@@ -64,7 +60,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -74,24 +69,17 @@ CONFIG_SLAB=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -112,7 +100,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7619 is not set
 # CONFIG_CPU_SUBTYPE_SH7206 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
 # CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7706 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
@@ -120,6 +107,7 @@ CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7710 is not set
 # CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 CONFIG_CPU_SUBTYPE_SH7091=y
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -134,7 +122,6 @@ CONFIG_CPU_SUBTYPE_SH7091=y
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
 # CONFIG_CPU_SUBTYPE_SH7785 is not set
 # CONFIG_CPU_SUBTYPE_SHX3 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 
@@ -177,7 +164,9 @@ CONFIG_NR_QUICK=2
 # Cache configuration
 #
 # CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
 
 #
 # Processor features
@@ -185,12 +174,11 @@ CONFIG_NR_QUICK=2
 CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_CPU_BIG_ENDIAN is not set
 CONFIG_SH_FPU=y
-# CONFIG_SH_DSP is not set
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
+CONFIG_CPU_HAS_FPU=y
 
 #
 # Board support
@@ -270,6 +258,7 @@ CONFIG_CMDLINE="console=ttySC1,115200 panic=3"
 #
 # Bus options
 #
+CONFIG_MAPLE=y
 CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
 CONFIG_PCI_AUTO=y
@@ -368,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -380,27 +370,10 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
@@ -411,14 +384,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
 # CONFIG_IDE is not set
 
 #
@@ -426,12 +396,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
 # CONFIG_SCSI_NETLINK is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
 
 #
@@ -444,26 +411,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_STNIC is not set
@@ -472,10 +429,6 @@ CONFIG_MII=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
@@ -520,15 +473,7 @@ CONFIG_8139TOO=y
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -536,6 +481,7 @@ CONFIG_8139TOO=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -606,10 +552,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -631,10 +573,6 @@ CONFIG_HW_RANDOM=y
 # CONFIG_APPLICOM is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
@@ -644,11 +582,8 @@ CONFIG_DEVPORT=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 
 #
@@ -673,6 +608,7 @@ CONFIG_DEVPORT=y
 #
 # CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 # CONFIG_FB_DDC is not set
@@ -699,7 +635,6 @@ CONFIG_FB_DEFERRED_IO=y
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 CONFIG_FB_PVR2=y
-# CONFIG_FB_EPSON1355 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
@@ -725,6 +660,7 @@ CONFIG_FB_PVR2=y
 #
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
@@ -749,16 +685,10 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -773,32 +703,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 #
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
 # CONFIG_RTC_CLASS is not set
 
 #
@@ -814,6 +720,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # File systems
 #
@@ -890,7 +801,6 @@ CONFIG_RAMFS=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -935,10 +845,6 @@ CONFIG_ENABLE_MUST_CHECK=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -949,6 +855,7 @@ CONFIG_BITREVERSE=y
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
index b931d9b2d5798158206b4011efaa1dd11eeed9f9..756d38dc2f717655ee3458e7a00ada63ba231c7a 100644 (file)
@@ -1,37 +1,47 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct  3 11:10:06 2006
+# Linux kernel version: 2.6.23-rc4
+# Tue Sep 11 19:42:44 2007
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 # CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_UTS_NS is not set
-# CONFIG_IKCONFIG is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_USER_NS is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
@@ -44,27 +54,25 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 # CONFIG_MODULES is not set
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -82,55 +90,17 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 #
 # System type
 #
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-CONFIG_SH_HP6XX=y
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
 CONFIG_CPU_SH3=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-
-#
-# SH-3 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
 # CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7706 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 CONFIG_CPU_SUBTYPE_SH7709=y
 # CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 # CONFIG_CPU_SUBTYPE_SH7091 is not set
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -139,66 +109,78 @@ CONFIG_CPU_SUBTYPE_SH7709=y
 # CONFIG_CPU_SUBTYPE_SH7751R is not set
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
 # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
 
 #
 # Memory management options
 #
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_PAGE_OFFSET=0x80000000
-CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_START=0x0d000000
 CONFIG_MEMORY_SIZE=0x00400000
 CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
 # CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
 
 #
 # Cache configuration
 #
 # CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
 
 #
 # Processor features
 #
 CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
 # CONFIG_SH_FPU_EMU is not set
-# CONFIG_SH_DSP is not set
 CONFIG_SH_ADC=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_PINT_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
-# Timer support
+# Board support
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+CONFIG_SH_HP6XX=y
+
+#
+# Timer and clock configuration
 #
 CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
 CONFIG_SH_PCLK_FREQ=22110000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
 
 #
 # CPU Frequency scaling
@@ -208,6 +190,7 @@ CONFIG_SH_PCLK_FREQ=22110000
 #
 # DMA support
 #
+CONFIG_SH_DMA_API=y
 CONFIG_SH_DMA=y
 CONFIG_NR_ONCHIP_DMA_CHANNELS=4
 # CONFIG_NR_DMA_CHANNELS_BOOL is not set
@@ -222,15 +205,22 @@ CONFIG_HD64461_IRQ=36
 CONFIG_HD64461_IOBASE=0xb0000000
 CONFIG_HD64461_ENABLER=y
 
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
 #
 # Kernel features
 #
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 # CONFIG_KEXEC is not set
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
@@ -240,14 +230,13 @@ CONFIG_PREEMPT_NONE=y
 #
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_UBC_WAKEUP is not set
 # CONFIG_CMDLINE_BOOL is not set
 
 #
 # Bus options
 #
 CONFIG_ISA=y
-# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -265,15 +254,10 @@ CONFIG_PCMCIA_IOCTL=y
 # CONFIG_TCIC is not set
 CONFIG_PCMCIA_PROBE=y
 
-#
-# PCI Hotplug Support
-#
-
 #
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
@@ -282,8 +266,9 @@ CONFIG_BINFMT_ELF=y
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
-CONFIG_APM=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_APM_EMULATION=y
 
 #
 # Networking
@@ -301,109 +286,76 @@ CONFIG_APM=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 # CONFIG_PNP is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_RAM is not set
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECS=y
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
-# CONFIG_ATA is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+CONFIG_PATA_PLATFORM=y
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -411,19 +363,17 @@ CONFIG_IDE_GENERIC=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=y
 
 #
 # Userland interfaces
 #
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_TSDEV=y
 CONFIG_INPUT_TSDEV_SCREEN_X=240
 CONFIG_INPUT_TSDEV_SCREEN_Y=320
-# CONFIG_INPUT_EVDEV is not set
+CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
@@ -436,9 +386,12 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_HP6XX=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
@@ -447,6 +400,7 @@ CONFIG_TOUCHSCREEN_HP600=y
 # CONFIG_TOUCHSCREEN_PENMOUNT is not set
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
 # CONFIG_INPUT_MISC is not set
 
 #
@@ -476,29 +430,20 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_SH_SCI is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
+CONFIG_LEGACY_PTY_COUNT=64
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
-#
-# Ftape, the floppy tape device driver
-#
-
 #
 # PCMCIA character devices
 #
@@ -506,16 +451,8 @@ CONFIG_HW_RANDOM=y
 # CONFIG_CARDMAN_4000 is not set
 # CONFIG_CARDMAN_4040 is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -523,48 +460,55 @@ CONFIG_HW_RANDOM=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
 
 #
-# Dallas's 1-wire bus
-#
-
-#
-# Hardware Monitoring support
-#
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
+# CONFIG_DAB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_HP680=y
 
 #
-# Graphics support
+# Display device support
 #
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_BACKLIGHT is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_EPSON1355 is not set
+
+#
+# Frame buffer hardware drivers
+#
 # CONFIG_FB_S1D13XXX is not set
 CONFIG_FB_HIT=y
 # CONFIG_FB_VIRTUAL is not set
@@ -575,6 +519,7 @@ CONFIG_FB_HIT=y
 # CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -587,79 +532,49 @@ CONFIG_FONT_PEARL_8x8=y
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_10x18 is not set
-
-#
-# Logo configuration
-#
 # CONFIG_LOGO is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
 #
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE_DRIVER is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_SH_DAC_AUDIO=y
-CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
 
 #
-# LED drivers
-#
-
-#
-# LED Triggers
+# RTC interfaces
 #
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
 
 #
-# InfiniBand support
+# SPI RTC drivers
 #
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# Platform RTC drivers
 #
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
 
 #
-# Real Time Clock
+# on-CPU RTC drivers
 #
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_DRV_SH=y
 
 #
 # DMA Engine support
@@ -674,6 +589,11 @@ CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # File systems
 #
@@ -681,10 +601,12 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -705,7 +627,7 @@ CONFIG_DNOTIFY=y
 # DOS/FAT/NT Filesystems
 #
 CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
+CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
@@ -755,7 +677,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_850=y
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -799,34 +721,73 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 #
 # Kernel hacking
 #
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_PRINTK_TIME is not set
 CONFIG_ENABLE_MUST_CHECK=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_UNWIND_INFO is not set
 # CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_KGDB is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/magicpanelr2_defconfig b/arch/sh/configs/magicpanelr2_defconfig
new file mode 100644 (file)
index 0000000..f8398a5
--- /dev/null
@@ -0,0 +1,925 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc2
+# Fri Aug 17 12:15:16 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+CONFIG_CPU_SUBTYPE_SH7720=y
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0C000000
+CONFIG_MEMORY_SIZE=0x03F00000
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+CONFIG_SH_ADC=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_DSP=y
+
+#
+# Board support
+#
+CONFIG_SH_MAGIC_PANEL_R2=y
+
+#
+# Magic Panel R2 options
+#
+CONFIG_SH_MAGIC_PANEL_R2_VERSION=3
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=24000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+CONFIG_SH_DMA_API=y
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=6
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x0000000
+CONFIG_MTD_PHYSMAP_LEN=0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
+# CONFIG_MTD_SOLUTIONENGINE is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
+CONFIG_SMC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_BIND34=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_DEBUG_KOBJECT=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0xa4430000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+CONFIG_SH_KGDB=y
+
+#
+# KGDB configuration options
+#
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+# CONFIG_KGDB_NMI is not set
+CONFIG_KGDB_SYSRQ=y
+
+#
+# Serial port setup
+#
+CONFIG_KGDB_DEFPORT=0
+CONFIG_KGDB_DEFBAUD=115200
+CONFIG_KGDB_DEFPARITY_N=y
+# CONFIG_KGDB_DEFPARITY_E is not set
+# CONFIG_KGDB_DEFPARITY_O is not set
+CONFIG_KGDB_DEFBITS_8=y
+# CONFIG_KGDB_DEFBITS_7 is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
similarity index 85%
rename from arch/sh/configs/rts7751r2d_defconfig
rename to arch/sh/configs/rts7751r2d1_defconfig
index b64f73b704d615f19cf0f4af204d9ef104f06e19..2dc754e5b733d30b67c2a7041a2572e04d921326 100644 (file)
@@ -1,46 +1,47 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc1
-# Thu Mar  1 16:42:40 2007
+# Linux kernel version: 2.6.23-rc2
+# Tue Aug 14 18:04:44 2007
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PCI=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
@@ -54,31 +55,29 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -96,61 +95,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 #
 # System type
 #
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-CONFIG_SH_RTS7751R2D=y
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_7206_SOLUTION_ENGINE is not set
-# CONFIG_SH_7619_SOLUTION_ENGINE is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
 CONFIG_CPU_SH4=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
 # CONFIG_CPU_SUBTYPE_SH7619 is not set
-
-#
-# SH-2A Processor Support
-#
 # CONFIG_CPU_SUBTYPE_SH7206 is not set
-
-#
-# SH-3 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
 # CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7706 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
 # CONFIG_CPU_SUBTYPE_SH7708 is not set
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 # CONFIG_CPU_SUBTYPE_SH7091 is not set
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -159,35 +113,30 @@ CONFIG_CPU_SH4=y
 CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
 # CONFIG_CPU_SUBTYPE_ST40STB1 is not set
 # CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
 # CONFIG_CPU_SUBTYPE_SH7785 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 
 #
 # Memory management options
 #
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_PAGE_OFFSET=0x80000000
 CONFIG_MEMORY_START=0x0c000000
 CONFIG_MEMORY_SIZE=0x04000000
 CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
@@ -197,17 +146,19 @@ CONFIG_FLATMEM_MANUAL=y
 # CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
 
 #
 # Cache configuration
 #
 # CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
 
 #
 # Processor features
@@ -215,7 +166,6 @@ CONFIG_ZONE_DMA_FLAG=0
 CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_CPU_BIG_ENDIAN is not set
 CONFIG_SH_FPU=y
-# CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
 CONFIG_CPU_HAS_INTC_IRQ=y
@@ -223,17 +173,31 @@ CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
 #
-# Timer support
+# Board support
 #
-CONFIG_SH_TMU=y
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+CONFIG_SH_RTS7751R2D=y
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_LBOX_RE2 is not set
 
 #
 # RTS7751R2D options
 #
-CONFIG_RTS7751R2D_REV11=y
+# CONFIG_RTS7751R2D_PLUS is not set
+CONFIG_RTS7751R2D_1=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
 CONFIG_SH_TIMER_IRQ=16
-# CONFIG_NO_IDLE_HZ is not set
 CONFIG_SH_PCLK_FREQ=60000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
 
 #
 # CPU Frequency scaling
@@ -244,19 +208,15 @@ CONFIG_SH_PCLK_FREQ=60000000
 # DMA support
 #
 # CONFIG_SH_DMA is not set
-# CONFIG_NR_ONCHIP_DMA_CHANNELS is not set
-# CONFIG_NR_DMA_CHANNELS_BOOL is not set
 
 #
 # Companion Chips
 #
-CONFIG_VOYAGERGX=y
-# CONFIG_HD6446X_SERIES is not set
-CONFIG_HEARTBEAT=y
 
 #
 # Additional SuperH Device Drivers
 #
+CONFIG_HEARTBEAT=y
 # CONFIG_PUSH_SWITCH is not set
 
 #
@@ -268,7 +228,7 @@ CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 # CONFIG_KEXEC is not set
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
@@ -289,15 +249,12 @@ CONFIG_PCI=y
 CONFIG_SH_PCIDMA_NONCOHERENT=y
 CONFIG_PCI_AUTO=y
 CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=y
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 # CONFIG_HOTPLUG_PCI_CPCI is not set
@@ -307,14 +264,8 @@ CONFIG_HOTPLUG_PCI=y
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
-#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
 #
 # Networking
 #
@@ -323,7 +274,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -360,20 +310,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -399,8 +337,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
 CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -413,31 +360,10 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=m
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
@@ -449,19 +375,13 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 # CONFIG_IDE is not set
 
 #
@@ -469,6 +389,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
@@ -490,6 +411,7 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -497,12 +419,8 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
@@ -512,7 +430,6 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
@@ -535,10 +452,6 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
 # CONFIG_SATA_AHCI is not set
@@ -561,6 +474,7 @@ CONFIG_ATA=y
 # CONFIG_PATA_AMD is not set
 # CONFIG_PATA_ARTOP is not set
 # CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
 # CONFIG_PATA_CMD64X is not set
 # CONFIG_PATA_CS5520 is not set
 # CONFIG_PATA_CS5530 is not set
@@ -593,10 +507,6 @@ CONFIG_ATA=y
 # CONFIG_PATA_VIA is not set
 # CONFIG_PATA_WINBOND is not set
 CONFIG_PATA_PLATFORM=y
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
 
 #
@@ -610,35 +520,18 @@ CONFIG_PATA_PLATFORM=y
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_STNIC is not set
@@ -647,10 +540,6 @@ CONFIG_MII=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
@@ -677,10 +566,7 @@ CONFIG_8139TOO=y
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
@@ -691,61 +577,26 @@ CONFIG_8139TOO=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-# CONFIG_NET_WIRELESS_RTNETLINK is not set
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_IPW2100 is not set
-# CONFIG_IPW2200 is not set
-CONFIG_HERMES=m
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_NORTEL_HERMES is not set
-# CONFIG_PCI_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Wan interfaces
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -756,15 +607,7 @@ CONFIG_NET_WIRELESS=y
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -772,6 +615,7 @@ CONFIG_NET_WIRELESS=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -788,6 +632,7 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -828,32 +673,15 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -861,21 +689,24 @@ CONFIG_HW_RANDOM=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -887,22 +718,31 @@ CONFIG_MFD_SM501=y
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 # CONFIG_FIRMWARE_EDID is not set
 # CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
 # CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_BACKLIGHT is not set
@@ -910,14 +750,13 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_TILEBLITTING is not set
 
 #
-# Frambuffer hardware drivers
+# Frambuffer hardware drivers
 #
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
-# CONFIG_FB_EPSON1355 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
@@ -932,7 +771,10 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
 CONFIG_FB_SM501=y
 # CONFIG_FB_VIRTUAL is not set
 
@@ -941,14 +783,11 @@ CONFIG_FB_SM501=y
 #
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
@@ -1048,35 +887,34 @@ CONFIG_SND_AC97_CODEC=m
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
 CONFIG_SND_YMFPCI=m
+CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y
 # CONFIG_SND_AC97_POWER_SAVE is not set
 
 #
-# SoC audio support
+# SUPERH devices
+#
+
+#
+# System on Chip audio support
 #
 # CONFIG_SND_SOC is not set
 
+#
+# SoC Audio support for SuperH
+#
+
 #
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=m
-# CONFIG_OBSOLETE_OSS is not set
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
 CONFIG_AC97_BUS=m
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1090,37 +928,9 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1134,17 +944,27 @@ CONFIG_RTC_INTF_SYSFS=y
 CONFIG_RTC_INTF_PROC=y
 CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
 
 #
-# RTC drivers
+# Platform RTC drivers
 #
 # CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
 # CONFIG_RTC_DRV_DS1742 is not set
 # CONFIG_RTC_DRV_M48T86 is not set
-CONFIG_RTC_DRV_SH=y
-# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_M48T59 is not set
 # CONFIG_RTC_DRV_V3020 is not set
 
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
 #
 # DMA Engine support
 #
@@ -1159,12 +979,9 @@ CONFIG_RTC_DRV_SH=y
 #
 
 #
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -1247,7 +1064,6 @@ CONFIG_RAMFS=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1321,7 +1137,6 @@ CONFIG_ENABLE_MUST_CHECK=y
 # CONFIG_DEBUG_FS is not set
 # CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_SH_STANDARD_BIOS is not set
 CONFIG_EARLY_SCIF_CONSOLE=y
@@ -1334,10 +1149,6 @@ CONFIG_EARLY_PRINTK=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1346,8 +1157,11 @@ CONFIG_EARLY_PRINTK=y
 CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/rts7751r2dplus_defconfig b/arch/sh/configs/rts7751r2dplus_defconfig
new file mode 100644 (file)
index 0000000..4ff5a75
--- /dev/null
@@ -0,0 +1,1167 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc2
+# Tue Aug 14 16:33:08 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PCI=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+CONFIG_CPU_SUBTYPE_SH7751R=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Board support
+#
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+CONFIG_SH_RTS7751R2D=y
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_LBOX_RE2 is not set
+
+#
+# RTS7751R2D options
+#
+CONFIG_RTS7751R2D_PLUS=y
+# CONFIG_RTS7751R2D_1 is not set
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=60000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=serial"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+CONFIG_PATA_PLATFORM=y
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=1
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_SM501=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+CONFIG_FB_SM501=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y
+# CONFIG_SND_AC97_POWER_SAVE is not set
+
+#
+# SUPERH devices
+#
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index f2f2a3c9c32db0456504ac8c8e10e64bf05c91bb..0d0cda908270edce4613a36573ceda66fdfcc6bf 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc4
-# Fri Jun 15 19:37:46 2007
+# Linux kernel version: 2.6.23-rc4
+# Thu Sep 13 16:40:16 2007
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -17,25 +17,22 @@ CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
@@ -60,23 +57,17 @@ CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 # CONFIG_VM_EVENT_COUNTERS is not set
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=1
-
-#
-# Loadable module support
-#
 # CONFIG_MODULES is not set
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -98,7 +89,6 @@ CONFIG_CPU_SH2=y
 CONFIG_CPU_SH2A=y
 # CONFIG_CPU_SUBTYPE_SH7619 is not set
 CONFIG_CPU_SUBTYPE_SH7206=y
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
 # CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7706 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
@@ -106,6 +96,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7710 is not set
 # CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 # CONFIG_CPU_SUBTYPE_SH7091 is not set
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -119,7 +110,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
 # CONFIG_CPU_SUBTYPE_SH7785 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 
@@ -136,15 +127,16 @@ CONFIG_ARCH_SPARSEMEM_DEFAULT=y
 CONFIG_MAX_ACTIVE_REGIONS=1
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
 # CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
 CONFIG_SPARSEMEM_STATIC=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
@@ -155,7 +147,9 @@ CONFIG_NR_QUICK=2
 # Cache configuration
 #
 # CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
 
 #
 # Processor features
@@ -163,8 +157,6 @@ CONFIG_NR_QUICK=2
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_CPU_BIG_ENDIAN=y
 # CONFIG_SH_FPU_EMU is not set
-# CONFIG_SH_DSP is not set
-CONFIG_CPU_HAS_IPR_IRQ=y
 
 #
 # Board support
@@ -185,12 +177,23 @@ CONFIG_SH_CLK_MD=6
 #
 # CPU Frequency scaling
 #
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_SH_CPU_FREQ is not set
 
 #
 # DMA support
 #
-# CONFIG_SH_DMA is not set
 
 #
 # Companion Chips
@@ -199,17 +202,17 @@ CONFIG_SH_CLK_MD=6
 #
 # Additional SuperH Device Drivers
 #
-# CONFIG_HEARTBEAT is not set
+CONFIG_HEARTBEAT=y
 # CONFIG_PUSH_SWITCH is not set
 
 #
 # Kernel features
 #
-CONFIG_HZ_100=y
+# CONFIG_HZ_100 is not set
 # CONFIG_HZ_250 is not set
 # CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
 CONFIG_PREEMPT_NONE=y
@@ -221,11 +224,13 @@ CONFIG_PREEMPT_NONE=y
 #
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC3,115200 earlyprintk=serial ignore_loglevel"
 
 #
 # Bus options
 #
+# CONFIG_CF_ENABLER is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
@@ -315,6 +320,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -325,11 +331,9 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
@@ -411,31 +415,16 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_IDE is not set
 
 #
@@ -443,27 +432,18 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
 # CONFIG_SCSI_NETLINK is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_STNIC is not set
@@ -483,15 +463,7 @@ CONFIG_NETDEV_10000=y
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -499,6 +471,7 @@ CONFIG_NETDEV_10000=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -546,19 +519,11 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_UNIX98_PTYS is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
@@ -567,11 +532,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 
 #
@@ -596,25 +558,21 @@ CONFIG_DAB=y
 #
 # CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
 # CONFIG_FB is not set
 
 #
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 # CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -625,31 +583,7 @@ CONFIG_HID=y
 #
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
 # CONFIG_RTC_CLASS is not set
 
 #
@@ -665,6 +599,11 @@ CONFIG_HID=y
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # File systems
 #
@@ -736,7 +675,6 @@ CONFIG_RAMFS=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -752,12 +690,12 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Distributed Lock Manager
 #
-# CONFIG_DLM is not set
 
 #
 # Profiling support
 #
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
 
 #
 # Kernel hacking
@@ -768,19 +706,41 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+CONFIG_SLUB_DEBUG_ON=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_FAULT_INJECTION is not set
 # CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0xfffe9800
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_4KSTACKS is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -791,6 +751,7 @@ CONFIG_BITREVERSE=y
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_HAS_IOMEM=y
index 219bad558b10f7223c6825abe4d656598af23174..a794c082709bf5a4e532bc5e87fd771fdf8b7a6b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc4
-# Wed Jun 20 14:09:27 2007
+# Linux kernel version: 2.6.23-rc7
+# Fri Sep 21 19:07:30 2007
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -13,32 +13,33 @@ CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_SYS_SUPPORTS_NUMA=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -63,34 +64,26 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
+# CONFIG_SLAB is not set
 # CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
+CONFIG_SLOB=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -113,7 +106,6 @@ CONFIG_CPU_SH4A=y
 CONFIG_CPU_SHX3=y
 # CONFIG_CPU_SUBTYPE_SH7619 is not set
 # CONFIG_CPU_SUBTYPE_SH7206 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
 # CONFIG_CPU_SUBTYPE_SH7705 is not set
 # CONFIG_CPU_SUBTYPE_SH7706 is not set
 # CONFIG_CPU_SUBTYPE_SH7707 is not set
@@ -121,6 +113,7 @@ CONFIG_CPU_SHX3=y
 # CONFIG_CPU_SUBTYPE_SH7709 is not set
 # CONFIG_CPU_SUBTYPE_SH7710 is not set
 # CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
 # CONFIG_CPU_SUBTYPE_SH7750 is not set
 # CONFIG_CPU_SUBTYPE_SH7091 is not set
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -135,7 +128,6 @@ CONFIG_CPU_SHX3=y
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
 # CONFIG_CPU_SUBTYPE_SH7785 is not set
 CONFIG_CPU_SUBTYPE_SHX3=y
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
 # CONFIG_CPU_SUBTYPE_SH7722 is not set
 
@@ -148,12 +140,15 @@ CONFIG_PAGE_OFFSET=0x80000000
 CONFIG_MEMORY_START=0x0c000000
 CONFIG_MEMORY_SIZE=0x04000000
 CONFIG_VSYSCALL=y
+# CONFIG_NUMA is not set
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_SPARSEMEM_DEFAULT=y
-CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_MAX_ACTIVE_REGIONS=6
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_MEMORY_PROBE=y
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
@@ -163,12 +158,14 @@ CONFIG_HUGETLB_PAGE_SIZE_64K=y
 # CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
 # CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
 CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
 # CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
 CONFIG_SPARSEMEM_STATIC=y
+CONFIG_MEMORY_HOTPLUG=y
+CONFIG_MEMORY_HOTPLUG_SPARSE=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
@@ -178,24 +175,25 @@ CONFIG_NR_QUICK=2
 # Cache configuration
 #
 # CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_CACHE_WRITEBACK is not set
+# CONFIG_CACHE_WRITETHROUGH is not set
+CONFIG_CACHE_OFF=y
 
 #
 # Processor features
 #
 CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_CPU_BIG_ENDIAN is not set
-# CONFIG_SH_FPU is not set
-# CONFIG_SH_FPU_EMU is not set
-CONFIG_SH_DSP=y
+CONFIG_SH_FPU=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_FPU=y
 
 #
 # Board support
 #
+CONFIG_SH_X3PROTO=y
 
 #
 # Timer and clock configuration
@@ -204,13 +202,25 @@ CONFIG_SH_TMU=y
 CONFIG_SH_TIMER_IRQ=16
 CONFIG_SH_PCLK_FREQ=50000000
 CONFIG_TICK_ONESHOT=y
-CONFIG_NO_HZ=y
+# CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
 
 #
 # CPU Frequency scaling
 #
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_SH_CPU_FREQ=y
 
 #
 # DMA support
@@ -237,6 +247,7 @@ CONFIG_HZ_250=y
 CONFIG_HZ=250
 CONFIG_KEXEC=y
 # CONFIG_CRASH_DUMP is not set
+# CONFIG_SMP is not set
 # CONFIG_PREEMPT_NONE is not set
 # CONFIG_PREEMPT_VOLUNTARY is not set
 CONFIG_PREEMPT=y
@@ -249,7 +260,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 # CONFIG_UBC_WAKEUP is not set
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC0,115200 ip=192.168.1.2:::255.255.255.0 root=/dev/nfs nfsroot=192.168.1.1:/exports/devel/rfs/mobiler noaliencache earlyprintk=bios ignore_loglevel"
+CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=bios ignore_loglevel"
 
 #
 # Bus options
@@ -265,12 +276,106 @@ CONFIG_CMDLINE="console=ttySC0,115200 ip=192.168.1.2:::255.255.255.0 root=/dev/n
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
 
 #
 # Networking
 #
-# CONFIG_NET is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -285,37 +390,21 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_IDE is not set
 
 #
@@ -323,6 +412,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
@@ -351,73 +441,54 @@ CONFIG_SCSI_WAIT_SCAN=m
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
 CONFIG_PATA_PLATFORM=y
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+CONFIG_SMC91X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
 # CONFIG_PHONE is not set
 
 #
 # Input device support
 #
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_INPUT is not set
 
 #
 # Hardware I/O ports
 #
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO is not set
 # CONFIG_GAMEPORT is not set
 
 #
@@ -442,19 +513,18 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# IPMI
+# Watchdog Device Drivers
 #
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SH_WDT is not set
+# CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
@@ -463,11 +533,8 @@ CONFIG_HW_RANDOM=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 
 #
@@ -479,6 +546,7 @@ CONFIG_HW_RANDOM=y
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
 # CONFIG_DAB is not set
 
 #
@@ -491,24 +559,18 @@ CONFIG_HW_RANDOM=y
 #
 # CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 # CONFIG_FB is not set
 
 #
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
-# CONFIG_HID is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 # CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -517,68 +579,32 @@ CONFIG_HW_RANDOM=y
 #
 # USB Gadget Support
 #
-# CONFIG_USB_GADGET is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+CONFIG_USB_GADGET_M66592=y
+CONFIG_USB_M66592=y
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
-
-#
-# RTC interfaces
-#
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-# CONFIG_RTC_DRV_TEST is not set
-
-#
-# I2C RTC drivers
-#
-
-#
-# SPI RTC drivers
-#
-
-#
-# Platform RTC drivers
-#
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-# CONFIG_RTC_DRV_V3020 is not set
-
-#
-# on-CPU RTC drivers
-#
-CONFIG_RTC_DRV_SH=y
+# CONFIG_RTC_CLASS is not set
 
 #
 # DMA Engine support
@@ -593,6 +619,11 @@ CONFIG_RTC_DRV_SH=y
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+CONFIG_UIO=m
+
 #
 # File systems
 #
@@ -612,6 +643,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -666,6 +698,17 @@ CONFIG_RAMFS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
 
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
 #
 # Partition Types
 #
@@ -677,6 +720,11 @@ CONFIG_MSDOS_PARTITION=y
 #
 # CONFIG_NLS is not set
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Profiling support
 #
@@ -687,31 +735,28 @@ CONFIG_PROFILING=y
 # Kernel hacking
 #
 CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
-CONFIG_DEBUG_SLAB=y
-CONFIG_DEBUG_SLAB_LEAK=y
 CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_LOCK_ALLOC=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
 # CONFIG_PROVE_LOCKING is not set
-CONFIG_LOCKDEP=y
-CONFIG_DEBUG_LOCKDEP=y
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
@@ -735,10 +780,6 @@ CONFIG_DEBUG_STACK_USAGE=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -749,6 +790,7 @@ CONFIG_BITREVERSE=y
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
index ee711431e50451805a8580d3a5368fcaf268279d..4e711a0c3dae1925302ea3a368df888a0e946748 100644 (file)
@@ -12,6 +12,7 @@ config SH_DMA
 config NR_ONCHIP_DMA_CHANNELS
        int
        depends on SH_DMA
+       default "6" if CPU_SUBTYPE_SH7720
        default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
        default "12" if CPU_SUBTYPE_SH7780
        default "4"
index 06ed0609a95d6c58ecf476d483f0ef6ea617e83e..958bac1c585a9fe91fed90ee7cfdb8605cd3e857 100644 (file)
@@ -24,13 +24,19 @@ static int dmte_irq_map[] = {
        DMTE1_IRQ,
        DMTE2_IRQ,
        DMTE3_IRQ,
-#if defined(CONFIG_CPU_SUBTYPE_SH7751R) ||     \
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)  ||     \
+    defined(CONFIG_CPU_SUBTYPE_SH7751R) ||     \
     defined(CONFIG_CPU_SUBTYPE_SH7760)  ||     \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)  ||     \
     defined(CONFIG_CPU_SUBTYPE_SH7780)
        DMTE4_IRQ,
        DMTE5_IRQ,
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7751R) ||     \
+    defined(CONFIG_CPU_SUBTYPE_SH7760)  ||     \
+    defined(CONFIG_CPU_SUBTYPE_SH7780)
        DMTE6_IRQ,
-       DMTE7_IRQ,    
+       DMTE7_IRQ,
 #endif
 };
 
@@ -196,7 +202,8 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan)
        return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan);
 }
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780)
 #define dmaor_read_reg()       ctrl_inw(DMAOR)
 #define dmaor_write_reg(data)  ctrl_outw(data, DMAOR)
 #else
index 10c1828c9ff51b5fbd3cf5d104153ef77fb40afd..b76a14f12ce24dfba85431fc551cb292bee7f5ed 100644 (file)
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/io.h>
+#include <asm/heartbeat.h>
 
 #define DRV_NAME "heartbeat"
-#define DRV_VERSION "0.1.0"
+#define DRV_VERSION "0.1.1"
 
-struct heartbeat_data {
-       void __iomem *base;
-       unsigned char bit_pos[8];
-       struct timer_list timer;
-};
+static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+static inline void heartbeat_toggle_bit(struct heartbeat_data *hd,
+                                       unsigned bit, unsigned int inverted)
+{
+       unsigned int new;
+
+       new = (1 << hd->bit_pos[bit]);
+       if (inverted)
+               new = ~new;
+
+       switch (hd->regsize) {
+       case 32:
+               iowrite32(new, hd->base);
+               break;
+       case 16:
+               iowrite16(new, hd->base);
+               break;
+       default:
+               iowrite8(new, hd->base);
+               break;
+       }
+}
 
 static void heartbeat_timer(unsigned long data)
 {
        struct heartbeat_data *hd = (struct heartbeat_data *)data;
        static unsigned bit = 0, up = 1;
 
-       ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base);
+       heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED);
+
        bit += up;
-       if ((bit == 0) || (bit == ARRAY_SIZE(hd->bit_pos)-1))
+       if ((bit == 0) || (bit == (hd->nr_bits)-1))
                up = -up;
 
        mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
@@ -64,21 +84,31 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       hd = kmalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
-       if (unlikely(!hd))
-               return -ENOMEM;
-
        if (pdev->dev.platform_data) {
-               memcpy(hd->bit_pos, pdev->dev.platform_data,
-                      ARRAY_SIZE(hd->bit_pos));
+               hd = pdev->dev.platform_data;
        } else {
-               int i;
+               hd = kzalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
+               if (unlikely(!hd))
+                       return -ENOMEM;
+       }
+
+       hd->base = ioremap_nocache(res->start, res->end - res->start + 1);
+       if (!unlikely(hd->base)) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+
+               if (!pdev->dev.platform_data)
+                       kfree(hd);
+
+               return -ENXIO;
+       }
 
-               for (i = 0; i < ARRAY_SIZE(hd->bit_pos); i++)
-                       hd->bit_pos[i] = i;
+       if (!hd->nr_bits) {
+               hd->bit_pos = default_bit_pos;
+               hd->nr_bits = ARRAY_SIZE(default_bit_pos);
        }
 
-       hd->base = (void __iomem *)(unsigned long)res->start;
+       if (!hd->regsize)
+               hd->regsize = 8;        /* default access size */
 
        setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
        platform_set_drvdata(pdev, hd);
@@ -91,10 +121,12 @@ static int heartbeat_drv_remove(struct platform_device *pdev)
        struct heartbeat_data *hd = platform_get_drvdata(pdev);
 
        del_timer_sync(&hd->timer);
+       iounmap(hd->base);
 
        platform_set_drvdata(pdev, NULL);
 
-       kfree(hd);
+       if (!pdev->dev.platform_data)
+               kfree(hd);
 
        return 0;
 }
index 4a518d948049b41ff150a82303b3b69ee58fa691..ec8430c8d2d1b16050bf4851a143a70e2691f0c9 100644 (file)
 #include "pci-sh4.h"
 
 static u8 rts7751r2d_irq_tab[] __initdata = {
-       IRQ_PCISLOT1,
-       IRQ_PCISLOT2,
-       IRQ_PCMCIA,
-       IRQ_PCIETH,
+       IRQ_PCI_INTA,
+       IRQ_PCI_INTB,
+       IRQ_PCI_INTC,
+       IRQ_PCI_INTD,
 };
 
 int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
index 5508e45d48389f0a8f34dcf4e44761a2068cd00f..e516087fb435f1ea16b66e00e9795ab9c6cf7e30 100644 (file)
@@ -79,19 +79,6 @@ static int __init sh7780_pci_init(void)
                ctrl_outl(0xAAAA0000, INTC_ICR1);
                /* INTPRI: priority=3(all) */
                ctrl_outl(0x33333333, INTC_INTPRI);
-       } else {
-               /* INTC SH-4 Mode */
-               ctrl_outl(0x00200000, INTC_ICR0);
-               /* enable PCIINTA - PCIINTD */
-               ctrl_outl(0x00078000, INTC_INT2MSKCR);
-               /* disable IRL4-7 Interrupt */
-               ctrl_outl(0x40000000, INTC_INTMSK1);
-               /* disable IRL4-7 Interrupt */
-               ctrl_outl(0x0000fffe, INTC_INTMSK2);
-               /* enable IRL0-3 Interrupt */
-               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
-               /* enable IRL0-3 Interrupt */
-               ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
        }
 
        if ((ret = sh4_pci_check_direct()) != 0)
index 92807ffa8e2036a9d4ac66dbcf5d3e86276ea309..b5f1e23ed57cc3ef68a7bc6f05560f133fd0c8a2 100644 (file)
@@ -83,6 +83,8 @@ static void propagate_rate(struct clk *clk)
                        continue;
                if (likely(clkp->ops && clkp->ops->recalc))
                        clkp->ops->recalc(clkp);
+               if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
+                       propagate_rate(clkp);
        }
 }
 
index 9172e97dc26ab0d9f6e5155f464a33fa5c227be9..c217c4bf0085addff0e4746789d4ac3d67d4e2eb 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/cache.h>
 #include <asm/io.h>
 #include <asm/ubc.h>
+#include <asm/smp.h>
 
 /*
  * Generic wrapper for command line arguments to disable on-chip
@@ -143,12 +144,15 @@ static void __init cache_init(void)
                flags &= ~CCR_CACHE_EMODE;
 #endif
 
-#ifdef CONFIG_SH_WRITETHROUGH
-       /* Turn on Write-through caching */
+#if defined(CONFIG_CACHE_WRITETHROUGH)
+       /* Write-through */
        flags |= CCR_CACHE_WT;
-#else
-       /* .. or default to Write-back */
+#elif defined(CONFIG_CACHE_WRITEBACK)
+       /* Write-back */
        flags |= CCR_CACHE_CB;
+#else
+       /* Off */
+       flags &= ~CCR_CACHE_ENABLE;
 #endif
 
        ctrl_outl(flags, CCR);
@@ -213,8 +217,11 @@ static void __init dsp_init(void)
  * Each processor family is still responsible for doing its own probing
  * and cache configuration in detect_cpu_and_cache_system().
  */
-asmlinkage void __init sh_cpu_init(void)
+
+asmlinkage void __cpuinit sh_cpu_init(void)
 {
+       current_thread_info()->cpu = hard_smp_processor_id();
+
        /* First, probe the CPU */
        detect_cpu_and_cache_system();
 
@@ -224,9 +231,10 @@ asmlinkage void __init sh_cpu_init(void)
        /* Init the cache */
        cache_init();
 
-       shm_align_mask = max_t(unsigned long,
-                              current_cpu_data.dcache.way_size - 1,
-                              PAGE_SIZE - 1);
+       if (raw_smp_processor_id() == 0)
+               shm_align_mask = max_t(unsigned long,
+                                      current_cpu_data.dcache.way_size - 1,
+                                      PAGE_SIZE - 1);
 
        /* Disable the FPU */
        if (fpu_disabled) {
@@ -265,6 +273,7 @@ asmlinkage void __init sh_cpu_init(void)
         * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB.  So ..
         * we wake it up and hope that all is well.
         */
-       ubc_wakeup();
+       if (raw_smp_processor_id() == 0)
+               ubc_wakeup();
        speculative_execution_init();
 }
index 60bfc05cf3549b42d214645c33adc6b1e29b2c80..8da8e178f09cbe62c73bc43e1d1f5c839d4e9de0 100644 (file)
@@ -1,9 +1,7 @@
 #
 # Makefile for the Linux/SuperH CPU-specifc IRQ handlers.
 #
-obj-y  += imask.o
+obj-y  += imask.o intc.o
 
 obj-$(CONFIG_CPU_HAS_IPR_IRQ)          += ipr.o
 obj-$(CONFIG_CPU_HAS_MASKREG_IRQ)      += maskreg.o
-obj-$(CONFIG_CPU_HAS_INTC_IRQ)         += intc.o
-obj-$(CONFIG_CPU_HAS_INTC2_IRQ)                += intc2.o
index 9345a7130e9e5f9baddeb384671cb39271679213..6ac018c15e0355f1856e79c048d764739829e157 100644 (file)
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
+#include <linux/bootmem.h>
+
+#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
+       ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
+        ((addr_e) << 16) | ((addr_d << 24)))
+
+#define _INTC_SHIFT(h) (h & 0x1f)
+#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
+#define _INTC_FN(h) ((h >> 9) & 0xf)
+#define _INTC_MODE(h) ((h >> 13) & 0x7)
+#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
+#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
+
+struct intc_handle_int {
+       unsigned int irq;
+       unsigned long handle;
+};
+
+struct intc_desc_int {
+       unsigned long *reg;
+#ifdef CONFIG_SMP
+       unsigned long *smp;
+#endif
+       unsigned int nr_reg;
+       struct intc_handle_int *prio;
+       unsigned int nr_prio;
+       struct intc_handle_int *sense;
+       unsigned int nr_sense;
+       struct irq_chip chip;
+};
 
-#define _INTC_MK(fn, idx, bit, value) \
-       ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit))
-#define _INTC_FN(h) (h >> 24)
-#define _INTC_VALUE(h) ((h >> 16) & 0xff)
-#define _INTC_IDX(h) ((h >> 8) & 0xff)
-#define _INTC_BIT(h) (h & 0xff)
+#ifdef CONFIG_SMP
+#define IS_SMP(x) x.smp
+#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
+#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
+#else
+#define IS_SMP(x) 0
+#define INTC_REG(d, x, c) (d->reg[(x)])
+#define SMP_NR(d, x) 1
+#endif
 
-#define _INTC_PTR(desc, member, data) \
-       (desc->member + _INTC_IDX(data))
+static unsigned int intc_prio_level[NR_IRQS]; /* for now */
 
-static inline struct intc_desc *get_intc_desc(unsigned int irq)
+static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
 {
        struct irq_chip *chip = get_irq_chip(irq);
-       return (void *)((char *)chip - offsetof(struct intc_desc, chip));
+       return (void *)((char *)chip - offsetof(struct intc_desc_int, chip));
 }
 
 static inline unsigned int set_field(unsigned int value,
                                     unsigned int field_value,
-                                    unsigned int width,
-                                    unsigned int shift)
+                                    unsigned int handle)
 {
+       unsigned int width = _INTC_WIDTH(handle);
+       unsigned int shift = _INTC_SHIFT(handle);
+
        value &= ~(((1 << width) - 1) << shift);
        value |= field_value << shift;
        return value;
 }
 
-static inline unsigned int set_prio_field(struct intc_desc *desc,
-                                         unsigned int value,
-                                         unsigned int priority,
-                                         unsigned int data)
+static void write_8(unsigned long addr, unsigned long h, unsigned long data)
 {
-       unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width;
-
-       return set_field(value, priority, width, _INTC_BIT(data));
+       ctrl_outb(set_field(0, data, h), addr);
 }
 
-static void disable_prio_16(struct intc_desc *desc, unsigned int data)
+static void write_16(unsigned long addr, unsigned long h, unsigned long data)
 {
-       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
-
-       ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr);
+       ctrl_outw(set_field(0, data, h), addr);
 }
 
-static void enable_prio_16(struct intc_desc *desc, unsigned int data)
+static void write_32(unsigned long addr, unsigned long h, unsigned long data)
 {
-       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
-       unsigned int prio = _INTC_VALUE(data);
-
-       ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr);
+       ctrl_outl(set_field(0, data, h), addr);
 }
 
-static void disable_prio_32(struct intc_desc *desc, unsigned int data)
+static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
 {
-       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
-
-       ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr);
+       ctrl_outb(set_field(ctrl_inb(addr), data, h), addr);
 }
 
-static void enable_prio_32(struct intc_desc *desc, unsigned int data)
+static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
 {
-       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
-       unsigned int prio = _INTC_VALUE(data);
-
-       ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
+       ctrl_outw(set_field(ctrl_inw(addr), data, h), addr);
 }
 
-static void disable_mask_8(struct intc_desc *desc, unsigned int data)
+static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
 {
-       ctrl_outb(1 << _INTC_BIT(data),
-                 _INTC_PTR(desc, mask_regs, data)->set_reg);
+       ctrl_outl(set_field(ctrl_inl(addr), data, h), addr);
 }
 
-static void enable_mask_8(struct intc_desc *desc, unsigned int data)
+enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
+
+static void (*intc_reg_fns[])(unsigned long addr,
+                             unsigned long h,
+                             unsigned long data) = {
+       [REG_FN_WRITE_BASE + 0] = write_8,
+       [REG_FN_WRITE_BASE + 1] = write_16,
+       [REG_FN_WRITE_BASE + 3] = write_32,
+       [REG_FN_MODIFY_BASE + 0] = modify_8,
+       [REG_FN_MODIFY_BASE + 1] = modify_16,
+       [REG_FN_MODIFY_BASE + 3] = modify_32,
+};
+
+enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
+       MODE_MASK_REG,       /* Bit(s) set -> interrupt disabled */
+       MODE_DUAL_REG,       /* Two registers, set bit to enable / disable */
+       MODE_PRIO_REG,       /* Priority value written to enable interrupt */
+       MODE_PCLR_REG,       /* Above plus all bits set to disable interrupt */
+};
+
+static void intc_mode_field(unsigned long addr,
+                           unsigned long handle,
+                           void (*fn)(unsigned long,
+                                      unsigned long,
+                                      unsigned long),
+                           unsigned int irq)
 {
-       ctrl_outb(1 << _INTC_BIT(data),
-                 _INTC_PTR(desc, mask_regs, data)->clr_reg);
+       fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
 }
 
-static void disable_mask_32(struct intc_desc *desc, unsigned int data)
+static void intc_mode_zero(unsigned long addr,
+                          unsigned long handle,
+                          void (*fn)(unsigned long,
+                                      unsigned long,
+                                      unsigned long),
+                          unsigned int irq)
 {
-       ctrl_outl(1 << _INTC_BIT(data),
-                 _INTC_PTR(desc, mask_regs, data)->set_reg);
+       fn(addr, handle, 0);
 }
 
-static void enable_mask_32(struct intc_desc *desc, unsigned int data)
+static void intc_mode_prio(unsigned long addr,
+                          unsigned long handle,
+                          void (*fn)(unsigned long,
+                                      unsigned long,
+                                      unsigned long),
+                          unsigned int irq)
 {
-       ctrl_outl(1 << _INTC_BIT(data),
-                 _INTC_PTR(desc, mask_regs, data)->clr_reg);
+       fn(addr, handle, intc_prio_level[irq]);
 }
 
-enum { REG_FN_ERROR=0,
-       REG_FN_MASK_8, REG_FN_MASK_32,
-       REG_FN_PRIO_16, REG_FN_PRIO_32 };
-
-static struct {
-       void (*enable)(struct intc_desc *, unsigned int);
-       void (*disable)(struct intc_desc *, unsigned int);
-} intc_reg_fns[] = {
-       [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 },
-       [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 },
-       [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 },
-       [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
+static void (*intc_enable_fns[])(unsigned long addr,
+                                unsigned long handle,
+                                void (*fn)(unsigned long,
+                                           unsigned long,
+                                           unsigned long),
+                                unsigned int irq) = {
+       [MODE_ENABLE_REG] = intc_mode_field,
+       [MODE_MASK_REG] = intc_mode_zero,
+       [MODE_DUAL_REG] = intc_mode_field,
+       [MODE_PRIO_REG] = intc_mode_prio,
+       [MODE_PCLR_REG] = intc_mode_prio,
 };
 
-static void intc_enable(unsigned int irq)
+static void (*intc_disable_fns[])(unsigned long addr,
+                                 unsigned long handle,
+                                 void (*fn)(unsigned long,
+                                            unsigned long,
+                                            unsigned long),
+                                 unsigned int irq) = {
+       [MODE_ENABLE_REG] = intc_mode_zero,
+       [MODE_MASK_REG] = intc_mode_field,
+       [MODE_DUAL_REG] = intc_mode_field,
+       [MODE_PRIO_REG] = intc_mode_zero,
+       [MODE_PCLR_REG] = intc_mode_field,
+};
+
+static inline void _intc_enable(unsigned int irq, unsigned long handle)
 {
-       struct intc_desc *desc = get_intc_desc(irq);
-       unsigned int data = (unsigned int) get_irq_chip_data(irq);
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned long addr;
+       unsigned int cpu;
+
+       for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+               addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+               intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
+                                                   [_INTC_FN(handle)], irq);
+       }
+}
 
-       intc_reg_fns[_INTC_FN(data)].enable(desc, data);
+static void intc_enable(unsigned int irq)
+{
+       _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
 }
 
 static void intc_disable(unsigned int irq)
 {
-       struct intc_desc *desc = get_intc_desc(irq);
-       unsigned int data = (unsigned int) get_irq_chip_data(irq);
-
-       intc_reg_fns[_INTC_FN(data)].disable(desc, data);
+       struct intc_desc_int *d = get_intc_desc(irq);
+       unsigned long handle = (unsigned long) get_irq_chip_data(irq);
+       unsigned long addr;
+       unsigned int cpu;
+
+       for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+               addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+               intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
+                                                    [_INTC_FN(handle)], irq);
+       }
 }
 
-static void set_sense_16(struct intc_desc *desc, unsigned int data)
+static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
+                                            unsigned int nr_hp,
+                                            unsigned int irq)
 {
-       unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
-       unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
-       unsigned int bit = _INTC_BIT(data);
-       unsigned int value = _INTC_VALUE(data);
+       int i;
+
+       /* this doesn't scale well, but...
+        *
+        * this function should only be used for cerain uncommon
+        * operations such as intc_set_priority() and intc_set_sense()
+        * and in those rare cases performance doesn't matter that much.
+        * keeping the memory footprint low is more important.
+        *
+        * one rather simple way to speed this up and still keep the
+        * memory footprint down is to make sure the array is sorted
+        * and then perform a bisect to lookup the irq.
+        */
 
-       ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr);
+       for (i = 0; i < nr_hp; i++) {
+               if ((hp + i)->irq != irq)
+                       continue;
+
+               return hp + i;
+       }
+
+       return NULL;
 }
 
-static void set_sense_32(struct intc_desc *desc, unsigned int data)
+int intc_set_priority(unsigned int irq, unsigned int prio)
 {
-       unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
-       unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
-       unsigned int bit = _INTC_BIT(data);
-       unsigned int value = _INTC_VALUE(data);
+       struct intc_desc_int *d = get_intc_desc(irq);
+       struct intc_handle_int *ihp;
+
+       if (!intc_prio_level[irq] || prio <= 1)
+               return -EINVAL;
+
+       ihp = intc_find_irq(d->prio, d->nr_prio, irq);
+       if (ihp) {
+               if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
+                       return -EINVAL;
 
-       ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr);
+               intc_prio_level[irq] = prio;
+
+               /*
+                * only set secondary masking method directly
+                * primary masking method is using intc_prio_level[irq]
+                * priority level will be set during next enable()
+                */
+
+               if (_INTC_FN(ihp->handle) != REG_FN_ERR)
+                       _intc_enable(irq, ihp->handle);
+       }
+       return 0;
 }
 
 #define VALID(x) (x | 0x80)
@@ -172,79 +285,38 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
 
 static int intc_set_sense(unsigned int irq, unsigned int type)
 {
-       struct intc_desc *desc = get_intc_desc(irq);
+       struct intc_desc_int *d = get_intc_desc(irq);
        unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
-       unsigned int i, j, data, bit;
-       intc_enum enum_id = 0;
-
-       for (i = 0; i < desc->nr_vectors; i++) {
-               struct intc_vect *vect = desc->vectors + i;
-
-               if (evt2irq(vect->vect) != irq)
-                       continue;
+       struct intc_handle_int *ihp;
+       unsigned long addr;
 
-               enum_id = vect->enum_id;
-               break;
-       }
-
-       if (!enum_id || !value)
+       if (!value)
                return -EINVAL;
 
-       value ^= VALID(0);
-
-       for (i = 0; i < desc->nr_sense_regs; i++) {
-               struct intc_sense_reg *sr = desc->sense_regs + i;
-
-               for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
-                       if (sr->enum_ids[j] != enum_id)
-                               continue;
-
-                       bit = sr->reg_width - ((j + 1) * sr->field_width);
-                       data = _INTC_MK(0, i, bit, value);
-
-                       switch(sr->reg_width) {
-                       case 16:
-                               set_sense_16(desc, data);
-                               break;
-                       case 32:
-                               set_sense_32(desc, data);
-                               break;
-                       }
-
-                       return 0;
-               }
+       ihp = intc_find_irq(d->sense, d->nr_sense, irq);
+       if (ihp) {
+               addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
+               intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
        }
-
-       return -EINVAL;
+       return 0;
 }
 
-static unsigned int __init intc_find_mask_handler(unsigned int width)
+static unsigned int __init intc_get_reg(struct intc_desc_int *d,
+                                unsigned long address)
 {
-       switch (width) {
-       case 8:
-               return REG_FN_MASK_8;
-       case 32:
-               return REG_FN_MASK_32;
-       }
+       unsigned int k;
 
-       BUG();
-       return REG_FN_ERROR;
-}
-
-static unsigned int __init intc_find_prio_handler(unsigned int width)
-{
-       switch (width) {
-       case 16:
-               return REG_FN_PRIO_16;
-       case 32:
-               return REG_FN_PRIO_32;
+       for (k = 0; k < d->nr_reg; k++) {
+               if (d->reg[k] == address)
+                       return k;
        }
 
        BUG();
-       return REG_FN_ERROR;
+       return 0;
 }
 
-static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
+static intc_enum __init intc_grp_id(struct intc_desc *desc,
+                                   intc_enum enum_id)
 {
        struct intc_group *g = desc->groups;
        unsigned int i, j;
@@ -289,10 +361,12 @@ static unsigned int __init intc_prio_value(struct intc_desc *desc,
 }
 
 static unsigned int __init intc_mask_data(struct intc_desc *desc,
+                                         struct intc_desc_int *d,
                                          intc_enum enum_id, int do_grps)
 {
        struct intc_mask_reg *mr = desc->mask_regs;
-       unsigned int i, j, fn;
+       unsigned int i, j, fn, mode;
+       unsigned long reg_e, reg_d;
 
        for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
                mr = desc->mask_regs + i;
@@ -301,25 +375,46 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc,
                        if (mr->enum_ids[j] != enum_id)
                                continue;
 
-                       fn = intc_find_mask_handler(mr->reg_width);
-                       if (fn == REG_FN_ERROR)
-                               return 0;
+                       if (mr->set_reg && mr->clr_reg) {
+                               fn = REG_FN_WRITE_BASE;
+                               mode = MODE_DUAL_REG;
+                               reg_e = mr->clr_reg;
+                               reg_d = mr->set_reg;
+                       } else {
+                               fn = REG_FN_MODIFY_BASE;
+                               if (mr->set_reg) {
+                                       mode = MODE_ENABLE_REG;
+                                       reg_e = mr->set_reg;
+                                       reg_d = mr->set_reg;
+                               } else {
+                                       mode = MODE_MASK_REG;
+                                       reg_e = mr->clr_reg;
+                                       reg_d = mr->clr_reg;
+                               }
+                       }
 
-                       return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0);
+                       fn += (mr->reg_width >> 3) - 1;
+                       return _INTC_MK(fn, mode,
+                                       intc_get_reg(d, reg_e),
+                                       intc_get_reg(d, reg_d),
+                                       1,
+                                       (mr->reg_width - 1) - j);
                }
        }
 
        if (do_grps)
-               return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0);
+               return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
 
        return 0;
 }
 
 static unsigned int __init intc_prio_data(struct intc_desc *desc,
+                                         struct intc_desc_int *d,
                                          intc_enum enum_id, int do_grps)
 {
        struct intc_prio_reg *pr = desc->prio_regs;
-       unsigned int i, j, fn, bit, prio;
+       unsigned int i, j, fn, mode, bit;
+       unsigned long reg_e, reg_d;
 
        for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
                pr = desc->prio_regs + i;
@@ -328,28 +423,72 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
                        if (pr->enum_ids[j] != enum_id)
                                continue;
 
-                       fn = intc_find_prio_handler(pr->reg_width);
-                       if (fn == REG_FN_ERROR)
-                               return 0;
+                       if (pr->set_reg && pr->clr_reg) {
+                               fn = REG_FN_WRITE_BASE;
+                               mode = MODE_PCLR_REG;
+                               reg_e = pr->set_reg;
+                               reg_d = pr->clr_reg;
+                       } else {
+                               fn = REG_FN_MODIFY_BASE;
+                               mode = MODE_PRIO_REG;
+                               if (!pr->set_reg)
+                                       BUG();
+                               reg_e = pr->set_reg;
+                               reg_d = pr->set_reg;
+                       }
 
-                       prio = intc_prio_value(desc, enum_id, 1);
+                       fn += (pr->reg_width >> 3) - 1;
                        bit = pr->reg_width - ((j + 1) * pr->field_width);
 
                        BUG_ON(bit < 0);
 
-                       return _INTC_MK(fn, i, bit, prio);
+                       return _INTC_MK(fn, mode,
+                                       intc_get_reg(d, reg_e),
+                                       intc_get_reg(d, reg_d),
+                                       pr->field_width, bit);
                }
        }
 
        if (do_grps)
-               return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0);
+               return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
 
        return 0;
 }
 
-static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
+static unsigned int __init intc_sense_data(struct intc_desc *desc,
+                                          struct intc_desc_int *d,
+                                          intc_enum enum_id)
+{
+       struct intc_sense_reg *sr = desc->sense_regs;
+       unsigned int i, j, fn, bit;
+
+       for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) {
+               sr = desc->sense_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+                       if (sr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = REG_FN_MODIFY_BASE;
+                       fn += (sr->reg_width >> 3) - 1;
+                       bit = sr->reg_width - ((j + 1) * sr->field_width);
+
+                       BUG_ON(bit < 0);
+
+                       return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
+                                       0, sr->field_width, bit);
+               }
+       }
+
+       return 0;
+}
+
+static void __init intc_register_irq(struct intc_desc *desc,
+                                    struct intc_desc_int *d,
+                                    intc_enum enum_id,
                                     unsigned int irq)
 {
+       struct intc_handle_int *hp;
        unsigned int data[2], primary;
 
        /* Prefer single interrupt source bitmap over other combinations:
@@ -359,15 +498,15 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
         * 4. priority, multiple interrupt sources (groups)
         */
 
-       data[0] = intc_mask_data(desc, enum_id, 0);
-       data[1] = intc_prio_data(desc, enum_id, 0);
+       data[0] = intc_mask_data(desc, d, enum_id, 0);
+       data[1] = intc_prio_data(desc, d, enum_id, 0);
 
        primary = 0;
        if (!data[0] && data[1])
                primary = 1;
 
-       data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1);
-       data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1);
+       data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
+       data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
 
        if (!data[primary])
                primary ^= 1;
@@ -375,31 +514,118 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
        BUG_ON(!data[primary]); /* must have primary masking method */
 
        disable_irq_nosync(irq);
-       set_irq_chip_and_handler_name(irq, &desc->chip,
+       set_irq_chip_and_handler_name(irq, &d->chip,
                                      handle_level_irq, "level");
        set_irq_chip_data(irq, (void *)data[primary]);
 
+       /* record the desired priority level */
+       intc_prio_level[irq] = intc_prio_value(desc, enum_id, 1);
+
        /* enable secondary masking method if present */
        if (data[!primary])
-               intc_reg_fns[_INTC_FN(data[!primary])].enable(desc,
-                                                             data[!primary]);
+               _intc_enable(irq, data[!primary]);
+
+       /* add irq to d->prio list if priority is available */
+       if (data[1]) {
+               hp = d->prio + d->nr_prio;
+               hp->irq = irq;
+               hp->handle = data[1];
+
+               if (primary) {
+                       /*
+                        * only secondary priority should access registers, so
+                        * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
+                        */
+
+                       hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
+                       hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
+               }
+               d->nr_prio++;
+       }
+
+       /* add irq to d->sense list if sense is available */
+       data[0] = intc_sense_data(desc, d, enum_id);
+       if (data[0]) {
+               (d->sense + d->nr_sense)->irq = irq;
+               (d->sense + d->nr_sense)->handle = data[0];
+               d->nr_sense++;
+       }
 
        /* irq should be disabled by default */
-       desc->chip.mask(irq);
+       d->chip.mask(irq);
 }
 
+static unsigned int __init save_reg(struct intc_desc_int *d,
+                                   unsigned int cnt,
+                                   unsigned long value,
+                                   unsigned int smp)
+{
+       if (value) {
+               d->reg[cnt] = value;
+#ifdef CONFIG_SMP
+               d->smp[cnt] = smp;
+#endif
+               return 1;
+       }
+
+       return 0;
+}
+
+
 void __init register_intc_controller(struct intc_desc *desc)
 {
-       unsigned int i;
+       unsigned int i, k, smp;
+       struct intc_desc_int *d;
+
+       d = alloc_bootmem(sizeof(*d));
+
+       d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
+       d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
+       d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
+
+       d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
+#ifdef CONFIG_SMP
+       d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
+#endif
+       k = 0;
+
+       if (desc->mask_regs) {
+               for (i = 0; i < desc->nr_mask_regs; i++) {
+                       smp = IS_SMP(desc->mask_regs[i]);
+                       k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
+                       k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
+               }
+       }
+
+       if (desc->prio_regs) {
+               d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio));
+
+               for (i = 0; i < desc->nr_prio_regs; i++) {
+                       smp = IS_SMP(desc->prio_regs[i]);
+                       k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
+                       k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
+               }
+       }
+
+       if (desc->sense_regs) {
+               d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense));
+
+               for (i = 0; i < desc->nr_sense_regs; i++) {
+                       k += save_reg(d, k, desc->sense_regs[i].reg, 0);
+               }
+       }
+
+       BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
 
-       desc->chip.mask = intc_disable;
-       desc->chip.unmask = intc_enable;
-       desc->chip.mask_ack = intc_disable;
-       desc->chip.set_type = intc_set_sense;
+       d->chip.name = desc->name;
+       d->chip.mask = intc_disable;
+       d->chip.unmask = intc_enable;
+       d->chip.mask_ack = intc_disable;
+       d->chip.set_type = intc_set_sense;
 
        for (i = 0; i < desc->nr_vectors; i++) {
                struct intc_vect *vect = desc->vectors + i;
 
-               intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect));
+               intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
        }
 }
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
deleted file mode 100644 (file)
index cc52213..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Interrupt handling for INTC2-based IRQ.
- *
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * These are the "new Hitachi style" interrupts, as present on the
- * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
- */
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <asm/smp.h>
-
-static inline struct intc2_desc *get_intc2_desc(unsigned int irq)
-{
-       struct irq_chip *chip = get_irq_chip(irq);
-       return (void *)((char *)chip - offsetof(struct intc2_desc, chip));
-}
-
-static void disable_intc2_irq(unsigned int irq)
-{
-       struct intc2_data *p = get_irq_chip_data(irq);
-       struct intc2_desc *d = get_intc2_desc(irq);
-
-       ctrl_outl(1 << p->msk_shift, d->msk_base + p->msk_offset +
-                                    (hard_smp_processor_id() * 4));
-}
-
-static void enable_intc2_irq(unsigned int irq)
-{
-       struct intc2_data *p = get_irq_chip_data(irq);
-       struct intc2_desc *d = get_intc2_desc(irq);
-
-       ctrl_outl(1 << p->msk_shift, d->mskclr_base + p->msk_offset +
-                                    (hard_smp_processor_id() * 4));
-}
-
-/*
- * Setup an INTC2 style interrupt.
- * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
- * allowing the use of the numbers straight out of the datasheet.
- * For example:
- *    PIO1 which is INTPRI00[19,16] and INTMSK00[13]
- * would be:               ^     ^             ^  ^
- *                         |     |             |  |
- *     { 84,              0,   16,            0, 13 },
- *
- * in the intc2_data table.
- */
-void register_intc2_controller(struct intc2_desc *desc)
-{
-       int i;
-
-       desc->chip.mask = disable_intc2_irq;
-       desc->chip.unmask = enable_intc2_irq;
-       desc->chip.mask_ack = disable_intc2_irq;
-
-       for (i = 0; i < desc->nr_irqs; i++) {
-               unsigned long ipr, flags;
-               struct intc2_data *p = desc->intc2_data + i;
-
-               disable_irq_nosync(p->irq);
-
-               if (desc->prio_base) {
-                       /* Set the priority level */
-                       local_irq_save(flags);
-
-                       ipr = ctrl_inl(desc->prio_base + p->ipr_offset);
-                       ipr &= ~(0xf << p->ipr_shift);
-                       ipr |= p->priority << p->ipr_shift;
-                       ctrl_outl(ipr, desc->prio_base + p->ipr_offset);
-
-                       local_irq_restore(flags);
-               }
-
-               set_irq_chip_and_handler_name(p->irq, &desc->chip,
-                                             handle_level_irq, "level");
-               set_irq_chip_data(p->irq, p);
-
-               disable_intc2_irq(p->irq);
-       }
-}
index abbf17427e52c87bb2e25e70828e722997ef64a2..5916d9096b9935c7bbf946c4a3a6efdb9b015e9b 100644 (file)
  * for more details.
  */
 #include <linux/init.h>
-#include <linux/smp.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 
 int __init detect_cpu_and_cache_system(void)
 {
 #if defined(CONFIG_CPU_SUBTYPE_SH7619)
-       current_cpu_data.type                   = CPU_SH7619;
-       current_cpu_data.dcache.ways            = 4;
-       current_cpu_data.dcache.way_incr        = (1<<12);
-       current_cpu_data.dcache.sets            = 256;
-       current_cpu_data.dcache.entry_shift     = 4;
-       current_cpu_data.dcache.linesz          = L1_CACHE_BYTES;
-       current_cpu_data.dcache.flags           = 0;
+       boot_cpu_data.type                      = CPU_SH7619;
+       boot_cpu_data.dcache.ways               = 4;
+       boot_cpu_data.dcache.way_incr   = (1<<12);
+       boot_cpu_data.dcache.sets               = 256;
+       boot_cpu_data.dcache.entry_shift        = 4;
+       boot_cpu_data.dcache.linesz             = L1_CACHE_BYTES;
+       boot_cpu_data.dcache.flags              = 0;
 #endif
        /*
         * SH-2 doesn't have separate caches
         */
-       current_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
-       current_cpu_data.icache = current_cpu_data.dcache;
+       boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
+       boot_cpu_data.icache = boot_cpu_data.dcache;
 
        return 0;
 }
index a979b981e6a38cc85fe93c673432ef23fa264560..ec6adc3f306f081b0b86170d5764520344578a48 100644 (file)
 #include <linux/serial.h>
 #include <asm/sci.h>
 
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       WDT, EDMAC, CMT0, CMT1,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+       SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+       HIF_HIFI, HIF_HIFBI,
+       DMAC0, DMAC1, DMAC2, DMAC3,
+       SIOF,
+
+       /* interrupt groups */
+       SCIF0, SCIF1, SCIF2,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+       INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+       INTC_IRQ(IRQ4, 80), INTC_IRQ(IRQ5, 81),
+       INTC_IRQ(IRQ6, 82), INTC_IRQ(IRQ7, 83),
+       INTC_IRQ(WDT, 84), INTC_IRQ(EDMAC, 85),
+       INTC_IRQ(CMT0, 86), INTC_IRQ(CMT1, 87),
+       INTC_IRQ(SCIF0_ERI, 88), INTC_IRQ(SCIF0_RXI, 89),
+       INTC_IRQ(SCIF0_BRI, 90), INTC_IRQ(SCIF0_TXI, 91),
+       INTC_IRQ(SCIF1_ERI, 92), INTC_IRQ(SCIF1_RXI, 93),
+       INTC_IRQ(SCIF1_BRI, 94), INTC_IRQ(SCIF1_TXI, 95),
+       INTC_IRQ(SCIF2_ERI, 96), INTC_IRQ(SCIF2_RXI, 97),
+       INTC_IRQ(SCIF2_BRI, 98), INTC_IRQ(SCIF2_TXI, 99),
+       INTC_IRQ(HIF_HIFI, 100), INTC_IRQ(HIF_HIFBI, 101),
+       INTC_IRQ(DMAC0, 104), INTC_IRQ(DMAC1, 105),
+       INTC_IRQ(DMAC2, 106), INTC_IRQ(DMAC3, 107),
+       INTC_IRQ(SIOF, 108),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xf8140006, 0, 16, 4, /* IPRA */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+       { 0xf8140008, 0, 16, 4, /* IPRB */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { 0xf8080000, 0, 16, 4, /* IPRC */ { WDT, EDMAC, CMT0, CMT1 } },
+       { 0xf8080002, 0, 16, 4, /* IPRD */ { SCIF0, SCIF1, SCIF2 } },
+       { 0xf8080004, 0, 16, 4, /* IPRE */ { HIF_HIFI, HIF_HIFBI } },
+       { 0xf8080006, 0, 16, 4, /* IPRF */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
+       { 0xf8080008, 0, 16, 4, /* IPRG */ { SIOF } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, groups,
+                        NULL, NULL, prio_registers, NULL);
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xf8400000,
@@ -52,43 +107,7 @@ static int __init sh7619_devices_setup(void)
 }
 __initcall(sh7619_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       { 86, 0,  4, 2 },       /* CMI0 */
-       { 88, 1, 12, 3 },       /* SCIF0_ERI */
-       { 89, 1, 12, 3 },       /* SCIF0_RXI */
-       { 90, 1, 12, 3 },       /* SCIF0_BRI */
-       { 91, 1, 12, 3 },       /* SCIF0_TXI */
-       { 92, 1,  8, 3 },       /* SCIF1_ERI */
-       { 93, 1,  8, 3 },       /* SCIF1_RXI */
-       { 94, 1,  8, 3 },       /* SCIF1_BRI */
-       { 95, 1,  8, 3 },       /* SCIF1_TXI */
-       { 96, 1,  4, 3 },       /* SCIF2_ERI */
-       { 97, 1,  4, 3 },       /* SCIF2_RXI */
-       { 98, 1,  4, 3 },       /* SCIF2_BRI */
-       { 99, 1,  4, 3 },       /* SCIF2_TXI */
-};
-
-static unsigned long ipr_offsets[] = {
-       0xf8080000,     /* IPRC */
-       0xf8080002,     /* IPRD */
-       0xf8080004,     /* IPRE */
-       0xf8080006,     /* IPRF */
-       0xf8080008,     /* IPRG */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7619",
-       },
-};
-
 void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
+       register_intc_controller(&intc_desc);
 }
index f455c3509789b8ba5b4943e758b31b27d9626695..6d02465704b98966ab1ac71cb9f8986abca28369 100644 (file)
 int __init detect_cpu_and_cache_system(void)
 {
        /* Just SH7206 for now .. */
-       current_cpu_data.type                   = CPU_SH7206;
-       current_cpu_data.flags                  |= CPU_HAS_OP32;
+       boot_cpu_data.type                      = CPU_SH7206;
+       boot_cpu_data.flags                     |= CPU_HAS_OP32;
 
-       current_cpu_data.dcache.ways            = 4;
-       current_cpu_data.dcache.way_incr        = (1 << 11);
-       current_cpu_data.dcache.sets            = 128;
-       current_cpu_data.dcache.entry_shift     = 4;
-       current_cpu_data.dcache.linesz          = L1_CACHE_BYTES;
-       current_cpu_data.dcache.flags           = 0;
+       boot_cpu_data.dcache.ways               = 4;
+       boot_cpu_data.dcache.way_incr   = (1 << 11);
+       boot_cpu_data.dcache.sets               = 128;
+       boot_cpu_data.dcache.entry_shift        = 4;
+       boot_cpu_data.dcache.linesz             = L1_CACHE_BYTES;
+       boot_cpu_data.dcache.flags              = 0;
 
        /*
         * The icache is the same as the dcache as far as this setup is
@@ -33,7 +33,7 @@ int __init detect_cpu_and_cache_system(void)
         * lacks the U bit that the dcache has, none of this has any bearing
         * on the cache info.
         */
-       current_cpu_data.icache         = current_cpu_data.dcache;
+       boot_cpu_data.icache            = boot_cpu_data.dcache;
 
        return 0;
 }
index deab16500167c79fdd1fcec616ffc19f01114275..bd745aa87222f5f2b23e5e4a00e9a55ad2feea23 100644 (file)
 #include <linux/serial.h>
 #include <asm/sci.h>
 
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+       ADC_ADI0, ADC_ADI1,
+       DMAC0_DEI, DMAC0_HEI, DMAC1_DEI, DMAC1_HEI,
+       DMAC2_DEI, DMAC2_HEI, DMAC3_DEI, DMAC3_HEI,
+       DMAC4_DEI, DMAC4_HEI, DMAC5_DEI, DMAC5_HEI,
+       DMAC6_DEI, DMAC6_HEI, DMAC7_DEI, DMAC7_HEI,
+       CMT0, CMT1, BSC, WDT,
+       MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
+       MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
+       MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
+       MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
+       MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
+       MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
+       MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W,
+       POE2_OEI1, POE2_OEI2,
+       MTU2S_TGI3A, MTU2S_TGI3B, MTU2S_TGI3C, MTU2S_TGI3D, MTU2S_TCI3V,
+       MTU2S_TGI4A, MTU2S_TGI4B, MTU2S_TGI4C, MTU2S_TGI4D, MTU2S_TCI4V,
+       MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W,
+       POE2_OEI3,
+       IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI,
+       SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+       SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+       SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+       SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+
+       /* interrupt groups */
+       PINT, DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+       MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+       MTU3_ABCD, MTU4_ABCD, MTU5, POE2_12, MTU3S_ABCD, MTU4S_ABCD, MTU5S,
+       IIC3, SCIF0, SCIF1, SCIF2, SCIF3,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+       INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+       INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+       INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+       INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+       INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+       INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+       INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+       INTC_IRQ(ADC_ADI0, 92), INTC_IRQ(ADC_ADI1, 96),
+       INTC_IRQ(DMAC0_DEI, 108), INTC_IRQ(DMAC0_HEI, 109),
+       INTC_IRQ(DMAC1_DEI, 112), INTC_IRQ(DMAC1_HEI, 113),
+       INTC_IRQ(DMAC2_DEI, 116), INTC_IRQ(DMAC2_HEI, 117),
+       INTC_IRQ(DMAC3_DEI, 120), INTC_IRQ(DMAC3_HEI, 121),
+       INTC_IRQ(DMAC4_DEI, 124), INTC_IRQ(DMAC4_HEI, 125),
+       INTC_IRQ(DMAC5_DEI, 128), INTC_IRQ(DMAC5_HEI, 129),
+       INTC_IRQ(DMAC6_DEI, 132), INTC_IRQ(DMAC6_HEI, 133),
+       INTC_IRQ(DMAC7_DEI, 136), INTC_IRQ(DMAC7_HEI, 137),
+       INTC_IRQ(CMT0, 140), INTC_IRQ(CMT1, 144),
+       INTC_IRQ(BSC, 148), INTC_IRQ(WDT, 152),
+       INTC_IRQ(MTU2_TGI0A, 156), INTC_IRQ(MTU2_TGI0B, 157),
+       INTC_IRQ(MTU2_TGI0C, 158), INTC_IRQ(MTU2_TGI0D, 159),
+       INTC_IRQ(MTU2_TCI0V, 160),
+       INTC_IRQ(MTU2_TGI0E, 161), INTC_IRQ(MTU2_TGI0F, 162),
+       INTC_IRQ(MTU2_TGI1A, 164), INTC_IRQ(MTU2_TGI1B, 165),
+       INTC_IRQ(MTU2_TCI1V, 168), INTC_IRQ(MTU2_TCI1U, 169),
+       INTC_IRQ(MTU2_TGI2A, 172), INTC_IRQ(MTU2_TGI2B, 173),
+       INTC_IRQ(MTU2_TCI2V, 176), INTC_IRQ(MTU2_TCI2U, 177),
+       INTC_IRQ(MTU2_TGI3A, 180), INTC_IRQ(MTU2_TGI3B, 181),
+       INTC_IRQ(MTU2_TGI3C, 182), INTC_IRQ(MTU2_TGI3D, 183),
+       INTC_IRQ(MTU2_TCI3V, 184),
+       INTC_IRQ(MTU2_TGI4A, 188), INTC_IRQ(MTU2_TGI4B, 189),
+       INTC_IRQ(MTU2_TGI4C, 190), INTC_IRQ(MTU2_TGI4D, 191),
+       INTC_IRQ(MTU2_TCI4V, 192),
+       INTC_IRQ(MTU2_TGI5U, 196), INTC_IRQ(MTU2_TGI5V, 197),
+       INTC_IRQ(MTU2_TGI5W, 198),
+       INTC_IRQ(POE2_OEI1, 200), INTC_IRQ(POE2_OEI2, 201),
+       INTC_IRQ(MTU2S_TGI3A, 204), INTC_IRQ(MTU2S_TGI3B, 205),
+       INTC_IRQ(MTU2S_TGI3C, 206), INTC_IRQ(MTU2S_TGI3D, 207),
+       INTC_IRQ(MTU2S_TCI3V, 208),
+       INTC_IRQ(MTU2S_TGI4A, 212), INTC_IRQ(MTU2S_TGI4B, 213),
+       INTC_IRQ(MTU2S_TGI4C, 214), INTC_IRQ(MTU2S_TGI4D, 215),
+       INTC_IRQ(MTU2S_TCI4V, 216),
+       INTC_IRQ(MTU2S_TGI5U, 220), INTC_IRQ(MTU2S_TGI5V, 221),
+       INTC_IRQ(MTU2S_TGI5W, 222),
+       INTC_IRQ(POE2_OEI3, 224),
+       INTC_IRQ(IIC3_STPI, 228), INTC_IRQ(IIC3_NAKI, 229),
+       INTC_IRQ(IIC3_RXI, 230), INTC_IRQ(IIC3_TXI, 231),
+       INTC_IRQ(IIC3_TEI, 232),
+       INTC_IRQ(SCIF0_BRI, 240), INTC_IRQ(SCIF0_ERI, 241),
+       INTC_IRQ(SCIF0_RXI, 242), INTC_IRQ(SCIF0_TXI, 243),
+       INTC_IRQ(SCIF1_BRI, 244), INTC_IRQ(SCIF1_ERI, 245),
+       INTC_IRQ(SCIF1_RXI, 246), INTC_IRQ(SCIF1_TXI, 247),
+       INTC_IRQ(SCIF2_BRI, 248), INTC_IRQ(SCIF2_ERI, 249),
+       INTC_IRQ(SCIF2_RXI, 250), INTC_IRQ(SCIF2_TXI, 251),
+       INTC_IRQ(SCIF3_BRI, 252), INTC_IRQ(SCIF3_ERI, 253),
+       INTC_IRQ(SCIF3_RXI, 254), INTC_IRQ(SCIF3_TXI, 255),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+                  PINT4, PINT5, PINT6, PINT7),
+       INTC_GROUP(DMAC0, DMAC0_DEI, DMAC0_HEI),
+       INTC_GROUP(DMAC1, DMAC1_DEI, DMAC1_HEI),
+       INTC_GROUP(DMAC2, DMAC2_DEI, DMAC2_HEI),
+       INTC_GROUP(DMAC3, DMAC3_DEI, DMAC3_HEI),
+       INTC_GROUP(DMAC4, DMAC4_DEI, DMAC4_HEI),
+       INTC_GROUP(DMAC5, DMAC5_DEI, DMAC5_HEI),
+       INTC_GROUP(DMAC6, DMAC6_DEI, DMAC6_HEI),
+       INTC_GROUP(DMAC7, DMAC7_DEI, DMAC7_HEI),
+       INTC_GROUP(MTU0_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
+       INTC_GROUP(MTU0_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
+       INTC_GROUP(MTU1_AB, MTU2_TGI1A, MTU2_TGI1B),
+       INTC_GROUP(MTU1_VU, MTU2_TCI1V, MTU2_TCI1U),
+       INTC_GROUP(MTU2_AB, MTU2_TGI2A, MTU2_TGI2B),
+       INTC_GROUP(MTU2_VU, MTU2_TCI2V, MTU2_TCI2U),
+       INTC_GROUP(MTU3_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
+       INTC_GROUP(MTU4_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
+       INTC_GROUP(MTU5, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W),
+       INTC_GROUP(POE2_12, POE2_OEI1, POE2_OEI2),
+       INTC_GROUP(MTU3S_ABCD, MTU2S_TGI3A, MTU2S_TGI3B,
+                  MTU2S_TGI3C, MTU2S_TGI3D),
+       INTC_GROUP(MTU4S_ABCD, MTU2S_TGI4A, MTU2S_TGI4B,
+                  MTU2S_TGI4C, MTU2S_TGI4D),
+       INTC_GROUP(MTU5S, MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W),
+       INTC_GROUP(IIC3, IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI),
+       INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+       INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+       INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+       { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, ADC_ADI0, ADC_ADI1 } },
+       { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
+       { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
+       { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { CMT0, CMT1, BSC, WDT } },
+       { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { MTU0_ABCD, MTU0_VEF,
+                                             MTU1_AB, MTU1_VU } },
+       { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { MTU2_AB, MTU2_VU,
+                                             MTU3_ABCD, MTU2_TCI3V } },
+       { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { MTU4_ABCD, MTU2_TCI4V,
+                                             MTU5, POE2_12 } },
+       { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU3S_ABCD, MTU2S_TCI3V,
+                                             MTU4S_ABCD, MTU2S_TCI4V } },
+       { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU5S, POE2_OEI3, IIC3, 0 } },
+       { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xfffe0808, 0, 16, /* PINTER */
+         { 0, 0, 0, 0, 0, 0, 0, 0,
+           PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7206", vectors, groups,
+                        NULL, mask_registers, prio_registers, NULL);
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xfffe8000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 241, 242, 243, 240},
+               .irqs           =  { 241, 242, 243, 240 },
        }, {
                .mapbase        = 0xfffe8800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 247, 244, 245, 246},
+               .irqs           =  { 245, 246, 247, 244 },
        }, {
                .mapbase        = 0xfffe9000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 249, 250, 251, 248},
+               .irqs           =  { 249, 250, 251, 248 },
        }, {
                .mapbase        = 0xfffe9800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 253, 254, 255, 252},
+               .irqs           =  { 253, 254, 255, 252 },
        }, {
                .flags = 0,
        }
@@ -57,57 +214,7 @@ static int __init sh7206_devices_setup(void)
 }
 __initcall(sh7206_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       { 140,  7, 12, 2 },     /* CMI0 */
-       { 164,  8,  4, 2 },     /* MTU2_TGI1A */
-       { 240, 13, 12, 3 },     /* SCIF0_BRI */
-       { 241, 13, 12, 3 },     /* SCIF0_ERI */
-       { 242, 13, 12, 3 },     /* SCIF0_RXI */
-       { 243, 13, 12, 3 },     /* SCIF0_TXI */
-       { 244, 13,  8, 3 },     /* SCIF1_BRI */
-       { 245, 13,  8, 3 },     /* SCIF1_ERI */
-       { 246, 13,  8, 3 },     /* SCIF1_RXI */
-       { 247, 13,  8, 3 },     /* SCIF1_TXI */
-       { 248, 13,  4, 3 },     /* SCIF2_BRI */
-       { 249, 13,  4, 3 },     /* SCIF2_ERI */
-       { 250, 13,  4, 3 },     /* SCIF2_RXI */
-       { 251, 13,  4, 3 },     /* SCIF2_TXI */
-       { 252, 13,  0, 3 },     /* SCIF3_BRI */
-       { 253, 13,  0, 3 },     /* SCIF3_ERI */
-       { 254, 13,  0, 3 },     /* SCIF3_RXI */
-       { 255, 13,  0, 3 },     /* SCIF3_TXI */
-};
-
-static unsigned long ipr_offsets[] = {
-       0xfffe0818,     /* IPR01 */
-       0xfffe081a,     /* IPR02 */
-       0,              /* unused */
-       0,              /* unused */
-       0xfffe0820,     /* IPR05 */
-       0xfffe0c00,     /* IPR06 */
-       0xfffe0c02,     /* IPR07 */
-       0xfffe0c04,     /* IPR08 */
-       0xfffe0c06,     /* IPR09 */
-       0xfffe0c08,     /* IPR10 */
-       0xfffe0c0a,     /* IPR11 */
-       0xfffe0c0c,     /* IPR12 */
-       0xfffe0c0e,     /* IPR13 */
-       0xfffe0c10,     /* IPR14 */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7206",
-       },
-};
-
 void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
+       register_intc_controller(&intc_desc);
 }
index 55b750763f66765729c024abeee4d0499b6f6a3e..646eb6933614a0852ec21798e5d01265dbaac5ad 100644 (file)
@@ -6,12 +6,13 @@ obj-y := ex.o probe.o entry.o
 
 # CPU subtype setup
 obj-$(CONFIG_CPU_SUBTYPE_SH7705)       += setup-sh7705.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7706)       += setup-sh7709.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7707)       += setup-sh7709.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7708)       += setup-sh7708.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7709)       += setup-sh7709.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7706)       += setup-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7707)       += setup-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7708)       += setup-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7709)       += setup-sh770x.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7710)       += setup-sh7710.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7712)       += setup-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7720)       += setup-sh7720.o
 
 # Primary on-chip clocks (common)
 clock-$(CONFIG_CPU_SH3)                        := clock-sh3.o
@@ -19,5 +20,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7705)    := clock-sh7705.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7706)     := clock-sh7706.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7709)     := clock-sh7709.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7710)     := clock-sh7710.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7720)     := clock-sh7710.o
 
 obj-y  += $(clock-y)
index 647623b22edc81d3c2ae5ea0c75b4fd29b2ba9e1..bf579e061e097a638f1aa03a3842cc118f578033 100644 (file)
@@ -50,44 +50,47 @@ int __init detect_cpu_and_cache_system(void)
 
        back_to_P1();
 
-       current_cpu_data.dcache.ways            = 4;
-       current_cpu_data.dcache.entry_shift     = 4;
-       current_cpu_data.dcache.linesz          = L1_CACHE_BYTES;
-       current_cpu_data.dcache.flags           = 0;
+       boot_cpu_data.dcache.ways               = 4;
+       boot_cpu_data.dcache.entry_shift        = 4;
+       boot_cpu_data.dcache.linesz             = L1_CACHE_BYTES;
+       boot_cpu_data.dcache.flags              = 0;
 
        /*
         * 7709A/7729 has 16K cache (256-entry), while 7702 has only
         * 2K(direct) 7702 is not supported (yet)
         */
        if (data0 == data1 && data2 == data3) { /* Shadow */
-               current_cpu_data.dcache.way_incr        = (1 << 11);
-               current_cpu_data.dcache.entry_mask      = 0x7f0;
-               current_cpu_data.dcache.sets            = 128;
-               current_cpu_data.type = CPU_SH7708;
+               boot_cpu_data.dcache.way_incr   = (1 << 11);
+               boot_cpu_data.dcache.entry_mask = 0x7f0;
+               boot_cpu_data.dcache.sets       = 128;
+               boot_cpu_data.type = CPU_SH7708;
 
-               current_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC;
+               boot_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC;
        } else {                                /* 7709A or 7729  */
-               current_cpu_data.dcache.way_incr        = (1 << 12);
-               current_cpu_data.dcache.entry_mask      = 0xff0;
-               current_cpu_data.dcache.sets            = 256;
-               current_cpu_data.type = CPU_SH7729;
+               boot_cpu_data.dcache.way_incr   = (1 << 12);
+               boot_cpu_data.dcache.entry_mask = 0xff0;
+               boot_cpu_data.dcache.sets       = 256;
+               boot_cpu_data.type = CPU_SH7729;
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7706)
-               current_cpu_data.type = CPU_SH7706;
+               boot_cpu_data.type = CPU_SH7706;
 #endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7710)
-               current_cpu_data.type = CPU_SH7710;
+               boot_cpu_data.type = CPU_SH7710;
 #endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7712)
-               current_cpu_data.type = CPU_SH7712;
+               boot_cpu_data.type = CPU_SH7712;
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+               boot_cpu_data.type = CPU_SH7720;
 #endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7705)
-               current_cpu_data.type = CPU_SH7705;
+               boot_cpu_data.type = CPU_SH7705;
 
 #if defined(CONFIG_SH7705_CACHE_32KB)
-               current_cpu_data.dcache.way_incr        = (1 << 13);
-               current_cpu_data.dcache.entry_mask      = 0x1ff0;
-               current_cpu_data.dcache.sets            = 512;
+               boot_cpu_data.dcache.way_incr   = (1 << 13);
+               boot_cpu_data.dcache.entry_mask = 0x1ff0;
+               boot_cpu_data.dcache.sets       = 512;
                ctrl_outl(CCR_CACHE_32KB, CCR3);
 #else
                ctrl_outl(CCR_CACHE_16KB, CCR3);
@@ -98,9 +101,8 @@ int __init detect_cpu_and_cache_system(void)
        /*
         * SH-3 doesn't have separate caches
         */
-       current_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
-       current_cpu_data.icache = current_cpu_data.dcache;
+       boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
+       boot_cpu_data.icache = boot_cpu_data.dcache;
 
        return 0;
 }
-
index ebd9d06d8bdd10bb7454c62533ddcd467d451c54..f6c65f2659e913b61f7b660fbb7f4dba82d2eae4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SH7705 Setup
  *
- *  Copyright (C) 2006  Paul Mundt
+ *  Copyright (C) 2006, 2007  Paul Mundt
  *  Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * This file is subject to the terms and conditions of the GNU General Public
  */
 #include <linux/platform_device.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <linux/serial.h>
 #include <asm/sci.h>
+#include <asm/rtc.h>
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
+       PINT07, PINT815,
+       DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+       SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+       ADC_ADI,
+       USB_USI0, USB_USI1,
+       TPU0, TPU1, TPU2, TPU3,
+       TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       WDT,
+       REF_RCMI,
+
+       /* interrupt groups */
+       RTC, TMU2, DMAC, USB, SCIF2, SCIF0,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+       INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
+       INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
+       INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
+       INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+       INTC_VECT(SCIF0_TXI, 0x8e0),
+       INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920),
+       INTC_VECT(SCIF2_TXI, 0x960),
+       INTC_VECT(ADC_ADI, 0x980),
+       INTC_VECT(USB_USI0, 0xa20), INTC_VECT(USB_USI1, 0xa40),
+       INTC_VECT(TPU0, 0xc00), INTC_VECT(TPU1, 0xc20),
+       INTC_VECT(TPU3, 0xc80), INTC_VECT(TPU1, 0xca0),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(REF_RCMI, 0x580),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+       INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
+       INTC_GROUP(USB, USB_USI0, USB_USI1),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+       INTC_PRIO(DMAC, 7),
+       INTC_PRIO(SCIF2, 3),
+       INTC_PRIO(SCIF0, 3),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, 0, 0 } },
+       { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+       { 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, IRQ5, IRQ4 } },
+       { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, SCIF0, SCIF2, ADC_ADI } },
+       { 0xa4080000, 0, 16, 4, /* IPRF */ { 0, 0, USB } },
+       { 0xa4080002, 0, 16, 4, /* IPRG */ { TPU0, TPU1 } },
+       { 0xa4080004, 0, 16, 4, /* IPRH */ { TPU2, TPU3 } },
+
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, groups,
+                        priorities, NULL, prio_registers, NULL);
+
+static struct intc_vect vectors_irq[] __initdata = {
+       INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+       INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh7705-irq", vectors_irq, NULL,
+                        priorities, NULL, prio_registers, NULL);
 
 static struct plat_sci_port sci_platform_data[] = {
        {
@@ -37,8 +119,43 @@ static struct platform_device sci_device = {
        },
 };
 
+static struct resource rtc_resources[] = {
+       [0] =   {
+               .start  = 0xfffffec0,
+               .end    = 0xfffffec0 + 0x1e,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] =   {
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] =   {
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] =   {
+               .start  = 22,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct sh_rtc_platform_info rtc_info = {
+       .capabilities   = RTC_CAP_4_DIGIT_YEAR,
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+       .dev            = {
+               .platform_data = &rtc_info,
+       },
+};
+
 static struct platform_device *sh7705_devices[] __initdata = {
        &sci_device,
+       &rtc_device,
 };
 
 static int __init sh7705_devices_setup(void)
@@ -48,51 +165,16 @@ static int __init sh7705_devices_setup(void)
 }
 __initcall(sh7705_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR-idx, shift, priority */
-       { 16, 0, 12, 2 }, /* TMU0 TUNI*/
-       { 17, 0,  8, 2 }, /* TMU1 TUNI */
-       { 18, 0,  4, 2 }, /* TMU2 TUNI */
-       { 27, 1, 12, 2 }, /* WDT ITI */
-       { 20, 0,  0, 2 }, /* RTC ATI (alarm) */
-       { 21, 0,  0, 2 }, /* RTC PRI (period) */
-       { 22, 0,  0, 2 }, /* RTC CUI (carry) */
-       { 48, 4, 12, 7 }, /* DMAC DMTE0 */
-       { 49, 4, 12, 7 }, /* DMAC DMTE1 */
-       { 50, 4, 12, 7 }, /* DMAC DMTE2 */
-       { 51, 4, 12, 7 }, /* DMAC DMTE3 */
-       { 52, 4,  8, 3 }, /* SCIF0 ERI */
-       { 53, 4,  8, 3 }, /* SCIF0 RXI */
-       { 55, 4,  8, 3 }, /* SCIF0 TXI */
-       { 56, 4,  4, 3 }, /* SCIF1 ERI */
-       { 57, 4,  4, 3 }, /* SCIF1 RXI */
-       { 59, 4,  4, 3 }, /* SCIF1 TXI */
-};
-
-static unsigned long ipr_offsets[] = {
-       0xFFFFFEE2,     /* 0: IPRA */
-       0xFFFFFEE4,     /* 1: IPRB */
-       0xA4000016,     /* 2: IPRC */
-       0xA4000018,     /* 3: IPRD */
-       0xA400001A,     /* 4: IPRE */
-       0xA4080000,     /* 5: IPRF */
-       0xA4080002,     /* 6: IPRG */
-       0xA4080004,     /* 7: IPRH */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7705",
-       },
-};
+void __init plat_irq_setup_pins(int mode)
+{
+       if (mode == IRQ_MODE_IRQ) {
+               register_intc_controller(&intc_desc_irq);
+               return;
+       }
+       BUG();
+}
 
 void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
+       register_intc_controller(&intc_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7708.c b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
deleted file mode 100644 (file)
index f933723..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SH7708 Setup
- *
- *  Copyright (C) 2006  Paul Mundt
- *
- * 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 more details.
- */
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <asm/sci.h>
-
-static struct plat_sci_port sci_platform_data[] = {
-       {
-               .mapbase        = 0xfffffe80,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .type           = PORT_SCI,
-               .irqs           = { 23, 24, 25, 0 },
-       }, {
-               .flags = 0,
-       }
-};
-
-static struct platform_device sci_device = {
-       .name           = "sh-sci",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = sci_platform_data,
-       },
-};
-
-static struct platform_device *sh7708_devices[] __initdata = {
-       &sci_device,
-};
-
-static int __init sh7708_devices_setup(void)
-{
-       return platform_add_devices(sh7708_devices,
-                                   ARRAY_SIZE(sh7708_devices));
-}
-__initcall(sh7708_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
deleted file mode 100644 (file)
index 086f8e2..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * SH7707/SH7709 Setup
- *
- *  Copyright (C) 2006  Paul Mundt
- *
- * 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 more details.
- */
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <asm/sci.h>
-
-static struct resource rtc_resources[] = {
-       [0] =   {
-               .start  = 0xfffffec0,
-               .end    = 0xfffffec0 + 0x1e,
-               .flags  = IORESOURCE_IO,
-       },
-       [1] =   {
-               .start  = 20,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] =   {
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] =   {
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct plat_sci_port sci_platform_data[] = {
-       {
-               .mapbase        = 0xfffffe80,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .type           = PORT_SCI,
-               .irqs           = { 23, 24, 25, 0 },
-       }, {
-               .mapbase        = 0xa4000150,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .type           = PORT_SCIF,
-               .irqs           = { 56, 57, 59, 58 },
-       }, {
-               .mapbase        = 0xa4000140,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .type           = PORT_IRDA,
-               .irqs           = { 52, 53, 55, 54 },
-       }, {
-               .flags = 0,
-       }
-};
-
-static struct platform_device sci_device = {
-       .name           = "sh-sci",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = sci_platform_data,
-       },
-};
-
-static struct platform_device rtc_device = {
-       .name           = "sh-rtc",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(rtc_resources),
-       .resource       = rtc_resources,
-};
-
-static struct platform_device *sh7709_devices[] __initdata = {
-       &sci_device,
-       &rtc_device,
-};
-
-static int __init sh7709_devices_setup(void)
-{
-       return platform_add_devices(sh7709_devices,
-               ARRAY_SIZE(sh7709_devices));
-}
-__initcall(sh7709_devices_setup);
-
-static struct ipr_data ipr_irq_table[] = {
-       { 16, 0, 12, 2 }, /* TMU TUNI0 */
-       { 17, 0, 8,  4 }, /* TMU TUNI1 */
-       { 18, 0, 4,  1 }, /* TMU TUNI1 */
-       { 19, 0, 4,  1 }, /* TMU TUNI1 */
-       { 20, 0, 0,  2 }, /* RTC CUI */
-       { 21, 0, 0,  2 }, /* RTC CUI */
-       { 22, 0, 0,  2 }, /* RTC CUI */
-
-       { 23, 1, 4,  3 }, /* SCI */
-       { 24, 1, 4,  3 }, /* SCI */
-       { 25, 1, 4,  3 }, /* SCI */
-       { 26, 1, 4,  3 }, /* SCI */
-       { 27, 1, 12, 3 }, /* WDT ITI */
-
-       { 32, 2, 0,  1 }, /* IRQ 0 */
-       { 33, 2, 4,  1 }, /* IRQ 1 */
-       { 34, 2, 8,  1 }, /* IRQ 2 APM */
-       { 35, 2, 12, 1 }, /* IRQ 3 TOUCHSCREEN */
-
-       { 36, 3, 0,  1 }, /* IRQ 4 */
-       { 37, 3, 4,  1 }, /* IRQ 5 */
-
-       { 48, 4, 12, 7 }, /* DMA */
-       { 49, 4, 12, 7 }, /* DMA */
-       { 50, 4, 12, 7 }, /* DMA */
-       { 51, 4, 12, 7 }, /* DMA */
-
-       { 52, 4, 8,  3 }, /* IRDA */
-       { 53, 4, 8,  3 }, /* IRDA */
-       { 54, 4, 8,  3 }, /* IRDA */
-       { 55, 4, 8,  3 }, /* IRDA */
-
-       { 56, 4, 4,  3 }, /* SCIF */
-       { 57, 4, 4,  3 }, /* SCIF */
-       { 58, 4, 4,  3 }, /* SCIF */
-       { 59, 4, 4,  3 }, /* SCIF */
-};
-
-static unsigned long ipr_offsets[] = {
-       0xfffffee2,     /* 0: IPRA */
-       0xfffffee4,     /* 1: IPRB */
-       0xa4000016,     /* 2: IPRC */
-       0xa4000018,     /* 3: IPRD */
-       0xa400001a,     /* 4: IPRE */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7709",
-       },
-};
-
-void __init plat_irq_setup(void)
-{
-       register_ipr_controller(&ipr_irq_desc);
-}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
new file mode 100644 (file)
index 0000000..60b04b1
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * SH3 Setup code for SH7706, SH7707, SH7708, SH7709
+ *
+ *  Copyright (C) 2007  Magnus Damm
+ *
+ * Based on setup-sh7709.c
+ *
+ *  Copyright (C) 2006  Paul Mundt
+ *
+ * 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 more details.
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
+       PINT07, PINT815,
+       DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+       SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI,
+       ADC_ADI,
+       LCDC, PCC0, PCC1,
+       TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       WDT,
+       REF_RCMI, REF_ROVI,
+
+       /* interrupt groups */
+       RTC, REF, TMU2, DMAC, SCI, SCIF2, SCIF0,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(SCI_ERI, 0x4e0), INTC_VECT(SCI_RXI, 0x500),
+       INTC_VECT(SCI_TXI, 0x520), INTC_VECT(SCI_TEI, 0x540),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(REF_RCMI, 0x580),
+       INTC_VECT(REF_ROVI, 0x5a0),
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+       INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+       INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
+       INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
+       INTC_VECT(ADC_ADI, 0x980),
+       INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920),
+       INTC_VECT(SCIF2_BRI, 0x940), INTC_VECT(SCIF2_TXI, 0x960),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+       INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
+       INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+       INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+       INTC_VECT(LCDC, 0x9a0),
+       INTC_VECT(PCC0, 0x9c0), INTC_VECT(PCC1, 0x9e0),
+#endif
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+       INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+       INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
+       INTC_GROUP(SCI, SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+       INTC_PRIO(DMAC, 7),
+       INTC_PRIO(SCI, 3),
+       INTC_PRIO(SCIF2, 3),
+       INTC_PRIO(SCIF0, 3),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } },
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+       { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+       { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
+       { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, 0, SCIF2, ADC_ADI } },
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+       { 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, } },
+       { 0xa400001a, 0, 16, 4, /* IPRE */ { 0, SCIF0 } },
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+       { 0xa400001c, 0, 16, 4, /* IPRF */ { 0, LCDC, PCC0, PCC1, } },
+#endif
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, groups,
+                        priorities, NULL, prio_registers, NULL);
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+static struct intc_vect vectors_irq[] __initdata = {
+       INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+       INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh770x-irq", vectors_irq, NULL,
+                        priorities, NULL, prio_registers, NULL);
+#endif
+
+static struct resource rtc_resources[] = {
+       [0] =   {
+               .start  = 0xfffffec0,
+               .end    = 0xfffffec0 + 0x1e,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] =   {
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] =   {
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] =   {
+               .start  = 22,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+};
+
+static struct plat_sci_port sci_platform_data[] = {
+       {
+               .mapbase        = 0xfffffe80,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCI,
+               .irqs           = { 23, 24, 25, 0 },
+       },
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+       {
+               .mapbase        = 0xa4000150,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 56, 57, 59, 58 },
+       },
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+       {
+               .mapbase        = 0xa4000140,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_IRDA,
+               .irqs           = { 52, 53, 55, 54 },
+       },
+#endif
+       {
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+static struct platform_device *sh770x_devices[] __initdata = {
+       &sci_device,
+       &rtc_device,
+};
+
+static int __init sh770x_devices_setup(void)
+{
+       return platform_add_devices(sh770x_devices,
+               ARRAY_SIZE(sh770x_devices));
+}
+__initcall(sh770x_devices_setup);
+
+#define INTC_ICR1              0xa4000010UL
+#define INTC_ICR1_IRQLVL       (1<<14)
+
+void __init plat_irq_setup_pins(int mode)
+{
+       if (mode == IRQ_MODE_IRQ) {
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+               ctrl_outw(ctrl_inw(INTC_ICR1) & ~INTC_ICR1_IRQLVL, INTC_ICR1);
+               register_intc_controller(&intc_desc_irq);
+               return;
+#endif
+       }
+       BUG();
+}
+
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+}
index 1322848933736d49aea74f268215d283be8b5d9b..84e5629fa84175716e837dd2d5b17be7b9ed70dc 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * SH7710 Setup
+ * SH3 Setup code for SH7710, SH7712
  *
- *  Copyright (C) 2006  Paul Mundt
+ *  Copyright (C) 2006, 2007  Paul Mundt
  *  Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * This file is subject to the terms and conditions of the GNU General Public
  */
 #include <linux/platform_device.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <linux/serial.h>
 #include <asm/sci.h>
+#include <asm/rtc.h>
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
+       DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+       DMAC_DEI4, DMAC_DEI5,
+       IPSEC,
+       EDMAC0, EDMAC1, EDMAC2,
+       SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI,
+       SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI,
+       TMU0, TMU1, TMU2,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       WDT,
+       REF,
+
+       /* interrupt groups */
+       RTC, DMAC1, SCIF0, SCIF1, DMAC2, SIOF0, SIOF1,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+       INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
+       INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
+       INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+       INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
+       INTC_VECT(SCIF1_ERI, 0x900), INTC_VECT(SCIF1_RXI, 0x920),
+       INTC_VECT(SCIF1_BRI, 0x940), INTC_VECT(SCIF1_TXI, 0x960),
+       INTC_VECT(DMAC_DEI4, 0xb80), INTC_VECT(DMAC_DEI5, 0xba0),
+#ifdef CONFIG_CPU_SUBTYPE_SH7710
+       INTC_VECT(IPSEC, 0xbe0),
+#endif
+       INTC_VECT(EDMAC0, 0xc00), INTC_VECT(EDMAC1, 0xc20),
+       INTC_VECT(EDMAC2, 0xc40),
+       INTC_VECT(SIOF0_ERI, 0xe00), INTC_VECT(SIOF0_TXI, 0xe20),
+       INTC_VECT(SIOF0_RXI, 0xe40), INTC_VECT(SIOF0_CCI, 0xe60),
+       INTC_VECT(SIOF1_ERI, 0xe80), INTC_VECT(SIOF1_TXI, 0xea0),
+       INTC_VECT(SIOF1_RXI, 0xec0), INTC_VECT(SIOF1_CCI, 0xee0),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2, 0x440),
+       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(REF, 0x580),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(DMAC1, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+       INTC_GROUP(DMAC2, DMAC_DEI4, DMAC_DEI5),
+       INTC_GROUP(SIOF0, SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI),
+       INTC_GROUP(SIOF1, SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+       INTC_PRIO(DMAC1, 7),
+       INTC_PRIO(DMAC2, 7),
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+       INTC_PRIO(SIOF0, 3),
+       INTC_PRIO(SIOF1, 3),
+       INTC_PRIO(EDMAC0, 5),
+       INTC_PRIO(EDMAC1, 5),
+       INTC_PRIO(EDMAC2, 5),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
+       { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+       { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
+       { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC1, SCIF0, SCIF1 } },
+       { 0xa4080000, 0, 16, 4, /* IPRF */ { 0, DMAC2 } },
+#ifdef CONFIG_CPU_SUBTYPE_SH7710
+       { 0xa4080000, 0, 16, 4, /* IPRF */ { IPSEC } },
+#endif
+       { 0xa4080002, 0, 16, 4, /* IPRG */ { EDMAC0, EDMAC1, EDMAC2 } },
+       { 0xa4080004, 0, 16, 4, /* IPRH */ { 0, 0, 0, SIOF0 } },
+       { 0xa4080006, 0, 16, 4, /* IPRI */ { 0, 0, SIOF1 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, groups,
+                        priorities, NULL, prio_registers, NULL);
+
+static struct intc_vect vectors_irq[] __initdata = {
+       INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+       INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh7710-irq", vectors_irq, NULL,
+                        priorities, NULL, prio_registers, NULL);
+
+static struct resource rtc_resources[] = {
+       [0] =   {
+               .start  = 0xa413fec0,
+               .end    = 0xa413fec0 + 0x1e,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] =   {
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] =   {
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] =   {
+               .start  = 22,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct sh_rtc_platform_info rtc_info = {
+       .capabilities   = RTC_CAP_4_DIGIT_YEAR,
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+       .dev            = {
+               .platform_data = &rtc_info,
+       },
+};
 
 static struct plat_sci_port sci_platform_data[] = {
        {
@@ -20,7 +152,7 @@ static struct plat_sci_port sci_platform_data[] = {
                .type           = PORT_SCIF,
                .irqs           = { 52, 53, 55, 54 },
        }, {
-               .mapbase        = 0xa4420000,
+               .mapbase        = 0xa4410000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 56, 57, 59, 58 },
@@ -40,6 +172,7 @@ static struct platform_device sci_device = {
 
 static struct platform_device *sh7710_devices[] __initdata = {
        &sci_device,
+       &rtc_device,
 };
 
 static int __init sh7710_devices_setup(void)
@@ -49,59 +182,16 @@ static int __init sh7710_devices_setup(void)
 }
 __initcall(sh7710_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR-idx, shift, priority */
-       { 16, 0, 12, 2 }, /* TMU0 TUNI*/
-       { 17, 0,  8, 2 }, /* TMU1 TUNI */
-       { 18, 0,  4, 2 }, /* TMU2 TUNI */
-       { 27, 1, 12, 2 }, /* WDT ITI */
-       { 20, 0,  0, 2 }, /* RTC ATI (alarm) */
-       { 21, 0,  0, 2 }, /* RTC PRI (period) */
-       { 22, 0,  0, 2 }, /* RTC CUI (carry) */
-       { 48, 4, 12, 7 }, /* DMAC DMTE0 */
-       { 49, 4, 12, 7 }, /* DMAC DMTE1 */
-       { 50, 4, 12, 7 }, /* DMAC DMTE2 */
-       { 51, 4, 12, 7 }, /* DMAC DMTE3 */
-       { 52, 4,  8, 3 }, /* SCIF0 ERI */
-       { 53, 4,  8, 3 }, /* SCIF0 RXI */
-       { 54, 4,  8, 3 }, /* SCIF0 BRI */
-       { 55, 4,  8, 3 }, /* SCIF0 TXI */
-       { 56, 4,  4, 3 }, /* SCIF1 ERI */
-       { 57, 4,  4, 3 }, /* SCIF1 RXI */
-       { 58, 4,  4, 3 }, /* SCIF1 BRI */
-       { 59, 4,  4, 3 }, /* SCIF1 TXI */
-       { 76, 5,  8, 7 }, /* DMAC DMTE4 */
-       { 77, 5,  8, 7 }, /* DMAC DMTE5 */
-       { 80, 6, 12, 5 }, /* EDMAC EINT0 */
-       { 81, 6,  8, 5 }, /* EDMAC EINT1 */
-       { 82, 6,  4, 5 }, /* EDMAC EINT2 */
-};
-
-static unsigned long ipr_offsets[] = {
-       0xA414FEE2,     /* 0: IPRA */
-       0xA414FEE4,     /* 1: IPRB */
-       0xA4140016,     /* 2: IPRC */
-       0xA4140018,     /* 3: IPRD */
-       0xA414001A,     /* 4: IPRE */
-       0xA4080000,     /* 5: IPRF */
-       0xA4080002,     /* 6: IPRG */
-       0xA4080004,     /* 7: IPRH */
-       0xA4080006,     /* 8: IPRI */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7710",
-       },
-};
+void __init plat_irq_setup_pins(int mode)
+{
+       if (mode == IRQ_MODE_IRQ) {
+               register_intc_controller(&intc_desc_irq);
+               return;
+       }
+       BUG();
+}
 
 void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
+       register_intc_controller(&intc_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
new file mode 100644 (file)
index 0000000..a0929b8
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * SH7720 Setup
+ *
+ *  Copyright (C) 2007  Markus Brunner, Mark Jonas
+ *
+ *  Based on arch/sh/kernel/cpu/sh4/setup-sh7750.c:
+ *
+ *  Copyright (C) 2006  Paul Mundt
+ *  Copyright (C) 2006  Jamie Lenehan
+ *
+ * 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 more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <asm/sci.h>
+#include <asm/rtc.h>
+
+#define INTC_ICR1      0xA4140010UL
+#define INTC_ICR_IRLM   0x4000
+#define INTC_ICR_IRQ   (~INTC_ICR_IRLM)
+
+static struct resource rtc_resources[] = {
+       [0] = {
+               .start  = 0xa413fec0,
+               .end    = 0xa413fec0 + 0x28 - 1,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] = {
+               /* Period IRQ */
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* Carry IRQ */
+               .start  = 22,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               /* Alarm IRQ */
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct sh_rtc_platform_info rtc_info = {
+       .capabilities   = RTC_CAP_4_DIGIT_YEAR,
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+       .dev            = {
+               .platform_data = &rtc_info,
+       },
+};
+
+static struct plat_sci_port sci_platform_data[] = {
+       {
+               .mapbase        = 0xa4430000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 80, 80, 80, 80 },
+       }, {
+               .mapbase        = 0xa4438000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 81, 81, 81, 81 },
+       }, {
+
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+static struct platform_device *sh7720_devices[] __initdata = {
+       &rtc_device,
+       &sci_device,
+};
+
+static int __init sh7720_devices_setup(void)
+{
+       return platform_add_devices(sh7720_devices,
+                                   ARRAY_SIZE(sh7720_devices));
+}
+__initcall(sh7720_devices_setup);
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       TMU0, TMU1, TMU2, RTC_ATI, RTC_PRI, RTC_CUI,
+       WDT, REF_RCMI, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND,
+       IRQ0, IRQ1, IRQ2, IRQ3,
+       USBF_SPD, TMU_SUNI, IRQ5, IRQ4,
+       DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3, LCDC, SSL,
+       ADC, DMAC2_DEI4, DMAC2_DEI5, USBFI0, USBFI1, CMT,
+       SCIF0, SCIF1,
+       PINT07, PINT815, TPU0, TPU1, TPU2, TPU3, IIC,
+       SIOF0, SIOF1, MMCI0, MMCI1, MMCI2, MMCI3, PCC,
+       USBHI, AFEIF,
+       H_UDI,
+       /* interrupt groups */
+       TMU, RTC, SIM, DMAC1, USBFI, DMAC2, USB, TPU, MMC,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(TMU0, 0x400),       INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2, 0x440),       INTC_VECT(RTC_ATI, 0x480),
+       INTC_VECT(RTC_PRI, 0x4a0),    INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(SIM_ERI, 0x4e0),    INTC_VECT(SIM_RXI, 0x500),
+       INTC_VECT(SIM_TXI, 0x520),    INTC_VECT(SIM_TEND, 0x540),
+       INTC_VECT(WDT, 0x560),        INTC_VECT(REF_RCMI, 0x580),
+       /* H_UDI cannot be masked */  INTC_VECT(TMU_SUNI, 0x6c0),
+       INTC_VECT(USBF_SPD, 0x6e0),   INTC_VECT(DMAC1_DEI0, 0x800),
+       INTC_VECT(DMAC1_DEI1, 0x820), INTC_VECT(DMAC1_DEI2, 0x840),
+       INTC_VECT(DMAC1_DEI3, 0x860), INTC_VECT(LCDC, 0x900),
+       INTC_VECT(SSL, 0x980),        INTC_VECT(USBFI0, 0xa20),
+       INTC_VECT(USBFI1, 0xa40),     INTC_VECT(USBHI, 0xa60),
+       INTC_VECT(DMAC2_DEI4, 0xb80), INTC_VECT(DMAC2_DEI5, 0xba0),
+       INTC_VECT(ADC, 0xbe0),        INTC_VECT(SCIF0, 0xc00),
+       INTC_VECT(SCIF1, 0xc20),      INTC_VECT(PINT07, 0xc80),
+       INTC_VECT(PINT815, 0xca0),    INTC_VECT(SIOF0, 0xd00),
+       INTC_VECT(SIOF1, 0xd20),      INTC_VECT(TPU0, 0xd80),
+       INTC_VECT(TPU1, 0xda0),       INTC_VECT(TPU2, 0xdc0),
+       INTC_VECT(TPU3, 0xde0),       INTC_VECT(IIC, 0xe00),
+       INTC_VECT(MMCI0, 0xe80),      INTC_VECT(MMCI1, 0xea0),
+       INTC_VECT(MMCI2, 0xec0),      INTC_VECT(MMCI3, 0xee0),
+       INTC_VECT(CMT, 0xf00),        INTC_VECT(PCC, 0xf60),
+       INTC_VECT(AFEIF, 0xfe0),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(TMU, TMU0, TMU1, TMU2),
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND),
+       INTC_GROUP(DMAC1, DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3),
+       INTC_GROUP(USBFI, USBFI0, USBFI1),
+       INTC_GROUP(DMAC2, DMAC2_DEI4, DMAC2_DEI5),
+       INTC_GROUP(TPU, TPU0, TPU1, TPU2, TPU3),
+       INTC_GROUP(MMC, MMCI0, MMCI1, MMCI2, MMCI3),
+};
+
+static struct intc_prio priorities[] __initdata = {
+       INTC_PRIO(SCIF0, 2),
+       INTC_PRIO(SCIF1, 2),
+       INTC_PRIO(DMAC1, 1),
+       INTC_PRIO(DMAC2, 1),
+       INTC_PRIO(RTC, 2),
+       INTC_PRIO(TMU, 2),
+       INTC_PRIO(TPU, 2),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xA414FEE2UL, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xA414FEE4UL, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, SIM, 0 } },
+       { 0xA4140016UL, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+       { 0xA4140018UL, 0, 16, 4, /* IPRD */ { USBF_SPD, TMU_SUNI, IRQ5, IRQ4 } },
+       { 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, SSL } },
+       { 0xA4080000UL, 0, 16, 4, /* IPRF */ { ADC, DMAC2, USBFI, CMT } },
+       { 0xA4080002UL, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, 0, 0 } },
+       { 0xA4080004UL, 0, 16, 4, /* IPRH */ { PINT07, PINT815, TPU, IIC } },
+       { 0xA4080006UL, 0, 16, 4, /* IPRI */ { SIOF0, SIOF1, MMC, PCC } },
+       { 0xA4080008UL, 0, 16, 4, /* IPRJ */ { 0, USBHI, 0, AFEIF } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, groups,
+               priorities, NULL, prio_registers, NULL);
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+       { INTC_ICR1, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
+};
+
+static struct intc_vect vectors_irq[] __initdata = {
+       INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+       INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+       INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7720-irq", vectors_irq,
+               NULL, priorities, NULL, prio_registers, sense_registers);
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ:
+               ctrl_outw(ctrl_inw(INTC_ICR1) & INTC_ICR_IRQ, INTC_ICR1);
+               register_intc_controller(&intc_irq_desc);
+               break;
+       default:
+               BUG();
+       }
+}
+
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+}
index 98d28fb1ce167a47769536163c68e31ee4c6bdc4..21375d777e9993687da782446a3ad27e96a3b2c3 100644 (file)
@@ -3,7 +3,7 @@
  *
  * CPU Subtype Probing for SH-4.
  *
- * Copyright (C) 2001 - 2006  Paul Mundt
+ * Copyright (C) 2001 - 2007  Paul Mundt
  * Copyright (C) 2003  Richard Curnow
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -12,7 +12,6 @@
  */
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/smp.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 
@@ -36,37 +35,34 @@ int __init detect_cpu_and_cache_system(void)
        /*
         * Setup some sane SH-4 defaults for the icache
         */
-       current_cpu_data.icache.way_incr        = (1 << 13);
-       current_cpu_data.icache.entry_shift     = 5;
-       current_cpu_data.icache.sets            = 256;
-       current_cpu_data.icache.ways            = 1;
-       current_cpu_data.icache.linesz          = L1_CACHE_BYTES;
+       boot_cpu_data.icache.way_incr           = (1 << 13);
+       boot_cpu_data.icache.entry_shift        = 5;
+       boot_cpu_data.icache.sets               = 256;
+       boot_cpu_data.icache.ways               = 1;
+       boot_cpu_data.icache.linesz             = L1_CACHE_BYTES;
 
        /*
         * And again for the dcache ..
         */
-       current_cpu_data.dcache.way_incr        = (1 << 14);
-       current_cpu_data.dcache.entry_shift     = 5;
-       current_cpu_data.dcache.sets            = 512;
-       current_cpu_data.dcache.ways            = 1;
-       current_cpu_data.dcache.linesz          = L1_CACHE_BYTES;
+       boot_cpu_data.dcache.way_incr           = (1 << 14);
+       boot_cpu_data.dcache.entry_shift        = 5;
+       boot_cpu_data.dcache.sets               = 512;
+       boot_cpu_data.dcache.ways               = 1;
+       boot_cpu_data.dcache.linesz             = L1_CACHE_BYTES;
 
        /*
-        * Setup some generic flags we can probe
-        * (L2 and DSP detection only work on SH-4A)
+        * Setup some generic flags we can probe on SH-4A parts
         */
        if (((pvr >> 16) & 0xff) == 0x10) {
-               if ((cvr & 0x02000000) == 0)
-                       current_cpu_data.flags |= CPU_HAS_L2_CACHE;
                if ((cvr & 0x10000000) == 0)
-                       current_cpu_data.flags |= CPU_HAS_DSP;
+                       boot_cpu_data.flags |= CPU_HAS_DSP;
 
-               current_cpu_data.flags |= CPU_HAS_LLSC;
+               boot_cpu_data.flags |= CPU_HAS_LLSC;
        }
 
        /* FPU detection works for everyone */
        if ((cvr & 0x20000000) == 1)
-               current_cpu_data.flags |= CPU_HAS_FPU;
+               boot_cpu_data.flags |= CPU_HAS_FPU;
 
        /* Mask off the upper chip ID */
        pvr &= 0xffff;
@@ -77,140 +73,140 @@ int __init detect_cpu_and_cache_system(void)
         */
        switch (pvr) {
        case 0x205:
-               current_cpu_data.type = CPU_SH7750;
-               current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+               boot_cpu_data.type = CPU_SH7750;
+               boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
                                   CPU_HAS_PERF_COUNTER;
                break;
        case 0x206:
-               current_cpu_data.type = CPU_SH7750S;
-               current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+               boot_cpu_data.type = CPU_SH7750S;
+               boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
                                   CPU_HAS_PERF_COUNTER;
                break;
        case 0x1100:
-               current_cpu_data.type = CPU_SH7751;
-               current_cpu_data.flags |= CPU_HAS_FPU;
+               boot_cpu_data.type = CPU_SH7751;
+               boot_cpu_data.flags |= CPU_HAS_FPU;
                break;
        case 0x2001:
        case 0x2004:
-               current_cpu_data.type = CPU_SH7770;
-               current_cpu_data.icache.ways = 4;
-               current_cpu_data.dcache.ways = 4;
+               boot_cpu_data.type = CPU_SH7770;
+               boot_cpu_data.icache.ways = 4;
+               boot_cpu_data.dcache.ways = 4;
 
-               current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
+               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
                break;
        case 0x2006:
        case 0x200A:
                if (prr == 0x61)
-                       current_cpu_data.type = CPU_SH7781;
+                       boot_cpu_data.type = CPU_SH7781;
                else
-                       current_cpu_data.type = CPU_SH7780;
+                       boot_cpu_data.type = CPU_SH7780;
 
-               current_cpu_data.icache.ways = 4;
-               current_cpu_data.dcache.ways = 4;
+               boot_cpu_data.icache.ways = 4;
+               boot_cpu_data.dcache.ways = 4;
 
-               current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
                                   CPU_HAS_LLSC;
                break;
        case 0x3000:
        case 0x3003:
        case 0x3009:
-               current_cpu_data.type = CPU_SH7343;
-               current_cpu_data.icache.ways = 4;
-               current_cpu_data.dcache.ways = 4;
-               current_cpu_data.flags |= CPU_HAS_LLSC;
+               boot_cpu_data.type = CPU_SH7343;
+               boot_cpu_data.icache.ways = 4;
+               boot_cpu_data.dcache.ways = 4;
+               boot_cpu_data.flags |= CPU_HAS_LLSC;
                break;
        case 0x3004:
        case 0x3007:
-               current_cpu_data.type = CPU_SH7785;
-               current_cpu_data.icache.ways = 4;
-               current_cpu_data.dcache.ways = 4;
-               current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+               boot_cpu_data.type = CPU_SH7785;
+               boot_cpu_data.icache.ways = 4;
+               boot_cpu_data.dcache.ways = 4;
+               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
                                          CPU_HAS_LLSC;
                break;
        case 0x3008:
                if (prr == 0xa0) {
-                       current_cpu_data.type = CPU_SH7722;
-                       current_cpu_data.icache.ways = 4;
-                       current_cpu_data.dcache.ways = 4;
-                       current_cpu_data.flags |= CPU_HAS_LLSC;
+                       boot_cpu_data.type = CPU_SH7722;
+                       boot_cpu_data.icache.ways = 4;
+                       boot_cpu_data.dcache.ways = 4;
+                       boot_cpu_data.flags |= CPU_HAS_LLSC;
                }
                break;
        case 0x4000:    /* 1st cut */
        case 0x4001:    /* 2nd cut */
-               current_cpu_data.type = CPU_SHX3;
-               current_cpu_data.icache.ways = 4;
-               current_cpu_data.dcache.ways = 4;
-               current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+               boot_cpu_data.type = CPU_SHX3;
+               boot_cpu_data.icache.ways = 4;
+               boot_cpu_data.dcache.ways = 4;
+               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
                                          CPU_HAS_LLSC;
                break;
        case 0x8000:
-               current_cpu_data.type = CPU_ST40RA;
-               current_cpu_data.flags |= CPU_HAS_FPU;
+               boot_cpu_data.type = CPU_ST40RA;
+               boot_cpu_data.flags |= CPU_HAS_FPU;
                break;
        case 0x8100:
-               current_cpu_data.type = CPU_ST40GX1;
-               current_cpu_data.flags |= CPU_HAS_FPU;
+               boot_cpu_data.type = CPU_ST40GX1;
+               boot_cpu_data.flags |= CPU_HAS_FPU;
                break;
        case 0x700:
-               current_cpu_data.type = CPU_SH4_501;
-               current_cpu_data.icache.ways = 2;
-               current_cpu_data.dcache.ways = 2;
+               boot_cpu_data.type = CPU_SH4_501;
+               boot_cpu_data.icache.ways = 2;
+               boot_cpu_data.dcache.ways = 2;
                break;
        case 0x600:
-               current_cpu_data.type = CPU_SH4_202;
-               current_cpu_data.icache.ways = 2;
-               current_cpu_data.dcache.ways = 2;
-               current_cpu_data.flags |= CPU_HAS_FPU;
+               boot_cpu_data.type = CPU_SH4_202;
+               boot_cpu_data.icache.ways = 2;
+               boot_cpu_data.dcache.ways = 2;
+               boot_cpu_data.flags |= CPU_HAS_FPU;
                break;
        case 0x500 ... 0x501:
                switch (prr) {
                case 0x10:
-                       current_cpu_data.type = CPU_SH7750R;
+                       boot_cpu_data.type = CPU_SH7750R;
                        break;
                case 0x11:
-                       current_cpu_data.type = CPU_SH7751R;
+                       boot_cpu_data.type = CPU_SH7751R;
                        break;
                case 0x50 ... 0x5f:
-                       current_cpu_data.type = CPU_SH7760;
+                       boot_cpu_data.type = CPU_SH7760;
                        break;
                }
 
-               current_cpu_data.icache.ways = 2;
-               current_cpu_data.dcache.ways = 2;
+               boot_cpu_data.icache.ways = 2;
+               boot_cpu_data.dcache.ways = 2;
 
-               current_cpu_data.flags |= CPU_HAS_FPU;
+               boot_cpu_data.flags |= CPU_HAS_FPU;
 
                break;
        default:
-               current_cpu_data.type = CPU_SH_NONE;
+               boot_cpu_data.type = CPU_SH_NONE;
                break;
        }
 
 #ifdef CONFIG_SH_DIRECT_MAPPED
-       current_cpu_data.icache.ways = 1;
-       current_cpu_data.dcache.ways = 1;
+       boot_cpu_data.icache.ways = 1;
+       boot_cpu_data.dcache.ways = 1;
 #endif
 
 #ifdef CONFIG_CPU_HAS_PTEA
-       current_cpu_data.flags |= CPU_HAS_PTEA;
+       boot_cpu_data.flags |= CPU_HAS_PTEA;
 #endif
 
        /*
         * On anything that's not a direct-mapped cache, look to the CVR
         * for I/D-cache specifics.
         */
-       if (current_cpu_data.icache.ways > 1) {
+       if (boot_cpu_data.icache.ways > 1) {
                size = sizes[(cvr >> 20) & 0xf];
-               current_cpu_data.icache.way_incr        = (size >> 1);
-               current_cpu_data.icache.sets            = (size >> 6);
+               boot_cpu_data.icache.way_incr   = (size >> 1);
+               boot_cpu_data.icache.sets       = (size >> 6);
 
        }
 
        /* And the rest of the D-cache */
-       if (current_cpu_data.dcache.ways > 1) {
+       if (boot_cpu_data.dcache.ways > 1) {
                size = sizes[(cvr >> 16) & 0xf];
-               current_cpu_data.dcache.way_incr        = (size >> 1);
-               current_cpu_data.dcache.sets            = (size >> 6);
+               boot_cpu_data.dcache.way_incr   = (size >> 1);
+               boot_cpu_data.dcache.sets       = (size >> 6);
        }
 
        /*
@@ -218,7 +214,7 @@ int __init detect_cpu_and_cache_system(void)
         *
         * SH-4A's have an optional PIPT L2.
         */
-       if (current_cpu_data.flags & CPU_HAS_L2_CACHE) {
+       if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) {
                /*
                 * Size calculation is much more sensible
                 * than it is for the L1.
@@ -229,22 +225,22 @@ int __init detect_cpu_and_cache_system(void)
 
                BUG_ON(!size);
 
-               current_cpu_data.scache.way_incr        = (1 << 16);
-               current_cpu_data.scache.entry_shift     = 5;
-               current_cpu_data.scache.ways            = 4;
-               current_cpu_data.scache.linesz          = L1_CACHE_BYTES;
+               boot_cpu_data.scache.way_incr           = (1 << 16);
+               boot_cpu_data.scache.entry_shift        = 5;
+               boot_cpu_data.scache.ways               = 4;
+               boot_cpu_data.scache.linesz             = L1_CACHE_BYTES;
 
-               current_cpu_data.scache.entry_mask      =
-                       (current_cpu_data.scache.way_incr -
-                        current_cpu_data.scache.linesz);
+               boot_cpu_data.scache.entry_mask =
+                       (boot_cpu_data.scache.way_incr -
+                        boot_cpu_data.scache.linesz);
 
-               current_cpu_data.scache.sets            = size /
-                       (current_cpu_data.scache.linesz *
-                        current_cpu_data.scache.ways);
+               boot_cpu_data.scache.sets       = size /
+                       (boot_cpu_data.scache.linesz *
+                        boot_cpu_data.scache.ways);
 
-               current_cpu_data.scache.way_size        =
-                       (current_cpu_data.scache.sets *
-                        current_cpu_data.scache.linesz);
+               boot_cpu_data.scache.way_size   =
+                       (boot_cpu_data.scache.sets *
+                        boot_cpu_data.scache.linesz);
        }
 
        return 0;
index f2286de22bd5abe1718f402d72230d6f3364d9dc..523f68a9ce0e427e100dee5f52c15595a39cf1b9 100644 (file)
@@ -104,7 +104,7 @@ enum {
        DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
 };
 
-static struct intc_vect vectors[] = {
+static struct intc_vect vectors[] __initdata = {
        INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
        INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
        INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
@@ -118,7 +118,7 @@ static struct intc_vect vectors[] = {
        INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
 };
 
-static struct intc_group groups[] = {
+static struct intc_group groups[] __initdata = {
        INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
        INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
        INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
@@ -126,20 +126,20 @@ static struct intc_group groups[] = {
        INTC_GROUP(REF, REF_RCMI, REF_ROVI),
 };
 
-static struct intc_prio priorities[] = {
+static struct intc_prio priorities[] __initdata = {
        INTC_PRIO(SCIF, 3),
        INTC_PRIO(SCI1, 3),
        INTC_PRIO(DMAC, 7),
 };
 
-static struct intc_prio_reg prio_registers[] = {
-       { 0xffd00004, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
-       { 0xffd00008, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
-       { 0xffd0000c, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
-       { 0xffd00010, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
-       { 0xfe080000, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
-                                             TMU4, TMU3,
-                                             PCIC1, PCIC0_PCISERR } },
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+       { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
+       { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+       { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
+                                                TMU4, TMU3,
+                                                PCIC1, PCIC0_PCISERR } },
 };
 
 static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
@@ -150,13 +150,13 @@ static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
        defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
        defined(CONFIG_CPU_SUBTYPE_SH7751) || \
        defined(CONFIG_CPU_SUBTYPE_SH7091)
-static struct intc_vect vectors_dma4[] = {
+static struct intc_vect vectors_dma4[] __initdata = {
        INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
        INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
        INTC_VECT(DMAC_DMAE, 0x6c0),
 };
 
-static struct intc_group groups_dma4[] = {
+static struct intc_group groups_dma4[] __initdata = {
        INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
                   DMAC_DMTE3, DMAC_DMAE),
 };
@@ -168,7 +168,7 @@ static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
 
 /* SH7750R and SH7751R both have 8-channel DMA controllers */
 #if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
-static struct intc_vect vectors_dma8[] = {
+static struct intc_vect vectors_dma8[] __initdata = {
        INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
        INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
        INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
@@ -176,7 +176,7 @@ static struct intc_vect vectors_dma8[] = {
        INTC_VECT(DMAC_DMAE, 0x6c0),
 };
 
-static struct intc_group groups_dma8[] = {
+static struct intc_group groups_dma8[] __initdata = {
        INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
                   DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
                   DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
@@ -191,11 +191,11 @@ static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
 #if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
        defined(CONFIG_CPU_SUBTYPE_SH7751) || \
        defined(CONFIG_CPU_SUBTYPE_SH7751R)
-static struct intc_vect vectors_tmu34[] = {
+static struct intc_vect vectors_tmu34[] __initdata = {
        INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
 };
 
-static struct intc_mask_reg mask_registers[] = {
+static struct intc_mask_reg mask_registers[] __initdata = {
        { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
          { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, TMU4, TMU3,
@@ -210,7 +210,7 @@ static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
 #endif
 
 /* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
-static struct intc_vect vectors_irlm[] = {
+static struct intc_vect vectors_irlm[] __initdata = {
        INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
        INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
 };
@@ -220,14 +220,14 @@ static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
 
 /* SH7751 and SH7751R both have PCI */
 #if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
-static struct intc_vect vectors_pci[] = {
+static struct intc_vect vectors_pci[] __initdata = {
        INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
        INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
        INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
        INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
 };
 
-static struct intc_group groups_pci[] = {
+static struct intc_group groups_pci[] __initdata = {
        INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
                   PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
 };
@@ -282,13 +282,19 @@ void __init plat_irq_setup(void)
 #define INTC_ICR       0xffd00000UL
 #define INTC_ICR_IRLM   (1<<7)
 
-/* enable individual interrupt mode for external interupts */
-void __init ipr_irq_enable_irlm(void)
+void __init plat_irq_setup_pins(int mode)
 {
 #if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091)
        BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */
+       return;
 #endif
-       register_intc_controller(&intc_desc_irlm);
 
-       ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+       switch (mode) {
+       case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */
+               ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+               register_intc_controller(&intc_desc_irlm);
+               break;
+       default:
+               BUG();
+       }
 }
index 47fa270562537360d860d7adfea51b7d16d942d9..7a898cb1d94091a06672456c254a3754b0db5089 100644 (file)
 #include <linux/serial.h>
 #include <asm/sci.h>
 
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRL0, IRL1, IRL2, IRL3,
+       HUDI, GPIOI,
+       DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
+       DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
+       DMAC_DMAE,
+       IRQ4, IRQ5, IRQ6, IRQ7,
+       HCAN20, HCAN21,
+       SSI0, SSI1,
+       HAC0, HAC1,
+       I2C0, I2C1,
+       USB, LCDC,
+       DMABRG0, DMABRG1, DMABRG2,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+       SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+       SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+       HSPI,
+       MMCIF0, MMCIF1, MMCIF2, MMCIF3,
+       MFI, ADC, CMT,
+       TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+       WDT,
+       REF_RCMI, REF_ROVI,
+
+       /* interrupt groups */
+       DMAC, DMABRG, SCIF0, SCIF1, SCIF2, SIM, MMCIF, TMU2, REF,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
+       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+       INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
+       INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
+       INTC_VECT(DMAC_DMAE, 0x6c0),
+       INTC_VECT(IRQ4, 0x800), INTC_VECT(IRQ5, 0x820),
+       INTC_VECT(IRQ6, 0x840), INTC_VECT(IRQ6, 0x860),
+       INTC_VECT(HCAN20, 0x900), INTC_VECT(HCAN21, 0x920),
+       INTC_VECT(SSI0, 0x940), INTC_VECT(SSI1, 0x960),
+       INTC_VECT(HAC0, 0x980), INTC_VECT(HAC1, 0x9a0),
+       INTC_VECT(I2C0, 0x9c0), INTC_VECT(I2C1, 0x9e0),
+       INTC_VECT(USB, 0xa00), INTC_VECT(LCDC, 0xa20),
+       INTC_VECT(DMABRG0, 0xa80), INTC_VECT(DMABRG1, 0xaa0),
+       INTC_VECT(DMABRG2, 0xac0),
+       INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
+       INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
+       INTC_VECT(SCIF1_ERI, 0xb00), INTC_VECT(SCIF1_RXI, 0xb20),
+       INTC_VECT(SCIF1_BRI, 0xb40), INTC_VECT(SCIF1_TXI, 0xb60),
+       INTC_VECT(SCIF2_ERI, 0xb80), INTC_VECT(SCIF2_RXI, 0xba0),
+       INTC_VECT(SCIF2_BRI, 0xbc0), INTC_VECT(SCIF2_TXI, 0xbe0),
+       INTC_VECT(SIM_ERI, 0xc00), INTC_VECT(SIM_RXI, 0xc20),
+       INTC_VECT(SIM_TXI, 0xc40), INTC_VECT(SIM_TEI, 0xc60),
+       INTC_VECT(HSPI, 0xc80),
+       INTC_VECT(MMCIF0, 0xd00), INTC_VECT(MMCIF1, 0xd20),
+       INTC_VECT(MMCIF2, 0xd40), INTC_VECT(MMCIF3, 0xd60),
+       INTC_VECT(MFI, 0xe80), /* 0xf80 according to data sheet */
+       INTC_VECT(ADC, 0xf80), INTC_VECT(CMT, 0xfa0),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+                  DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
+                  DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+       INTC_GROUP(DMABRG, DMABRG0, DMABRG1, DMABRG2),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+       INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
+       INTC_GROUP(MMCIF, MMCIF0, MMCIF1, MMCIF2, MMCIF3),
+       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+       INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+};
+
+static struct intc_prio priorities[] __initdata = {
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+       INTC_PRIO(SCIF2, 3),
+       INTC_PRIO(SIM, 3),
+       INTC_PRIO(DMAC, 7),
+       INTC_PRIO(DMABRG, 13),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+         { IRQ4, IRQ5, IRQ6, IRQ7, 0, 0, HCAN20, HCAN21,
+           SSI0, SSI1, HAC0, HAC1, I2C0, I2C1, USB, LCDC,
+           0, DMABRG0, DMABRG1, DMABRG2,
+           SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+           SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+           SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, } },
+       { 0xfe080044, 0xfe080064, 32, /* INTMSK04 / INTMSKCLR04 */
+         { 0, 0, 0, 0, 0, 0, 0, 0,
+           SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+           HSPI, MMCIF0, MMCIF1, MMCIF2,
+           MMCIF3, 0, 0, 0, 0, 0, 0, 0,
+           0, MFI, 0, 0, 0, 0, ADC, CMT, } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2 } },
+       { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
+       { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, 0, HUDI } },
+       { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+       { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { 0xfe080004, 0, 32, 4, /* INTPRI04 */ { HCAN20, HCAN21, SSI0, SSI1,
+                                                HAC0, HAC1, I2C0, I2C1 } },
+       { 0xfe080008, 0, 32, 4, /* INTPRI08 */ { USB, LCDC, DMABRG, SCIF0,
+                                                SCIF1, SCIF2, SIM, HSPI } },
+       { 0xfe08000c, 0, 32, 4, /* INTPRI0C */ { 0, 0, MMCIF, 0,
+                                                MFI, 0, ADC, CMT } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7760", vectors, groups,
+                        priorities, mask_registers, prio_registers, NULL);
+
+static struct intc_vect vectors_irq[] __initdata = {
+       INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+       INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq, "sh7760-irq", vectors_irq, groups,
+                        priorities, mask_registers, prio_registers, NULL);
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xfe600000,
@@ -28,6 +158,11 @@ static struct plat_sci_port sci_platform_data[] = {
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
                .irqs           = { 76, 77, 79, 78 },
+       }, {
+               .mapbase        = 0xfe480000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCI,
+               .irqs           = { 80, 81, 82, 0 },
        }, {
                .flags = 0,
        }
@@ -52,114 +187,18 @@ static int __init sh7760_devices_setup(void)
 }
 __initcall(sh7760_devices_setup);
 
-static struct intc2_data intc2_irq_table[] = {
-       {48,  0, 28, 0, 31,  3},        /* IRQ 4 */
-       {49,  0, 24, 0, 30,  3},        /* IRQ 3 */
-       {50,  0, 20, 0, 29,  3},        /* IRQ 2 */
-       {51,  0, 16, 0, 28,  3},        /* IRQ 1 */
-       {56,  4, 28, 0, 25,  3},        /* HCAN2_CHAN0 */
-       {57,  4, 24, 0, 24,  3},        /* HCAN2_CHAN1 */
-       {58,  4, 20, 0, 23,  3},        /* I2S_CHAN0   */
-       {59,  4, 16, 0, 22,  3},        /* I2S_CHAN1   */
-       {60,  4, 12, 0, 21,  3},        /* AC97_CHAN0  */
-       {61,  4,  8, 0, 20,  3},        /* AC97_CHAN1  */
-       {62,  4,  4, 0, 19,  3},        /* I2C_CHAN0   */
-       {63,  4,  0, 0, 18,  3},        /* I2C_CHAN1   */
-       {52,  8, 16, 0, 11,  3},        /* SCIF0_ERI_IRQ */
-       {53,  8, 16, 0, 10,  3},        /* SCIF0_RXI_IRQ */
-       {54,  8, 16, 0,  9,  3},        /* SCIF0_BRI_IRQ */
-       {55,  8, 16, 0,  8,  3},        /* SCIF0_TXI_IRQ */
-       {64,  8, 28, 0, 17,  3},        /* USBHI_IRQ */
-       {65,  8, 24, 0, 16,  3},        /* LCDC      */
-       {68,  8, 20, 0, 14, 13},        /* DMABRGI0_IRQ */
-       {69,  8, 20, 0, 13, 13},        /* DMABRGI1_IRQ */
-       {70,  8, 20, 0, 12, 13},        /* DMABRGI2_IRQ */
-       {72,  8, 12, 0,  7,  3},        /* SCIF1_ERI_IRQ */
-       {73,  8, 12, 0,  6,  3},        /* SCIF1_RXI_IRQ */
-       {74,  8, 12, 0,  5,  3},        /* SCIF1_BRI_IRQ */
-       {75,  8, 12, 0,  4,  3},        /* SCIF1_TXI_IRQ */
-       {76,  8,  8, 0,  3,  3},        /* SCIF2_ERI_IRQ */
-       {77,  8,  8, 0,  2,  3},        /* SCIF2_RXI_IRQ */
-       {78,  8,  8, 0,  1,  3},        /* SCIF2_BRI_IRQ */
-       {79,  8,  8, 0,  0,  3},        /* SCIF2_TXI_IRQ */
-       {80,  8,  4, 4, 23,  3},        /* SIM_ERI */
-       {81,  8,  4, 4, 22,  3},        /* SIM_RXI */
-       {82,  8,  4, 4, 21,  3},        /* SIM_TXI */
-       {83,  8,  4, 4, 20,  3},        /* SIM_TEI */
-       {84,  8,  0, 4, 19,  3},        /* HSPII */
-       {88, 12, 20, 4, 18,  3},        /* MMCI0 */
-       {89, 12, 20, 4, 17,  3},        /* MMCI1 */
-       {90, 12, 20, 4, 16,  3},        /* MMCI2 */
-       {91, 12, 20, 4, 15,  3},        /* MMCI3 */
-       {92, 12, 12, 4,  6,  3},        /* MFI */
-       {108,12,  4, 4,  1,  3},        /* ADC  */
-       {109,12,  0, 4,  0,  3},        /* CMTI */
-};
-
-static struct intc2_desc intc2_irq_desc __read_mostly = {
-       .prio_base      = 0xfe080000,
-       .msk_base       = 0xfe080040,
-       .mskclr_base    = 0xfe080060,
-
-       .intc2_data     = intc2_irq_table,
-       .nr_irqs        = ARRAY_SIZE(intc2_irq_table),
-
-       .chip = {
-               .name   = "INTC2-sh7760",
-       },
-};
-
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR-idx, shift, priority */
-       { 16, 0, 12, 2 }, /* TMU0 TUNI*/
-       { 17, 0,  8, 2 }, /* TMU1 TUNI */
-       { 18, 0,  4, 2 }, /* TMU2 TUNI */
-       { 19, 0,  4, 2 }, /* TMU2 TIPCI */
-       { 27, 1, 12, 2 }, /* WDT ITI */
-       { 28, 1,  8, 2 }, /* REF RCMI */
-       { 29, 1,  8, 2 }, /* REF ROVI */
-       { 32, 2,  0, 7 }, /* HUDI */
-       { 33, 2, 12, 7 }, /* GPIOI */
-       { 34, 2,  8, 7 }, /* DMAC DMTE0 */
-       { 35, 2,  8, 7 }, /* DMAC DMTE1 */
-       { 36, 2,  8, 7 }, /* DMAC DMTE2 */
-       { 37, 2,  8, 7 }, /* DMAC DMTE3 */
-       { 38, 2,  8, 7 }, /* DMAC DMAE */
-       { 44, 2,  8, 7 }, /* DMAC DMTE4 */
-       { 45, 2,  8, 7 }, /* DMAC DMTE5 */
-       { 46, 2,  8, 7 }, /* DMAC DMTE6 */
-       { 47, 2,  8, 7 }, /* DMAC DMTE7 */
-/* these here are only valid if INTC_ICR bit 7 is set to 1!
- * XXX: maybe CONFIG_SH_IRLMODE symbol? SH7751 could use it too */
-#if 0
-       {  2, 3, 12, 3 }, /* IRL0 */
-       {  5, 3,  8, 3 }, /* IRL1 */
-       {  8, 3,  4, 3 }, /* IRL2 */
-       { 11, 3,  0, 3 }, /* IRL3 */
-#endif
-};
-
-static unsigned long ipr_offsets[] = {
-       0xffd00004UL,   /* 0: IPRA */
-       0xffd00008UL,   /* 1: IPRB */
-       0xffd0000cUL,   /* 2: IPRC */
-       0xffd00010UL,   /* 3: IPRD */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7760",
-       },
-};
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ:
+               register_intc_controller(&intc_desc_irq);
+               break;
+       default:
+               BUG();
+       }
+}
 
 void __init plat_irq_setup(void)
 {
-       register_intc2_controller(&intc2_irq_desc);
-       register_ipr_controller(&ipr_irq_desc);
+       register_intc_controller(&intc_desc);
 }
index c21512c6044e790a815458b7833d48a7b7ce9639..b22a78c807e6bb012ba2f4289673176c598e8453 100644 (file)
@@ -58,11 +58,11 @@ do {                                                \
  */
 void sq_flush_range(unsigned long start, unsigned int len)
 {
-       volatile unsigned long *sq = (unsigned long *)start;
+       unsigned long *sq = (unsigned long *)start;
 
        /* Flush the queues */
        for (len >>= 5; len--; sq += 8)
-               prefetchw((void *)sq);
+               prefetchw(sq);
 
        /* Wait for completion */
        store_queue_barrier();
index e6a1fb5f8484f91351fecf19bb02ee672d754162..24539873943ab1476922dbbb6a27713923be9d60 100644 (file)
@@ -10,6 +10,9 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7343)      += setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SHX3)         += setup-shx3.o
 
+# SMP setup
+smp-$(CONFIG_CPU_SUBTYPE_SHX3)         := smp-shx3.o
+
 # Primary on-chip clocks (common)
 clock-$(CONFIG_CPU_SUBTYPE_SH7770)     := clock-sh7770.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7780)     := clock-sh7780.o
@@ -18,4 +21,5 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7343)    := clock-sh7343.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o
 clock-$(CONFIG_CPU_SUBTYPE_SHX3)       := clock-shx3.o
 
-obj-y  += $(clock-y)
+obj-y                  += $(clock-y)
+obj-$(CONFIG_SMP)      += $(smp-y)
index 91d61cf91ba17b8ec92efef4c20888f529290edb..c0a3f079dfdcda8565c1d3e83394d9b7930c70ac 100644 (file)
@@ -41,3 +41,7 @@ static int __init sh7343_devices_setup(void)
                                    ARRAY_SIZE(sh7343_devices));
 }
 __initcall(sh7343_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+}
index 25b913e07e2ca3984e066c43987fe0101082723c..55f66104431db8cbe97b144c224be5c97e4155eb 100644 (file)
@@ -84,7 +84,7 @@ enum {
        SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI,
 };
 
-static struct intc_vect vectors[] = {
+static struct intc_vect vectors[] __initdata = {
        INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
        INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
        INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
@@ -117,7 +117,7 @@ static struct intc_vect vectors[] = {
        INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
 };
 
-static struct intc_group groups[] = {
+static struct intc_group groups[] __initdata = {
        INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
        INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
        INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
@@ -130,7 +130,7 @@ static struct intc_group groups[] = {
        INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
 };
 
-static struct intc_prio priorities[] = {
+static struct intc_prio priorities[] __initdata = {
        INTC_PRIO(SCIF0, 3),
        INTC_PRIO(SCIF1, 3),
        INTC_PRIO(SCIF2, 3),
@@ -138,7 +138,7 @@ static struct intc_prio priorities[] = {
        INTC_PRIO(TMU1, 2),
 };
 
-static struct intc_mask_reg mask_registers[] = {
+static struct intc_mask_reg mask_registers[] __initdata = {
        { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
          { } },
        { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
@@ -168,24 +168,24 @@ static struct intc_mask_reg mask_registers[] = {
          { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-static struct intc_prio_reg prio_registers[] = {
-       { 0xa4080000, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
-       { 0xa4080004, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
-       { 0xa4080008, 16, 4, /* IPRC */ { } },
-       { 0xa408000c, 16, 4, /* IPRD */ { } },
-       { 0xa4080010, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
-       { 0xa4080014, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
-       { 0xa4080018, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
-       { 0xa408001c, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
-       { 0xa4080020, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
-       { 0xa4080024, 16, 4, /* IPRJ */ { 0, 0, SIU } },
-       { 0xa4080028, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
-       { 0xa408002c, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
-       { 0xa4140010, 32, 4, /* INTPRI00 */
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
+       { 0xa4080004, 0, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
+       { 0xa4080008, 0, 16, 4, /* IPRC */ { } },
+       { 0xa408000c, 0, 16, 4, /* IPRD */ { } },
+       { 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
+       { 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
+       { 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
+       { 0xa408001c, 0, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
+       { 0xa4080020, 0, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
+       { 0xa4080024, 0, 16, 4, /* IPRJ */ { 0, 0, SIU } },
+       { 0xa4080028, 0, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
+       { 0xa408002c, 0, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
+       { 0xa4140010, 0, 32, 4, /* INTPRI00 */
          { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-static struct intc_sense_reg sense_registers[] = {
+static struct intc_sense_reg sense_registers[] __initdata = {
        { 0xa414001c, 16, 2, /* ICR1 */
          { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
index 6a04cc5f5aca402a9a22abf6a2d0b3eade09b192..32f4f59a837b41ca36329488597177f6aa1573ef 100644 (file)
@@ -51,3 +51,7 @@ static int __init sh7770_devices_setup(void)
                                    ARRAY_SIZE(sh7770_devices));
 }
 __initcall(sh7770_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+}
index a4127ec15203dc78352cc24060edafb3db02611c..e8fd33ff0605df505cf328a78e9c70705bc9a252 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/serial.h>
+#include <linux/io.h>
 #include <asm/sci.h>
 
 static struct resource rtc_resources[] = {
@@ -114,7 +115,7 @@ enum {
        PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO,
 };
 
-static struct intc_vect vectors[] = {
+static struct intc_vect vectors[] __initdata = {
        INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
        INTC_VECT(RTC_CUI, 0x4c0),
        INTC_VECT(WDT, 0x560),
@@ -150,7 +151,7 @@ static struct intc_vect vectors[] = {
        INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
 };
 
-static struct intc_group groups[] = {
+static struct intc_group groups[] __initdata = {
        INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
        INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
        INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
@@ -167,12 +168,12 @@ static struct intc_group groups[] = {
        INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
 };
 
-static struct intc_prio priorities[] = {
+static struct intc_prio priorities[] __initdata = {
        INTC_PRIO(SCIF0, 3),
        INTC_PRIO(SCIF1, 3),
 };
 
-static struct intc_mask_reg mask_registers[] = {
+static struct intc_mask_reg mask_registers[] __initdata = {
        { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
          { 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
            SSI, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
@@ -180,16 +181,18 @@ static struct intc_mask_reg mask_registers[] = {
            HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
 };
 
-static struct intc_prio_reg prio_registers[] = {
-       { 0xffd40000, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, TMU2, TMU2_TICPI } },
-       { 0xffd40004, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
-       { 0xffd40008, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
-       { 0xffd4000c, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
-       { 0xffd40010, 32, 8, /* INT2PRI4 */ { CMT, HAC, PCISERR, PCIINTA, } },
-       { 0xffd40014, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
-                                             PCIINTD, PCIC5 } },
-       { 0xffd40018, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
-       { 0xffd4001c, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1,
+                                                TMU2, TMU2_TICPI } },
+       { 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
+       { 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
+       { 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
+       { 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { CMT, HAC,
+                                                PCISERR, PCIINTA, } },
+       { 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
+                                                PCIINTD, PCIC5 } },
+       { 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
+       { 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
 };
 
 static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
@@ -197,24 +200,24 @@ static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
 
 /* Support for external interrupt pins in IRQ mode */
 
-static struct intc_vect irq_vectors[] = {
+static struct intc_vect irq_vectors[] __initdata = {
        INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
        INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
        INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
        INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
 };
 
-static struct intc_mask_reg irq_mask_registers[] = {
+static struct intc_mask_reg irq_mask_registers[] __initdata = {
        { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
          { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-static struct intc_prio_reg irq_prio_registers[] = {
-       { 0xffd00010, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
-                                           IRQ4, IRQ5, IRQ6, IRQ7 } },
+static struct intc_prio_reg irq_prio_registers[] __initdata = {
+       { 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+                                              IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-static struct intc_sense_reg irq_sense_registers[] = {
+static struct intc_sense_reg irq_sense_registers[] __initdata = {
        { 0xffd0001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
                                            IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
@@ -225,7 +228,7 @@ static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
 
 /* External interrupt pins in IRL mode */
 
-static struct intc_vect irl_vectors[] = {
+static struct intc_vect irl_vectors[] __initdata = {
        INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
        INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
        INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
@@ -236,16 +239,16 @@ static struct intc_vect irl_vectors[] = {
        INTC_VECT(IRL_HHHL, 0x3c0),
 };
 
-static struct intc_mask_reg irl3210_mask_registers[] = {
-       { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+static struct intc_mask_reg irl3210_mask_registers[] __initdata = {
+       { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
          { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
            IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
            IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
            IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
 };
 
-static struct intc_mask_reg irl7654_mask_registers[] = {
-       { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+static struct intc_mask_reg irl7654_mask_registers[] __initdata = {
+       { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
          { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
            IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
@@ -259,8 +262,28 @@ static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
 static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
                         NULL, NULL, irl3210_mask_registers, NULL, NULL);
 
+#define INTC_ICR0      0xffd00000
+#define INTC_INTMSK0   0xffd00044
+#define INTC_INTMSK1   0xffd00048
+#define INTC_INTMSK2   0xffd40080
+#define INTC_INTMSKCLR1        0xffd00068
+#define INTC_INTMSKCLR2        0xffd40084
+
 void __init plat_irq_setup(void)
 {
+       /* disable IRQ7-0 */
+       ctrl_outl(0xff000000, INTC_INTMSK0);
+
+       /* disable IRL3-0 + IRL7-4 */
+       ctrl_outl(0xc0000000, INTC_INTMSK1);
+       ctrl_outl(0xfffefffe, INTC_INTMSK2);
+
+       /* select IRL mode for IRL3-0 + IRL7-4 */
+       ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
+
+       /* disable holding function, ie enable "SH-4 Mode" */
+       ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
        register_intc_controller(&intc_desc);
 }
 
@@ -268,12 +291,28 @@ void __init plat_irq_setup_pins(int mode)
 {
        switch (mode) {
        case IRQ_MODE_IRQ:
+               /* select IRQ mode for IRL3-0 + IRL7-4 */
+               ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0);
                register_intc_controller(&intc_irq_desc);
                break;
        case IRQ_MODE_IRL7654:
-               register_intc_controller(&intc_irl7654_desc);
+               /* enable IRL7-4 but don't provide any masking */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
                break;
        case IRQ_MODE_IRL3210:
+               /* enable IRL0-3 but don't provide any masking */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+               ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+               break;
+       case IRQ_MODE_IRL7654_MASK:
+               /* enable IRL7-4 and mask using cpu intc controller */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               register_intc_controller(&intc_irl7654_desc);
+               break;
+       case IRQ_MODE_IRL3210_MASK:
+               /* enable IRL0-3 and mask using cpu intc controller */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
                register_intc_controller(&intc_irl3210_desc);
                break;
        default:
index cf047562e43fd59fd60b4aa90acd0fb5497122be..39b215d6cee54b082f884e99773755f59fca0688 100644 (file)
@@ -10,6 +10,9 @@
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <asm/mmzone.h>
 #include <asm/sci.h>
 
 static struct plat_sci_port sci_platform_data[] = {
@@ -72,46 +75,281 @@ static int __init sh7785_devices_setup(void)
 }
 __initcall(sh7785_devices_setup);
 
-static struct intc2_data intc2_irq_table[] = {
-       { 28, 0, 24, 0, 0, 2 },         /* TMU0 */
-
-       { 40, 8, 24, 0, 2, 3 },         /* SCIF0 ERI */
-       { 41, 8, 24, 0, 2, 3 },         /* SCIF0 RXI */
-       { 42, 8, 24, 0, 2, 3 },         /* SCIF0 BRI */
-       { 43, 8, 24, 0, 2, 3 },         /* SCIF0 TXI */
-
-       { 44, 8, 16, 0, 3, 3 },         /* SCIF1 ERI */
-       { 45, 8, 16, 0, 3, 3 },         /* SCIF1 RXI */
-       { 46, 8, 16, 0, 3, 3 },         /* SCIF1 BRI */
-       { 47, 8, 16, 0, 3, 3 },         /* SCIF1 TXI */
-
-       { 64, 0x14,  8, 0, 14, 2 },     /* PCIC0 */
-       { 65, 0x14,  0, 0, 15, 2 },     /* PCIC1 */
-       { 66, 0x18, 24, 0, 16, 2 },     /* PCIC2 */
-       { 67, 0x18, 16, 0, 17, 2 },     /* PCIC3 */
-       { 68, 0x18,  8, 0, 18, 2 },     /* PCIC4 */
-
-       { 60,  8,  8, 0, 4, 3 },        /* SCIF2 ERI, RXI, BRI, TXI */
-       { 60,  8,  0, 0, 5, 3 },        /* SCIF3 ERI, RXI, BRI, TXI */
-       { 60, 12, 24, 0, 6, 3 },        /* SCIF4 ERI, RXI, BRI, TXI */
-       { 60, 12, 16, 0, 7, 3 },        /* SCIF5 ERI, RXI, BRI, TXI */
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+
+       IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+       IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+       IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+       IRL0_HHLL, IRL0_HHLH, IRL0_HHHL,
+
+       IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH,
+       IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH,
+       IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH,
+       IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
+
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       WDT,
+       TMU0, TMU1, TMU2, TMU2_TICPI,
+       HUDI,
+       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3,
+       DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+       DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, DMAC1_DMINT9,
+       DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE,
+       HSPI,
+       SCIF2, SCIF3, SCIF4, SCIF5,
+       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
+       PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
+       SIOF,
+       MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
+       DU,
+       GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI,
+       TMU3, TMU4, TMU5,
+       SSI0, SSI1,
+       HAC0, HAC1,
+       FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
+       GPIOI0, GPIOI1, GPIOI2, GPIOI3,
+
+       /* interrupt groups */
+
+       TMU012, DMAC0, SCIF0, SCIF1, DMAC1,
+       PCIC5, MMCIF, GDTA, TMU345, FLCTL, GPIO
 };
 
-static struct intc2_desc intc2_irq_desc __read_mostly = {
-       .prio_base      = 0xffd40000,
-       .msk_base       = 0xffd40038,
-       .mskclr_base    = 0xffd4003c,
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
+       INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
+       INTC_VECT(HUDI, 0x600),
+       INTC_VECT(DMAC0_DMINT0, 0x620), INTC_VECT(DMAC0_DMINT1, 0x640),
+       INTC_VECT(DMAC0_DMINT2, 0x660), INTC_VECT(DMAC0_DMINT3, 0x680),
+       INTC_VECT(DMAC0_DMINT4, 0x6a0), INTC_VECT(DMAC0_DMINT5, 0x6c0),
+       INTC_VECT(DMAC0_DMAE, 0x6e0),
+       INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+       INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+       INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
+       INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
+       INTC_VECT(DMAC1_DMINT6, 0x880), INTC_VECT(DMAC1_DMINT7, 0x8a0),
+       INTC_VECT(DMAC1_DMINT8, 0x8c0), INTC_VECT(DMAC1_DMINT9, 0x8e0),
+       INTC_VECT(DMAC1_DMINT10, 0x900), INTC_VECT(DMAC1_DMINT11, 0x920),
+       INTC_VECT(DMAC1_DMAE, 0x940),
+       INTC_VECT(HSPI, 0x960),
+       INTC_VECT(SCIF2, 0x980), INTC_VECT(SCIF3, 0x9a0),
+       INTC_VECT(SCIF4, 0x9c0), INTC_VECT(SCIF5, 0x9e0),
+       INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
+       INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
+       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
+       INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
+       INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+       INTC_VECT(SIOF, 0xc00),
+       INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
+       INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+       INTC_VECT(DU, 0xd80),
+       INTC_VECT(GDTA_GACLI, 0xda0), INTC_VECT(GDTA_GAMCI, 0xdc0),
+       INTC_VECT(GDTA_GAERI, 0xde0),
+       INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
+       INTC_VECT(TMU5, 0xe40),
+       INTC_VECT(SSI0, 0xe80), INTC_VECT(SSI1, 0xea0),
+       INTC_VECT(HAC0, 0xec0), INTC_VECT(HAC1, 0xee0),
+       INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
+       INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
+       INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
+       INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
+};
 
-       .intc2_data     = intc2_irq_table,
-       .nr_irqs        = ARRAY_SIZE(intc2_irq_table),
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
+       INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+                  DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+       INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+                  DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE),
+       INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
+       INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
+       INTC_GROUP(GDTA, GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI),
+       INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
+       INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
+                  FLCTL_FLTRQ0, FLCTL_FLTRQ1),
+       INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+};
 
-       .chip = {
-               .name   = "INTC2-sh7785",
-       },
+static struct intc_prio priorities[] __initdata = {
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+       INTC_PRIO(SCIF2, 3),
+       INTC_PRIO(SCIF3, 3),
+       INTC_PRIO(SCIF4, 3),
+       INTC_PRIO(SCIF5, 3),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+
+       { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
+         { IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+           IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+           IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+           IRL0_HHLL, IRL0_HHLH, IRL0_HHHL, 0,
+           IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH,
+           IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH,
+           IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH,
+           IRL4_HHLL, IRL4_HHLH, IRL4_HHHL, 0, } },
+
+       { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+         { 0, 0, 0, GDTA, DU, SSI0, SSI1, GPIO,
+           FLCTL, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
+           PCIINTA, PCISERR, HAC1, HAC0, DMAC1, DMAC0, HUDI, WDT,
+           SCIF5, SCIF4, SCIF3, SCIF2, SCIF1, SCIF0, TMU345, TMU012 } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xffd00010, 0, 32, 4, /* INTPRI */   { IRQ0, IRQ1, IRQ2, IRQ3,
+                                                IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1,
+                                                TMU2, TMU2_TICPI } },
+       { 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, } },
+       { 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1,
+                                                SCIF2, SCIF3 } },
+       { 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { SCIF4, SCIF5, WDT, } },
+       { 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { HUDI, DMAC0, DMAC1, } },
+       { 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { HAC0, HAC1,
+                                                PCISERR, PCIINTA } },
+       { 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { PCIINTB, PCIINTC,
+                                                PCIINTD, PCIC5 } },
+       { 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { SIOF, HSPI, MMCIF, } },
+       { 0xffd40020, 0, 32, 8, /* INT2PRI8 */ { FLCTL, GPIO, SSI0, SSI1, } },
+       { 0xffd40024, 0, 32, 8, /* INT2PRI9 */ { DU, GDTA, } },
 };
 
+static DECLARE_INTC_DESC(intc_desc, "sh7785", vectors, groups, priorities,
+                        mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect vectors_irq0123[] __initdata = {
+       INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+       INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+};
+
+static struct intc_vect vectors_irq4567[] __initdata = {
+       INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+       INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
+};
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+       { 0xffd0001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
+                                           IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc_irq0123, "sh7785-irq0123", vectors_irq0123,
+                        NULL, NULL, mask_registers, prio_registers,
+                        sense_registers);
+
+static DECLARE_INTC_DESC(intc_desc_irq4567, "sh7785-irq4567", vectors_irq4567,
+                        NULL, NULL, mask_registers, prio_registers,
+                        sense_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect vectors_irl0123[] __initdata = {
+       INTC_VECT(IRL0_LLLL, 0x200), INTC_VECT(IRL0_LLLH, 0x220),
+       INTC_VECT(IRL0_LLHL, 0x240), INTC_VECT(IRL0_LLHH, 0x260),
+       INTC_VECT(IRL0_LHLL, 0x280), INTC_VECT(IRL0_LHLH, 0x2a0),
+       INTC_VECT(IRL0_LHHL, 0x2c0), INTC_VECT(IRL0_LHHH, 0x2e0),
+       INTC_VECT(IRL0_HLLL, 0x300), INTC_VECT(IRL0_HLLH, 0x320),
+       INTC_VECT(IRL0_HLHL, 0x340), INTC_VECT(IRL0_HLHH, 0x360),
+       INTC_VECT(IRL0_HHLL, 0x380), INTC_VECT(IRL0_HHLH, 0x3a0),
+       INTC_VECT(IRL0_HHHL, 0x3c0),
+};
+
+static struct intc_vect vectors_irl4567[] __initdata = {
+       INTC_VECT(IRL4_LLLL, 0xb00), INTC_VECT(IRL4_LLLH, 0xb20),
+       INTC_VECT(IRL4_LLHL, 0xb40), INTC_VECT(IRL4_LLHH, 0xb60),
+       INTC_VECT(IRL4_LHLL, 0xb80), INTC_VECT(IRL4_LHLH, 0xba0),
+       INTC_VECT(IRL4_LHHL, 0xbc0), INTC_VECT(IRL4_LHHH, 0xbe0),
+       INTC_VECT(IRL4_HLLL, 0xc00), INTC_VECT(IRL4_HLLH, 0xc20),
+       INTC_VECT(IRL4_HLHL, 0xc40), INTC_VECT(IRL4_HLHH, 0xc60),
+       INTC_VECT(IRL4_HHLL, 0xc80), INTC_VECT(IRL4_HHLH, 0xca0),
+       INTC_VECT(IRL4_HHHL, 0xcc0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7785-irl0123", vectors_irl0123,
+                        NULL, NULL, mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7785-irl4567", vectors_irl4567,
+                        NULL, NULL, mask_registers, NULL, NULL);
+
+#define INTC_ICR0      0xffd00000
+#define INTC_INTMSK0   0xffd00044
+#define INTC_INTMSK1   0xffd00048
+#define INTC_INTMSK2   0xffd40080
+#define INTC_INTMSKCLR1        0xffd00068
+#define INTC_INTMSKCLR2        0xffd40084
+
 void __init plat_irq_setup(void)
 {
-       register_intc2_controller(&intc2_irq_desc);
+       /* disable IRQ3-0 + IRQ7-4 */
+       ctrl_outl(0xff000000, INTC_INTMSK0);
+
+       /* disable IRL3-0 + IRL7-4 */
+       ctrl_outl(0xc0000000, INTC_INTMSK1);
+       ctrl_outl(0xfffefffe, INTC_INTMSK2);
+
+       /* select IRL mode for IRL3-0 + IRL7-4 */
+       ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
+
+       /* disable holding function, ie enable "SH-4 Mode" */
+       ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
+       register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ7654:
+               /* select IRQ mode for IRL7-4 */
+               ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00400000, INTC_ICR0);
+               register_intc_controller(&intc_desc_irq4567);
+               break;
+       case IRQ_MODE_IRQ3210:
+               /* select IRQ mode for IRL3-0 */
+               ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00800000, INTC_ICR0);
+               register_intc_controller(&intc_desc_irq0123);
+               break;
+       case IRQ_MODE_IRL7654:
+               /* enable IRL7-4 but don't provide any masking */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
+               break;
+       case IRQ_MODE_IRL3210:
+               /* enable IRL0-3 but don't provide any masking */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+               ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+               break;
+       case IRQ_MODE_IRL7654_MASK:
+               /* enable IRL7-4 and mask using cpu intc controller */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               register_intc_controller(&intc_desc_irl4567);
+               break;
+       case IRQ_MODE_IRL3210_MASK:
+               /* enable IRL0-3 and mask using cpu intc controller */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+               register_intc_controller(&intc_desc_irl0123);
+               break;
+       default:
+               BUG();
+       }
 }
 
+void __init plat_mem_setup(void)
+{
+       /* Register the URAM space as Node 1 */
+       setup_bootmem_node(1, 0xe55f0000, 0xe5610000);
+}
index 704c064f70dc90ad58f5f7ef25843845b5d9ca2c..c6cdd7e3b0497e1453d2c912d8d1dd9d9fc77c28 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/io.h>
+#include <asm/mmzone.h>
 #include <asm/sci.h>
 
 static struct plat_sci_port sci_platform_data[] = {
@@ -58,28 +59,229 @@ static int __init shx3_devices_setup(void)
 }
 __initcall(shx3_devices_setup);
 
-static struct intc2_data intc2_irq_table[] = {
-       { 16, 0, 0, 0, 1, 2 },          /* TMU0 */
-       { 40, 4, 0, 0x20, 0, 3 },       /* SCIF0 ERI */
-       { 41, 4, 0, 0x20, 1, 3 },       /* SCIF0 RXI */
-       { 42, 4, 0, 0x20, 2, 3 },       /* SCIF0 BRI */
-       { 43, 4, 0, 0x20, 3, 3 },       /* SCIF0 TXI */
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+       IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+       IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+       IRL_HHLL, IRL_HHLH, IRL_HHHL,
+       IRQ0, IRQ1, IRQ2, IRQ3,
+       HUDII,
+       TMU0, TMU1, TMU2, TMU3, TMU4, TMU5,
+       PCII0, PCII1, PCII2, PCII3, PCII4,
+       PCII5, PCII6, PCII7, PCII8, PCII9,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+       SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+       SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI,
+       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3,
+       DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE,
+       DU,
+       DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, DMAC1_DMINT9,
+       DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE,
+       IIC, VIN0, VIN1, VCORE0, ATAPI,
+       DTU0_TEND, DTU0_AE, DTU0_TMISS,
+       DTU1_TEND, DTU1_AE, DTU1_TMISS,
+       DTU2_TEND, DTU2_AE, DTU2_TMISS,
+       DTU3_TEND, DTU3_AE, DTU3_TMISS,
+       FE0, FE1,
+       GPIO0, GPIO1, GPIO2, GPIO3,
+       PAM, IRM,
+       INTICI0, INTICI1, INTICI2, INTICI3,
+       INTICI4, INTICI5, INTICI6, INTICI7,
+
+       /* interrupt groups */
+       IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
+       DMAC0, DMAC1, DTU0, DTU1, DTU2, DTU3,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(HUDII, 0x3e0),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(TMU3, 0x460),
+       INTC_VECT(TMU4, 0x480), INTC_VECT(TMU5, 0x4a0),
+       INTC_VECT(PCII0, 0x500), INTC_VECT(PCII1, 0x520),
+       INTC_VECT(PCII2, 0x540), INTC_VECT(PCII3, 0x560),
+       INTC_VECT(PCII4, 0x580), INTC_VECT(PCII5, 0x5a0),
+       INTC_VECT(PCII6, 0x5c0), INTC_VECT(PCII7, 0x5e0),
+       INTC_VECT(PCII8, 0x600), INTC_VECT(PCII9, 0x620),
+       INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+       INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+       INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
+       INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
+       INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820),
+       INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860),
+       INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0),
+       INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0),
+       INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920),
+       INTC_VECT(DMAC0_DMINT2, 0x940), INTC_VECT(DMAC0_DMINT3, 0x960),
+       INTC_VECT(DMAC0_DMINT4, 0x980), INTC_VECT(DMAC0_DMINT5, 0x9a0),
+       INTC_VECT(DMAC0_DMAE, 0x9c0),
+       INTC_VECT(DU, 0x9e0),
+       INTC_VECT(DMAC1_DMINT6, 0xa00), INTC_VECT(DMAC1_DMINT7, 0xa20),
+       INTC_VECT(DMAC1_DMINT8, 0xa40), INTC_VECT(DMAC1_DMINT9, 0xa60),
+       INTC_VECT(DMAC1_DMINT10, 0xa80), INTC_VECT(DMAC1_DMINT11, 0xaa0),
+       INTC_VECT(DMAC1_DMAE, 0xac0),
+       INTC_VECT(IIC, 0xae0),
+       INTC_VECT(VIN0, 0xb00), INTC_VECT(VIN1, 0xb20),
+       INTC_VECT(VCORE0, 0xb00), INTC_VECT(ATAPI, 0xb60),
+       INTC_VECT(DTU0_TEND, 0xc00), INTC_VECT(DTU0_AE, 0xc20),
+       INTC_VECT(DTU0_TMISS, 0xc40),
+       INTC_VECT(DTU1_TEND, 0xc60), INTC_VECT(DTU1_AE, 0xc80),
+       INTC_VECT(DTU1_TMISS, 0xca0),
+       INTC_VECT(DTU2_TEND, 0xcc0), INTC_VECT(DTU2_AE, 0xce0),
+       INTC_VECT(DTU2_TMISS, 0xd00),
+       INTC_VECT(DTU3_TEND, 0xd20), INTC_VECT(DTU3_AE, 0xd40),
+       INTC_VECT(DTU3_TMISS, 0xd60),
+       INTC_VECT(FE0, 0xe00), INTC_VECT(FE1, 0xe20),
+       INTC_VECT(GPIO0, 0xe40), INTC_VECT(GPIO1, 0xe60),
+       INTC_VECT(GPIO2, 0xe80), INTC_VECT(GPIO3, 0xea0),
+       INTC_VECT(PAM, 0xec0), INTC_VECT(IRM, 0xee0),
+       INTC_VECT(INTICI0, 0xf00), INTC_VECT(INTICI1, 0xf20),
+       INTC_VECT(INTICI2, 0xf40), INTC_VECT(INTICI3, 0xf60),
+       INTC_VECT(INTICI4, 0xf80), INTC_VECT(INTICI5, 0xfa0),
+       INTC_VECT(INTICI6, 0xfc0), INTC_VECT(INTICI7, 0xfe0),
 };
 
-static struct intc2_desc intc2_irq_desc __read_mostly = {
-       .prio_base      = 0xfe410000,
-       .msk_base       = 0xfe410820,
-       .mskclr_base    = 0xfe410850,
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+                  IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+                  IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+                  IRL_HHLL, IRL_HHLH, IRL_HHHL),
+       INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+       INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI),
+       INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+                  DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+       INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+                  DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
+       INTC_GROUP(DTU0, DTU0_TEND, DTU0_AE, DTU0_TMISS),
+       INTC_GROUP(DTU1, DTU1_TEND, DTU1_AE, DTU1_TMISS),
+       INTC_GROUP(DTU2, DTU2_TEND, DTU2_AE, DTU2_TMISS),
+       INTC_GROUP(DTU3, DTU3_TEND, DTU3_AE, DTU3_TMISS),
+};
 
-       .intc2_data     = intc2_irq_table,
-       .nr_irqs        = ARRAY_SIZE(intc2_irq_table),
+static struct intc_prio priorities[] __initdata = {
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+       INTC_PRIO(SCIF2, 3),
+       INTC_PRIO(SCIF3, 3),
+};
 
-       .chip = {
-               .name   = "INTC2-SHX3",
-       },
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
+         { IRQ0, IRQ1, IRQ2, IRQ3 } },
+       { 0xfe410040, 0xfe410060, 32, /* CnINTMSK1 / CnINTMSKCLR1 */
+         { IRL } },
+       { 0xfe410820, 0xfe410850, 32, /* CnINT2MSK0 / CnINT2MSKCLR0 */
+         { FE1, FE0, 0, ATAPI, VCORE0, VIN1, VIN0, IIC,
+           DU, GPIO3, GPIO2, GPIO1, GPIO0, PAM, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0, /* HUDI bits ignored */
+           0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, } },
+       { 0xfe410830, 0xfe410860, 32, /* CnINT2MSK1 / CnINT2MSKCLR1 */
+         { 0, 0, 0, 0, DTU3, DTU2, DTU1, DTU0, /* IRM bits ignored */
+           PCII9, PCII8, PCII7, PCII6, PCII5, PCII4, PCII3, PCII2,
+           PCII1, PCII0, DMAC1_DMAE, DMAC1_DMINT11,
+           DMAC1_DMINT10, DMAC1_DMINT9, DMAC1_DMINT8, DMAC1_DMINT7,
+           DMAC1_DMINT6, DMAC0_DMAE, DMAC0_DMINT5, DMAC0_DMINT4,
+           DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 } },
+       { 0xfe410840, 0xfe410870, 32, /* CnINT2MSK2 / CnINT2MSKCLR2 */
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           SCIF3_TXI, SCIF3_BRI, SCIF3_RXI, SCIF3_ERI,
+           SCIF2_TXI, SCIF2_BRI, SCIF2_RXI, SCIF2_ERI,
+           SCIF1_TXI, SCIF1_BRI, SCIF1_RXI, SCIF1_ERI,
+           SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfe410010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+
+       { 0xfe410800, 0, 32, 4, /* INT2PRI0 */ { 0, HUDII, TMU5, TMU4,
+                                                TMU3, TMU2, TMU1, TMU0 } },
+       { 0xfe410804, 0, 32, 4, /* INT2PRI1 */ { DTU3, DTU2, DTU1, DTU0,
+                                                SCIF3, SCIF2,
+                                                SCIF1, SCIF0 } },
+       { 0xfe410808, 0, 32, 4, /* INT2PRI2 */ { DMAC1, DMAC0,
+                                                PCII56789, PCII4,
+                                                PCII3, PCII2,
+                                                PCII1, PCII0 } },
+       { 0xfe41080c, 0, 32, 4, /* INT2PRI3 */ { FE1, FE0, ATAPI, VCORE0,
+                                                VIN1, VIN0, IIC, DU} },
+       { 0xfe410810, 0, 32, 4, /* INT2PRI4 */ { 0, 0, PAM, GPIO3,
+                                                GPIO2, GPIO1, GPIO0, IRM } },
+       { 0xfe410090, 0xfe4100a0, 32, 4, /* CnICIPRI / CnICIPRICLR */
+         { INTICI7, INTICI6, INTICI5, INTICI4,
+           INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 4) },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "shx3", vectors, groups, priorities,
+                        mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+static struct intc_vect vectors_irq[] __initdata = {
+       INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+       INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+};
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+       { 0xfe41001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3 } },
 };
 
+static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
+                        priorities, mask_registers, prio_registers,
+                        sense_registers);
+
+/* External interrupt pins in IRL mode */
+static struct intc_vect vectors_irl[] __initdata = {
+       INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+       INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+       INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+       INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+       INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+       INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+       INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+       INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
+                        priorities, mask_registers, prio_registers, NULL);
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ:
+               register_intc_controller(&intc_desc_irq);
+               break;
+       case IRQ_MODE_IRL3210:
+               register_intc_controller(&intc_desc_irl);
+               break;
+       default:
+               BUG();
+       }
+}
+
 void __init plat_irq_setup(void)
 {
-       register_intc2_controller(&intc2_irq_desc);
+       register_intc_controller(&intc_desc);
+}
+
+void __init plat_mem_setup(void)
+{
+       unsigned int nid = 1;
+
+       /* Register CPU#0 URAM space as Node 1 */
+       setup_bootmem_node(nid++, 0x145f0000, 0x14610000);      /* CPU0 */
+
+#if 0
+       /* XXX: Not yet.. */
+       setup_bootmem_node(nid++, 0x14df0000, 0x14e10000);      /* CPU1 */
+       setup_bootmem_node(nid++, 0x155f0000, 0x15610000);      /* CPU2 */
+       setup_bootmem_node(nid++, 0x15df0000, 0x15e10000);      /* CPU3 */
+#endif
+
+       setup_bootmem_node(nid++, 0x16000000, 0x16020000);      /* CSM */
 }
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
new file mode 100644 (file)
index 0000000..e5e0684
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * SH-X3 SMP
+ *
+ *  Copyright (C) 2007  Paul Mundt
+ *  Copyright (C) 2007  Magnus Damm
+ *
+ * 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 more details.
+ */
+#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+void __init plat_smp_setup(void)
+{
+       unsigned int cpu = 0;
+       int i, num;
+
+       cpus_clear(cpu_possible_map);
+       cpu_set(cpu, cpu_possible_map);
+
+       __cpu_number_map[0] = 0;
+       __cpu_logical_map[0] = 0;
+
+       /*
+        * Do this stupidly for now.. we don't have an easy way to probe
+        * for the total number of cores.
+        */
+       for (i = 1, num = 0; i < NR_CPUS; i++) {
+               cpu_set(i, cpu_possible_map);
+               __cpu_number_map[i] = ++num;
+               __cpu_logical_map[num] = i;
+       }
+
+        printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
+}
+
+void __init plat_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
+#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
+
+#define STBCR_MSTP     0x00000001
+#define STBCR_RESET    0x00000002
+#define STBCR_LTSLP    0x80000000
+
+#define STBCR_AP_VAL   (STBCR_RESET | STBCR_LTSLP)
+
+void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
+{
+       ctrl_outl(entry_point, RESET_REG(cpu));
+
+       if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
+               ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
+
+       while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
+               ;
+
+       /* Start up secondary processor by sending a reset */
+       ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
+}
+
+int plat_smp_processor_id(void)
+{
+       return ctrl_inl(0xff000048); /* CPIDR */
+}
+
+void plat_send_ipi(unsigned int cpu, unsigned int message)
+{
+       unsigned long addr = 0xfe410070 + (cpu * 4);
+
+       BUG_ON(cpu >= 4);
+       BUG_ON(message >= SMP_MSG_NR);
+
+       ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
+}
+
+struct ipi_data {
+       void (*handler)(void *);
+       void *arg;
+       unsigned int message;
+};
+
+static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
+{
+       struct ipi_data *id = arg;
+       unsigned int cpu = hard_smp_processor_id();
+       unsigned int offs = 4 * cpu;
+       unsigned int x;
+
+       x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
+       x &= (1 << (id->message << 2));
+       ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
+
+       id->handler(id->arg);
+
+       return IRQ_HANDLED;
+}
+
+static struct ipi_data ipi_handlers[SMP_MSG_NR];
+
+int plat_register_ipi_handler(unsigned int message,
+                             void (*handler)(void *), void *arg)
+{
+       struct ipi_data *id = &ipi_handlers[message];
+
+       BUG_ON(SMP_MSG_NR >= 8);
+       BUG_ON(message >= SMP_MSG_NR);
+
+       id->handler = handler;
+       id->arg = arg;
+       id->message = message;
+
+       return request_irq(104 + message, ipi_interrupt_handler, 0, "IPI", id);
+}
index 71d1c427b9079771ecf2528a02ddf0559aef2232..e0590ffebd73f546af41b9a47453ab7eb09543ae 100644 (file)
@@ -77,8 +77,6 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy,
 
 static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
-
        if (!cpu_online(policy->cpu))
                return -ENODEV;
 
@@ -143,6 +141,7 @@ static struct cpufreq_driver sh_cpufreq_driver = {
 
 static int __init sh_cpufreq_module_init(void)
 {
+       printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
        return cpufreq_register_driver(&sh_cpufreq_driver);
 }
 
index 80b637c302035995ef6823d85b7186174d7060d6..2f30977558adf9b11eb89b2dd3c3e8545c2abed7 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1999, 2000  Niibe Yutaka
  *  Copyright (C) 2002  M. R. Brown
- *  Copyright (C) 2004 - 2006  Paul Mundt
+ *  Copyright (C) 2004 - 2007  Paul Mundt
  *
  * 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
@@ -13,6 +13,7 @@
 #include <linux/tty.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/delay.h>
 
 #ifdef CONFIG_SH_STANDARD_BIOS
 #include <asm/sh_bios.h>
@@ -62,6 +63,16 @@ static struct console bios_console = {
 #include <linux/serial_core.h>
 #include "../../../drivers/serial/sh-sci.h"
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+#define EPK_SCSMR_VALUE 0x000
+#define EPK_SCBRR_VALUE 0x00C
+#define EPK_FIFO_SIZE 64
+#define EPK_FIFO_BITS (0x7f00 >> 8)
+#else
+#define EPK_FIFO_SIZE 16
+#define EPK_FIFO_BITS (0x1f00 >> 8)
+#endif
+
 static struct uart_port scif_port = {
        .mapbase        = CONFIG_EARLY_SCIF_CONSOLE_PORT,
        .membase        = (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT,
@@ -69,7 +80,7 @@ static struct uart_port scif_port = {
 
 static void scif_sercon_putc(int c)
 {
-       while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16))
+       while (((sci_in(&scif_port, SCFDR) & EPK_FIFO_BITS) >= EPK_FIFO_SIZE))
                ;
 
        sci_out(&scif_port, SCxTDR, c);
@@ -105,7 +116,22 @@ static struct console scif_console = {
        .index          = -1,
 };
 
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS)
+#if !defined(CONFIG_SH_STANDARD_BIOS)
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+static void scif_sercon_init(char *s)
+{
+       sci_out(&scif_port, SCSCR, 0x0000);     /* clear TE and RE */
+       sci_out(&scif_port, SCFCR, 0x4006);     /* reset */
+       sci_out(&scif_port, SCSCR, 0x0000);     /* select internal clock */
+       sci_out(&scif_port, SCSMR, EPK_SCSMR_VALUE);
+       sci_out(&scif_port, SCBRR, EPK_SCBRR_VALUE);
+
+       mdelay(1);      /* wait 1-bit time */
+
+       sci_out(&scif_port, SCFCR, 0x0030);     /* TTRG=b'11 */
+       sci_out(&scif_port, SCSCR, 0x0030);     /* TE, RE */
+}
+#elif defined(CONFIG_CPU_SH4)
 #define DEFAULT_BAUD 115200
 /*
  * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4
@@ -146,7 +172,8 @@ static void scif_sercon_init(char *s)
        ctrl_outw(0, scif_port.mapbase + 36);
        ctrl_outw(0x30, scif_port.mapbase + 8);
 }
-#endif /* CONFIG_CPU_SH4 && !CONFIG_SH_STANDARD_BIOS */
+#endif /* defined(CONFIG_CPU_SUBTYPE_SH7720) */
+#endif /* !defined(CONFIG_SH_STANDARD_BIOS) */
 #endif /* CONFIG_EARLY_SCIF_CONSOLE */
 
 /*
@@ -163,17 +190,12 @@ static struct console *early_console =
 #endif
        ;
 
-static int __initdata keep_early;
-static int early_console_initialized;
-
-int __init setup_early_printk(char *buf)
+static int __init setup_early_printk(char *buf)
 {
-       if (!buf)
-               return 0;
+       int keep_early = 0;
 
-       if (early_console_initialized)
+       if (!buf)
                return 0;
-       early_console_initialized = 1;
 
        if (strstr(buf, "keep"))
                keep_early = 1;
@@ -186,7 +208,8 @@ int __init setup_early_printk(char *buf)
        if (!strncmp(buf, "serial", 6)) {
                early_console = &scif_console;
 
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS)
+#if (defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720)) && \
+    !defined(CONFIG_SH_STANDARD_BIOS)
                scif_sercon_init(buf + 6);
 #endif
        }
index b46728027195b15747b7b43f18a7e35e0a687623..e0317ed080c3402d870ab51c75dd34853f73b797 100644 (file)
@@ -176,7 +176,7 @@ work_notifysig:
        jmp     @r1
         lds    r0, pr
 work_resched:
-#ifndef CONFIG_PREEMPT
+#if defined(CONFIG_GUSA) && !defined(CONFIG_PREEMPT)
        ! gUSA handling
        mov.l   @(OFF_SP,r15), r0       ! get user space stack pointer
        mov     r0, r1
index 0bccc0ca5a0f73ff624ed862bc55fbf1764bf80d..3338239717f108f2d03f4779eecd7e9ed865ebe3 100644 (file)
@@ -54,8 +54,8 @@ ENTRY(_stext)
        mov.l   1f, r0          ! MD=1, RB=0, BL=0, IMASK=0xF
        ldc     r0, sr
        !                       Initialize global interrupt mask
-       mov     #0, r0
 #ifdef CONFIG_CPU_HAS_SR_RB
+       mov     #0, r0
        ldc     r0, r6_bank
 #endif
        
@@ -72,15 +72,18 @@ ENTRY(_stext)
        !
        mov.l   2f, r0
        mov     r0, r15         ! Set initial r15 (stack pointer)
-       mov     #(THREAD_SIZE >> 10), r1
-       shll8   r1              ! r1 = THREAD_SIZE
-       shll2   r1
-       sub     r1, r0          !
 #ifdef CONFIG_CPU_HAS_SR_RB
+       mov.l   7f, r0
        ldc     r0, r7_bank     ! ... and initial thread_info
 #endif
        
        !                       Clear BSS area
+#ifdef CONFIG_SMP      
+       mov.l   3f, r0
+       cmp/eq  #0, r0          ! skip clear if set to zero
+       bt      10f
+#endif
+       
        mov.l   3f, r1
        add     #4, r1
        mov.l   4f, r2
@@ -89,13 +92,14 @@ ENTRY(_stext)
        bf/s    9b              ! while (r1 < r2)
         mov.l  r0,@-r2
 
+10:            
        !                       Additional CPU initialization
        mov.l   6f, r0
        jsr     @r0
         nop
 
        SYNCO()                 ! Wait for pending instructions..
-
+       
        !                       Start kernel
        mov.l   5f, r0
        jmp     @r0
@@ -107,8 +111,10 @@ ENTRY(_stext)
 #else
 1:     .long   0x400080F0              ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
 #endif
+ENTRY(stack_start)
 2:     .long   init_thread_union+THREAD_SIZE
 3:     .long   __bss_start
 4:     .long   _end
 5:     .long   start_kernel
 6:     .long   sh_cpu_init
+7:     .long   init_thread_union
index edd1ec214e6d61a7c1367e85253955822e2fe64f..2fdc700dfd6e72be2bed5e8c4db4489967781d6c 100644 (file)
@@ -150,13 +150,6 @@ struct kgdb_regs trap_registers;
 char kgdb_in_gdb_mode;
 char in_nmi;                   /* Set during NMI to prevent reentry */
 int kgdb_nofault;              /* Boolean to ignore bus errs (i.e. in GDB) */
-int kgdb_enabled = 1;          /* Default to enabled, cmdline can disable */
-
-/* Exposed for user access */
-struct task_struct *kgdb_current;
-unsigned int kgdb_g_imask;
-int kgdb_trapa_val;
-int kgdb_excode;
 
 /* Default values for SCI (can override via kernel args in setup.c) */
 #ifndef CONFIG_KGDB_DEFPORT
@@ -616,7 +609,7 @@ static short *get_step_address(void)
        else
                addr = trap_registers.pc + 2;
 
-       kgdb_flush_icache_range(addr, addr + 2);
+       flush_icache_range(addr, addr + 2);
        return (short *) addr;
 }
 
@@ -639,8 +632,7 @@ static void do_single_step(void)
        *addr = STEP_OPCODE;
 
        /* Flush and return */
-       kgdb_flush_icache_range((long) addr, (long) addr + 2);
-       return;
+       flush_icache_range((long) addr, (long) addr + 2);
 }
 
 /* Undo a single step */
@@ -650,7 +642,7 @@ static void undo_single_step(void)
        /* Use stepped_address in case we stopped elsewhere */
        if (stepped_opcode != 0) {
                *(short*)stepped_address = stepped_opcode;
-               kgdb_flush_icache_range(stepped_address, stepped_address + 2);
+               flush_icache_range(stepped_address, stepped_address + 2);
        }
        stepped_opcode = 0;
 }
@@ -736,7 +728,7 @@ static void write_mem_msg(int binary)
                                        ebin_to_mem(ptr, (char*)addr, length);
                                else
                                        hex_to_mem(ptr, (char*)addr, length);
-                               kgdb_flush_icache_range(addr, addr + length);
+                               flush_icache_range(addr, addr + length);
                                ptr = 0;
                                send_ok_msg();
                        }
@@ -815,14 +807,10 @@ static void set_regs_msg(void)
 /*
  * Bring up the ports..
  */
-static int kgdb_serial_setup(void)
+static int __init kgdb_serial_setup(void)
 {
-       extern int kgdb_console_setup(struct console *co, char *options);
        struct console dummy;
-
-       kgdb_console_setup(&dummy, 0);
-
-       return 0;
+       return kgdb_console_setup(&dummy, 0);
 }
 #else
 #define kgdb_serial_setup()    0
@@ -833,22 +821,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
 {
        int sigval;
 
-       if (excep_code == NMI_VEC) {
-#ifndef CONFIG_KGDB_NMI
-               printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n");
-               return;
-#else /* CONFIG_KGDB_NMI */
-               if (!kgdb_enabled) {
-                       kgdb_enabled = 1;
-                       kgdb_init();
-               }
-#endif /* CONFIG_KGDB_NMI */
-       }
-
-       /* Ignore if we're disabled */
-       if (!kgdb_enabled)
-               return;
-
        /* Enter GDB mode (e.g. after detach) */
        if (!kgdb_in_gdb_mode) {
                /* Do serial setup, notify user, issue preemptive ack */
@@ -959,18 +931,10 @@ static void handle_exception(struct pt_regs *regs)
 
        /* Get excode for command loop call, user access */
        asm("stc r2_bank, %0":"=r"(excep_code));
-       kgdb_excode = excep_code;
-
-       /* Other interesting environment items for reference */
-       asm("stc r6_bank, %0":"=r"(kgdb_g_imask));
-       kgdb_current = current;
-       kgdb_trapa_val = trapa_value;
 
        /* Act on the exception */
        kgdb_command_loop(excep_code, trapa_value);
 
-       kgdb_current = NULL;
-
        /* Copy back the (maybe modified) registers */
        for (count = 0; count < 16; count++)
                regs->regs[count] = trap_registers.regs[count];
@@ -994,11 +958,8 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
 }
 
 /* Initialise the KGDB data structures and serial configuration */
-int kgdb_init(void)
+int __init kgdb_init(void)
 {
-       if (!kgdb_enabled)
-               return 1;
-
        in_nmi = 0;
        kgdb_nofault = 0;
        stepped_opcode = 0;
index 15ae322dbd741a594529835c2c543987125d37f9..b4469992d6b25aafab1e8fcc1f2cd089bee5f9e0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/tick.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
+#include <linux/preempt.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
@@ -349,12 +350,11 @@ struct task_struct *__switch_to(struct task_struct *prev,
        unlazy_fpu(prev, task_pt_regs(prev));
 #endif
 
-#ifdef CONFIG_PREEMPT
+#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT)
        {
-               unsigned long flags;
                struct pt_regs *regs;
 
-               local_irq_save(flags);
+               preempt_disable();
                regs = task_pt_regs(prev);
                if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
                        int offset = (int)regs->regs[15];
@@ -365,7 +365,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
                                /* Go to rewind point */
                                regs->pc = regs->regs[0] + offset;
                }
-               local_irq_restore(flags);
+               preempt_enable_no_resched();
        }
 #endif
 
index 2cf7dec0d6904fbe94317e2223e003106b938551..b3027a6775b91106d8b5b61c85fb5ed0bbb8c5d1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/module.h>
+#include <linux/smp.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -42,7 +43,13 @@ extern void * __rd_start, * __rd_end;
  * This value will be used at the very early stage of serial setup.
  * The bigger value means no problem.
  */
-struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, };
+struct sh_cpuinfo cpu_data[NR_CPUS] __read_mostly = {
+       [0] = {
+               .type                   = CPU_SH_NONE,
+               .loops_per_jiffy        = 10000000,
+       },
+};
+EXPORT_SYMBOL(cpu_data);
 
 /*
  * The machine vector. First entry in .machvec.init, or clobbered by
@@ -272,6 +279,10 @@ void __init setup_arch(char **cmdline_p)
                sh_mv.mv_setup(cmdline_p);
 
        paging_init();
+
+#ifdef CONFIG_SMP
+       plat_smp_setup();
+#endif
 }
 
 static const char *cpu_name[] = {
@@ -279,7 +290,7 @@ static const char *cpu_name[] = {
        [CPU_SH7705]    = "SH7705",     [CPU_SH7706]    = "SH7706",
        [CPU_SH7707]    = "SH7707",     [CPU_SH7708]    = "SH7708",
        [CPU_SH7709]    = "SH7709",     [CPU_SH7710]    = "SH7710",
-       [CPU_SH7712]    = "SH7712",
+       [CPU_SH7712]    = "SH7712",     [CPU_SH7720]    = "SH7720",
        [CPU_SH7729]    = "SH7729",     [CPU_SH7750]    = "SH7750",
        [CPU_SH7750S]   = "SH7750S",    [CPU_SH7750R]   = "SH7750R",
        [CPU_SH7751]    = "SH7751",     [CPU_SH7751R]   = "SH7751R",
index 37aef0a85197b7b754998e0f0d126cde9ee9cdbf..548e4285b37569e82e731dd5ba1f8e79dff45739 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/vmalloc.h>
 #include <linux/pci.h>
 #include <linux/irq.h>
-
+#include <asm/sections.h>
 #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
@@ -43,7 +43,6 @@ EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(__copy_user);
-EXPORT_SYMBOL(boot_cpu_data);
 
 #ifdef CONFIG_MMU
 EXPORT_SYMBOL(get_vm_area);
@@ -53,6 +52,7 @@ EXPORT_SYMBOL(get_vm_area);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
 
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
@@ -128,7 +128,8 @@ DECLARE_EXPORT(__movstrSI12_i4);
 #endif /* __GNUC__ == 4 */
 #endif
 
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
+       defined(CONFIG_SH7705_CACHE_32KB))
 /* needed by some modules */
 EXPORT_SYMBOL(flush_cache_all);
 EXPORT_SYMBOL(flush_cache_range);
@@ -136,17 +137,11 @@ EXPORT_SYMBOL(flush_dcache_page);
 EXPORT_SYMBOL(__flush_purge_region);
 #endif
 
-#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
-       defined(CONFIG_SH7705_CACHE_32KB))
+#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \
+       (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB))
 EXPORT_SYMBOL(clear_user_page);
 #endif
 
-EXPORT_SYMBOL(__down_trylock);
-
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(synchronize_irq);
-#endif
-
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
 #ifdef CONFIG_IPV6
@@ -154,3 +149,4 @@ EXPORT_SYMBOL(csum_ipv6_magic);
 #endif
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(_ebss);
index 706d81ccd10149e15e28ffbfeed70e69a656e009..2f42442cf164e9d6921b22bec246596304d3d640 100644 (file)
@@ -507,13 +507,11 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                                                ctrl_inw(regs->pc - 4));
                                break;
                }
+#ifdef CONFIG_GUSA
        } else {
                /* gUSA handling */
-#ifdef CONFIG_PREEMPT
-               unsigned long flags;
+               preempt_disable();
 
-               local_irq_save(flags);
-#endif
                if (regs->regs[15] >= 0xc0000000) {
                        int offset = (int)regs->regs[15];
 
@@ -524,8 +522,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                                regs->pc = regs->regs[0] + offset -
                                        instruction_size(ctrl_inw(regs->pc-4));
                }
-#ifdef CONFIG_PREEMPT
-               local_irq_restore(flags);
+
+               preempt_enable_no_resched();
 #endif
        }
 
index 283e1425ced57046d63cd850317f1c6b5e8dd766..94075e1a1e61b485f4e32a094870f5b8de7aa91a 100644 (file)
@@ -3,68 +3,40 @@
  *
  * SMP support for the SuperH processors.
  *
- * Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
+ * Copyright (C) 2006 - 2007 Akio Idehara
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * This 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 more details.
  */
-
 #include <linux/err.h>
 #include <linux/cache.h>
 #include <linux/cpumask.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <linux/threads.h>
+#include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-
+#include <linux/interrupt.h>
 #include <asm/atomic.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/smp.h>
+#include <asm/cacheflush.h>
+#include <asm/sections.h>
 
-/*
- * This was written with the Sega Saturn (SMP SH-2 7604) in mind,
- * but is designed to be usable regardless if there's an MMU
- * present or not.
- */
-struct sh_cpuinfo cpu_data[NR_CPUS];
-
-extern void per_cpu_trap_init(void);
+int __cpu_number_map[NR_CPUS];         /* Map physical to logical */
+int __cpu_logical_map[NR_CPUS];                /* Map logical to physical */
 
 cpumask_t cpu_possible_map;
 EXPORT_SYMBOL(cpu_possible_map);
 
 cpumask_t cpu_online_map;
 EXPORT_SYMBOL(cpu_online_map);
-static atomic_t cpus_booted = ATOMIC_INIT(0);
 
-/* These are defined by the board-specific code. */
-
-/*
- * Cause the function described by call_data to be executed on the passed
- * cpu.  When the function has finished, increment the finished field of
- * call_data.
- */
-void __smp_send_ipi(unsigned int cpu, unsigned int action);
-
-/*
- * Find the number of available processors
- */
-unsigned int __smp_probe_cpus(void);
-
-/*
- * Start a particular processor
- */
-void __smp_slave_init(unsigned int cpu);
+static atomic_t cpus_booted = ATOMIC_INIT(0);
 
 /*
  * Run specified function on a particular processor.
@@ -73,74 +45,123 @@ void __smp_call_function(unsigned int cpu);
 
 static inline void __init smp_store_cpu_info(unsigned int cpu)
 {
-       cpu_data[cpu].loops_per_jiffy = loops_per_jiffy;
+       struct sh_cpuinfo *c = cpu_data + cpu;
+
+       c->loops_per_jiffy = loops_per_jiffy;
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        unsigned int cpu = smp_processor_id();
-       int i;
 
-       atomic_set(&cpus_booted, 1);
-       smp_store_cpu_info(cpu);
-       
-       for (i = 0; i < __smp_probe_cpus(); i++)
-               cpu_set(i, cpu_possible_map);
+       init_new_context(current, &init_mm);
+       current_thread_info()->cpu = cpu;
+       plat_prepare_cpus(max_cpus);
+
+#ifndef CONFIG_HOTPLUG_CPU
+       cpu_present_map = cpu_possible_map;
+#endif
 }
 
 void __devinit smp_prepare_boot_cpu(void)
 {
        unsigned int cpu = smp_processor_id();
 
+       __cpu_number_map[0] = cpu;
+       __cpu_logical_map[0] = cpu;
+
        cpu_set(cpu, cpu_online_map);
        cpu_set(cpu, cpu_possible_map);
 }
 
-int __cpu_up(unsigned int cpu)
+asmlinkage void __cpuinit start_secondary(void)
 {
-       struct task_struct *tsk;
+       unsigned int cpu;
+       struct mm_struct *mm = &init_mm;
 
-       tsk = fork_idle(cpu);
+       atomic_inc(&mm->mm_count);
+       atomic_inc(&mm->mm_users);
+       current->active_mm = mm;
+       BUG_ON(current->mm);
+       enter_lazy_tlb(mm, current);
 
-       if (IS_ERR(tsk))
-               panic("Failed forking idle task for cpu %d\n", cpu);
-       
-       task_thread_info(tsk)->cpu = cpu;
+       per_cpu_trap_init();
+
+       preempt_disable();
+
+       local_irq_enable();
+
+       calibrate_delay();
+
+       cpu = smp_processor_id();
+       smp_store_cpu_info(cpu);
 
        cpu_set(cpu, cpu_online_map);
 
-       return 0;
+       cpu_idle();
 }
 
-int start_secondary(void *unused)
+extern struct {
+       unsigned long sp;
+       unsigned long bss_start;
+       unsigned long bss_end;
+       void *start_kernel_fn;
+       void *cpu_init_fn;
+       void *thread_info;
+} stack_start;
+
+int __cpuinit __cpu_up(unsigned int cpu)
 {
-       unsigned int cpu;
+       struct task_struct *tsk;
+       unsigned long timeout;
 
-       cpu = smp_processor_id();
+       tsk = fork_idle(cpu);
+       if (IS_ERR(tsk)) {
+               printk(KERN_ERR "Failed forking idle task for cpu %d\n", cpu);
+               return PTR_ERR(tsk);
+       }
 
-       atomic_inc(&init_mm.mm_count);
-       current->active_mm = &init_mm;
+       /* Fill in data in head.S for secondary cpus */
+       stack_start.sp = tsk->thread.sp;
+       stack_start.thread_info = tsk->stack;
+       stack_start.bss_start = 0; /* don't clear bss for secondary cpus */
+       stack_start.start_kernel_fn = start_secondary;
 
-       smp_store_cpu_info(cpu);
+       flush_cache_all();
 
-       __smp_slave_init(cpu);
-       preempt_disable();
-       per_cpu_trap_init();
-       
-       atomic_inc(&cpus_booted);
+       plat_start_cpu(cpu, (unsigned long)_stext);
 
-       cpu_idle();
-       return 0;
+       timeout = jiffies + HZ;
+       while (time_before(jiffies, timeout)) {
+               if (cpu_online(cpu))
+                       break;
+
+               udelay(10);
+       }
+
+       if (cpu_online(cpu))
+               return 0;
+
+       return -ENOENT;
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
-       smp_mb();
+       unsigned long bogosum = 0;
+       int cpu;
+
+       for_each_online_cpu(cpu)
+               bogosum += cpu_data[cpu].loops_per_jiffy;
+
+       printk(KERN_INFO "SMP: Total of %d processors activated "
+              "(%lu.%02lu BogoMIPS).\n", num_online_cpus(),
+              bogosum / (500000/HZ),
+              (bogosum / (5000/HZ)) % 100);
 }
 
 void smp_send_reschedule(int cpu)
 {
-       __smp_send_ipi(cpu, SMP_MSG_RESCHEDULE);
+       plat_send_ipi(cpu, SMP_MSG_RESCHEDULE);
 }
 
 static void stop_this_cpu(void *unused)
@@ -157,7 +178,6 @@ void smp_send_stop(void)
        smp_call_function(stop_this_cpu, 0, 1, 0);
 }
 
-
 struct smp_fn_call_struct smp_fn_call = {
        .lock           = SPIN_LOCK_UNLOCKED,
        .finished       = ATOMIC_INIT(0),
@@ -175,9 +195,6 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
        unsigned int nr_cpus = atomic_read(&cpus_booted);
        int i;
 
-       if (nr_cpus < 2)
-               return 0;
-
        /* Can deadlock when called with interrupts disabled */
        WARN_ON(irqs_disabled());
 
@@ -189,7 +206,7 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
 
        for (i = 0; i < nr_cpus; i++)
                if (i != smp_processor_id())
-                       __smp_call_function(i);
+                       plat_send_ipi(i, SMP_MSG_FUNCTION);
 
        if (wait)
                while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1));
@@ -205,3 +222,143 @@ int setup_profiling_timer(unsigned int multiplier)
        return 0;
 }
 
+static void flush_tlb_all_ipi(void *info)
+{
+       local_flush_tlb_all();
+}
+
+void flush_tlb_all(void)
+{
+       on_each_cpu(flush_tlb_all_ipi, 0, 1, 1);
+}
+
+static void flush_tlb_mm_ipi(void *mm)
+{
+       local_flush_tlb_mm((struct mm_struct *)mm);
+}
+
+/*
+ * The following tlb flush calls are invoked when old translations are
+ * being torn down, or pte attributes are changing. For single threaded
+ * address spaces, a new context is obtained on the current cpu, and tlb
+ * context on other cpus are invalidated to force a new context allocation
+ * at switch_mm time, should the mm ever be used on other cpus. For
+ * multithreaded address spaces, intercpu interrupts have to be sent.
+ * Another case where intercpu interrupts are required is when the target
+ * mm might be active on another cpu (eg debuggers doing the flushes on
+ * behalf of debugees, kswapd stealing pages from another process etc).
+ * Kanoj 07/00.
+ */
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       preempt_disable();
+
+       if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
+               smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
+       } else {
+               int i;
+               for (i = 0; i < num_online_cpus(); i++)
+                       if (smp_processor_id() != i)
+                               cpu_context(i, mm) = 0;
+       }
+       local_flush_tlb_mm(mm);
+
+       preempt_enable();
+}
+
+struct flush_tlb_data {
+       struct vm_area_struct *vma;
+       unsigned long addr1;
+       unsigned long addr2;
+};
+
+static void flush_tlb_range_ipi(void *info)
+{
+       struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+       local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma,
+                    unsigned long start, unsigned long end)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       preempt_disable();
+       if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
+               struct flush_tlb_data fd;
+
+               fd.vma = vma;
+               fd.addr1 = start;
+               fd.addr2 = end;
+               smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
+       } else {
+               int i;
+               for (i = 0; i < num_online_cpus(); i++)
+                       if (smp_processor_id() != i)
+                               cpu_context(i, mm) = 0;
+       }
+       local_flush_tlb_range(vma, start, end);
+       preempt_enable();
+}
+
+static void flush_tlb_kernel_range_ipi(void *info)
+{
+       struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+       local_flush_tlb_kernel_range(fd->addr1, fd->addr2);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       struct flush_tlb_data fd;
+
+       fd.addr1 = start;
+       fd.addr2 = end;
+       on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1, 1);
+}
+
+static void flush_tlb_page_ipi(void *info)
+{
+       struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+       local_flush_tlb_page(fd->vma, fd->addr1);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       preempt_disable();
+       if ((atomic_read(&vma->vm_mm->mm_users) != 1) ||
+           (current->mm != vma->vm_mm)) {
+               struct flush_tlb_data fd;
+
+               fd.vma = vma;
+               fd.addr1 = page;
+               smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
+       } else {
+               int i;
+               for (i = 0; i < num_online_cpus(); i++)
+                       if (smp_processor_id() != i)
+                               cpu_context(i, vma->vm_mm) = 0;
+       }
+       local_flush_tlb_page(vma, page);
+       preempt_enable();
+}
+
+static void flush_tlb_one_ipi(void *info)
+{
+       struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+       local_flush_tlb_one(fd->addr1, fd->addr2);
+}
+
+void flush_tlb_one(unsigned long asid, unsigned long vaddr)
+{
+       struct flush_tlb_data fd;
+
+       fd.addr1 = asid;
+       fd.addr2 = vaddr;
+
+       smp_call_function(flush_tlb_one_ipi, (void *)&fd, 1, 1);
+       local_flush_tlb_one(asid, vaddr);
+}
index 91fb7024e06f08626bd4b31efd0043ca6ad69b31..10bec45415ba0c09f856533418f1775e4e94eb96 100644 (file)
 #include <linux/sys.h>
 #include <linux/linkage.h>
 
-#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
-#define sys_nfsservctl         sys_ni_syscall
-#endif
-
-#if !defined(CONFIG_MMU)
-#define sys_madvise            sys_ni_syscall
-#define sys_readahead          sys_ni_syscall
-#define sys_mprotect           sys_ni_syscall
-#define sys_msync              sys_ni_syscall
-#define sys_mlock              sys_ni_syscall
-#define sys_munlock            sys_ni_syscall
-#define sys_mlockall           sys_ni_syscall
-#define sys_munlockall         sys_ni_syscall
-#define sys_mremap             sys_ni_syscall
-#define sys_mincore            sys_ni_syscall
-#define sys_remap_file_pages   sys_ni_syscall
-#endif
-
        .data
 ENTRY(sys_call_table)
        .long sys_restart_syscall       /* 0  -  old "setup()" system call*/
index 8a545d54e2d3f4b795167ebf350a808fcee11ec0..628ec9a15e383282a79df5b6701e35dd2122a56e 100644 (file)
@@ -173,7 +173,8 @@ static int tmu_timer_init(void)
 
        tmu_timer_stop();
 
-#if !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
+#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
+    !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
     !defined(CONFIG_CPU_SUBTYPE_SH7785) && \
     !defined(CONFIG_CPU_SUBTYPE_SHX3)
        ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
index 67015044d74a935f75bff8c86e58dce737faeaf0..dcb46e71da1c6d23217c6d22a5221ff59a931ff6 100644 (file)
@@ -807,12 +807,13 @@ static inline void __init gdb_vbr_init(void)
 }
 #endif
 
-void __init per_cpu_trap_init(void)
+void __cpuinit per_cpu_trap_init(void)
 {
        extern void *vbr_base;
 
 #ifdef CONFIG_SH_STANDARD_BIOS
-       gdb_vbr_init();
+       if (raw_smp_processor_id() == 0)
+               gdb_vbr_init();
 #endif
 
        /* NOTE: The VBR value should be at P1
index 9cb95af7b09013dd25fdfb0da3b1cf6e031bc84a..6d5abba2ee271a8147be2f56b2502ccd75600859 100644 (file)
@@ -62,6 +62,8 @@ SECTIONS
   __nosave_end = .;
 
   PERCPU(PAGE_SIZE)
+
+  . = ALIGN(L1_CACHE_BYTES);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   _edata = .;                  /* End of data section */
@@ -89,7 +91,14 @@ SECTIONS
   __con_initcall_end = .;
   SECURITY_INIT
 
+  /* .exit.text is discarded at runtime, not link time, to deal with
+     references from .rodata */
+  .exit.text : { *(.exit.text) }
+  .exit.data : { *(.exit.data) }
+
 #ifdef CONFIG_BLK_DEV_INITRD
+  . = ALIGN(PAGE_SIZE);
+
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
@@ -107,6 +116,7 @@ SECTIONS
        *(.bss.page_aligned)
        *(.bss)
        . = ALIGN(4);
+       _ebss = .;                      /* uClinux MTD sucks */
        _end = . ;
   }
 
index 43f3972a5fb97264736ffb6c21cb0937529b9d78..cf446bbab5b08c03aa615240791ace492cfd8957 100644 (file)
@@ -2,7 +2,6 @@
 # Processor families
 #
 config CPU_SH2
-       select SH_WRITETHROUGH if !CPU_SH2A
        bool
 
 config CPU_SH2A
@@ -19,6 +18,7 @@ config CPU_SH4
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
        select CPU_HAS_PTEA if (!CPU_SUBTYPE_ST40 && !CPU_SH4A) || CPU_SHX2
+       select CPU_HAS_FPU if !CPU_SH4AL_DSP
 
 config CPU_SH4A
        bool
@@ -32,7 +32,6 @@ config CPU_SH4AL_DSP
 config CPU_SUBTYPE_ST40
        bool
        select CPU_SH4
-       select CPU_HAS_INTC2_IRQ
 
 config CPU_SHX2
        bool
@@ -52,26 +51,22 @@ choice
 config CPU_SUBTYPE_SH7619
        bool "Support SH7619 processor"
        select CPU_SH2
-       select CPU_HAS_IPR_IRQ
 
 # SH-2A Processor Support
 
 config CPU_SUBTYPE_SH7206
        bool "Support SH7206 processor"
        select CPU_SH2A
-       select CPU_HAS_IPR_IRQ
 
 # SH-3 Processor Support
 
 config CPU_SUBTYPE_SH7705
        bool "Support SH7705 processor"
        select CPU_SH3
-       select CPU_HAS_IPR_IRQ
 
 config CPU_SUBTYPE_SH7706
        bool "Support SH7706 processor"
        select CPU_SH3
-       select CPU_HAS_IPR_IRQ
        help
          Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
 
@@ -91,14 +86,12 @@ config CPU_SUBTYPE_SH7708
 config CPU_SUBTYPE_SH7709
        bool "Support SH7709 processor"
        select CPU_SH3
-       select CPU_HAS_IPR_IRQ
        help
          Select SH7709 if you have a  80 Mhz SH-3 HD6417709 CPU.
 
 config CPU_SUBTYPE_SH7710
        bool "Support SH7710 processor"
        select CPU_SH3
-       select CPU_HAS_IPR_IRQ
        select CPU_HAS_DSP
        help
          Select SH7710 if you have a SH3-DSP SH7710 CPU.
@@ -106,24 +99,28 @@ config CPU_SUBTYPE_SH7710
 config CPU_SUBTYPE_SH7712
        bool "Support SH7712 processor"
        select CPU_SH3
-       select CPU_HAS_IPR_IRQ
        select CPU_HAS_DSP
        help
          Select SH7712 if you have a SH3-DSP SH7712 CPU.
 
+config CPU_SUBTYPE_SH7720
+       bool "Support SH7720 processor"
+       select CPU_SH3
+       select CPU_HAS_DSP
+       help
+         Select SH7720 if you have a SH3-DSP SH7720 CPU.
+
 # SH-4 Processor Support
 
 config CPU_SUBTYPE_SH7750
        bool "Support SH7750 processor"
        select CPU_SH4
-       select CPU_HAS_INTC_IRQ
        help
          Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
 
 config CPU_SUBTYPE_SH7091
        bool "Support SH7091 processor"
        select CPU_SH4
-       select CPU_HAS_INTC_IRQ
        help
          Select SH7091 if you have an SH-4 based Sega device (such as
          the Dreamcast, Naomi, and Naomi 2).
@@ -131,17 +128,14 @@ config CPU_SUBTYPE_SH7091
 config CPU_SUBTYPE_SH7750R
        bool "Support SH7750R processor"
        select CPU_SH4
-       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7750S
        bool "Support SH7750S processor"
        select CPU_SH4
-       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7751
        bool "Support SH7751 processor"
        select CPU_SH4
-       select CPU_HAS_INTC_IRQ
        help
          Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
          or if you have a HD6417751R CPU.
@@ -149,13 +143,10 @@ config CPU_SUBTYPE_SH7751
 config CPU_SUBTYPE_SH7751R
        bool "Support SH7751R processor"
        select CPU_SH4
-       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7760
        bool "Support SH7760 processor"
        select CPU_SH4
-       select CPU_HAS_INTC2_IRQ
-       select CPU_HAS_IPR_IRQ
 
 config CPU_SUBTYPE_SH4_202
        bool "Support SH4-202 processor"
@@ -185,19 +176,21 @@ config CPU_SUBTYPE_SH7770
 config CPU_SUBTYPE_SH7780
        bool "Support SH7780 processor"
        select CPU_SH4A
-       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7785
        bool "Support SH7785 processor"
        select CPU_SH4A
        select CPU_SHX2
-       select CPU_HAS_INTC2_IRQ
+       select ARCH_SPARSEMEM_ENABLE
+       select SYS_SUPPORTS_NUMA
 
 config CPU_SUBTYPE_SHX3
        bool "Support SH-X3 processor"
        select CPU_SH4A
        select CPU_SHX3
-       select CPU_HAS_INTC2_IRQ
+       select ARCH_SPARSEMEM_ENABLE
+       select SYS_SUPPORTS_NUMA
+       select SYS_SUPPORTS_SMP
 
 # SH4AL-DSP Processor Support
 
@@ -209,7 +202,6 @@ config CPU_SUBTYPE_SH7722
        bool "Support SH7722 processor"
        select CPU_SH4AL_DSP
        select CPU_SHX2
-       select CPU_HAS_INTC_IRQ
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
 
@@ -274,7 +266,7 @@ config 32BIT
 
 config X2TLB
        bool "Enable extended TLB mode"
-       depends on CPU_SHX2 && MMU && EXPERIMENTAL
+       depends on (CPU_SHX2 || CPU_SHX3) && MMU && EXPERIMENTAL
        help
          Selecting this option will enable the extended mode of the SH-X2
          TLB. For legacy SH-X behaviour and interoperability, say N. For
@@ -307,6 +299,7 @@ config NUMA
 
 config NODES_SHIFT
        int
+       default "3" if CPU_SUBTYPE_SHX3
        default "1"
        depends on NEED_MULTIPLE_NODES
 
@@ -323,7 +316,9 @@ config ARCH_SPARSEMEM_DEFAULT
 
 config MAX_ACTIVE_REGIONS
        int
-       default "2" if (CPU_SUBTYPE_SH7722 && SPARSEMEM)
+       default "6" if (CPU_SUBTYPE_SHX3 && SPARSEMEM)
+       default "2" if SPARSEMEM && (CPU_SUBTYPE_SH7722 || \
+                      CPU_SUBTYPE_SH7785)
        default "1"
 
 config ARCH_POPULATES_NODE_MAP
@@ -342,25 +337,27 @@ config ARCH_MEMORY_PROBE
 
 choice
        prompt "Kernel page size"
+       default PAGE_SIZE_8KB if X2TLB
        default PAGE_SIZE_4KB
 
 config PAGE_SIZE_4KB
        bool "4kB"
+       depends on !X2TLB
        help
          This is the default page size used by all SuperH CPUs.
 
 config PAGE_SIZE_8KB
        bool "8kB"
-       depends on EXPERIMENTAL && X2TLB
+       depends on X2TLB
        help
          This enables 8kB pages as supported by SH-X2 and later MMUs.
 
 config PAGE_SIZE_64KB
        bool "64kB"
-       depends on EXPERIMENTAL && CPU_SH4
+       depends on CPU_SH4
        help
          This enables support for 64kB pages, possible on all SH-4
-         CPUs and later. Highly experimental, not recommended.
+         CPUs and later.
 
 endchoice
 
@@ -412,8 +409,17 @@ config SH_DIRECT_MAPPED
          Turn this option off for platforms that do not have a direct-mapped
          cache, and you have no need to run the caches in such a configuration.
 
-config SH_WRITETHROUGH
-       bool "Use write-through caching"
+choice
+       prompt "Cache mode"
+       default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4
+       default CACHE_WRITETHROUGH if (CPU_SH2 && !CPU_SH2A)
+
+config CACHE_WRITEBACK
+       bool "Write-back"
+       depends on CPU_SH2A || CPU_SH3 || CPU_SH4
+
+config CACHE_WRITETHROUGH
+       bool "Write-through"
        help
          Selecting this option will configure the caches in write-through
          mode, as opposed to the default write-back configuration.
@@ -424,4 +430,9 @@ config SH_WRITETHROUGH
 
          If unsure, say N.
 
+config CACHE_OFF
+       bool "Off"
+
+endchoice
+
 endmenu
index 4061e89d84d09fff645297747e28482f5364a76b..ee30fb44dfe107d1acc1e5f70292c3d57438baf3 100644 (file)
@@ -4,29 +4,32 @@
 
 obj-y                  := init.o extable.o consistent.o
 
-obj-$(CONFIG_CPU_SH2)  += cache-sh2.o
-obj-$(CONFIG_CPU_SH3)  += cache-sh3.o
-obj-$(CONFIG_CPU_SH4)  += cache-sh4.o
+ifndef CONFIG_CACHE_OFF
+obj-$(CONFIG_CPU_SH2)          += cache-sh2.o
+obj-$(CONFIG_CPU_SH3)          += cache-sh3.o
+obj-$(CONFIG_CPU_SH4)          += cache-sh4.o
+obj-$(CONFIG_SH7705_CACHE_32KB)        += cache-sh7705.o
+endif
 
 mmu-y                  := tlb-nommu.o pg-nommu.o
-mmu-$(CONFIG_CPU_SH3)  += fault-nommu.o
-mmu-$(CONFIG_CPU_SH4)  += fault-nommu.o
 mmu-$(CONFIG_MMU)      := fault.o clear_page.o copy_page.o tlb-flush.o \
                           ioremap.o
 
 obj-y                  += $(mmu-y)
 
 ifdef CONFIG_DEBUG_FS
-obj-$(CONFIG_CPU_SH4)          += cache-debugfs.o
+obj-$(CONFIG_CPU_SH4)  += cache-debugfs.o
 endif
 
 ifdef CONFIG_MMU
-obj-$(CONFIG_CPU_SH3)          += tlb-sh3.o
-obj-$(CONFIG_CPU_SH4)          += tlb-sh4.o pg-sh4.o
-obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
+obj-$(CONFIG_CPU_SH3)  += tlb-sh3.o
+obj-$(CONFIG_CPU_SH4)  += tlb-sh4.o
+ifndef CONFIG_CACHE_OFF
+obj-$(CONFIG_CPU_SH4)          += pg-sh4.o
+obj-$(CONFIG_SH7705_CACHE_32KB)        += pg-sh7705.o
+endif
 endif
 
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
-obj-$(CONFIG_SH7705_CACHE_32KB)        += cache-sh7705.o
 obj-$(CONFIG_32BIT)            += pmb.o
 obj-$(CONFIG_NUMA)             += numa.o
index 86486326ef1d5fbc465d47b6542c867edb688fa2..226b190c5b9c29f045fdb5041ff6201c4263c493 100644 (file)
@@ -2,7 +2,7 @@
  * arch/sh/mm/cache-sh4.c
  *
  * Copyright (C) 1999, 2000, 2002  Niibe Yutaka
- * Copyright (C) 2001 - 2006  Paul Mundt
+ * Copyright (C) 2001 - 2007  Paul Mundt
  * Copyright (C) 2003  Richard Curnow
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -44,7 +44,7 @@ static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
 static void compute_alias(struct cache_info *c)
 {
        c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1);
-       c->n_aliases = (c->alias_mask >> PAGE_SHIFT) + 1;
+       c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0;
 }
 
 static void __init emit_cache_params(void)
@@ -54,21 +54,35 @@ static void __init emit_cache_params(void)
                ctrl_inl(CCN_CVR),
                ctrl_inl(CCN_PRR));
        printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n",
-               current_cpu_data.icache.ways,
-               current_cpu_data.icache.sets,
-               current_cpu_data.icache.way_incr);
+               boot_cpu_data.icache.ways,
+               boot_cpu_data.icache.sets,
+               boot_cpu_data.icache.way_incr);
        printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
-               current_cpu_data.icache.entry_mask,
-               current_cpu_data.icache.alias_mask,
-               current_cpu_data.icache.n_aliases);
+               boot_cpu_data.icache.entry_mask,
+               boot_cpu_data.icache.alias_mask,
+               boot_cpu_data.icache.n_aliases);
        printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n",
-               current_cpu_data.dcache.ways,
-               current_cpu_data.dcache.sets,
-               current_cpu_data.dcache.way_incr);
+               boot_cpu_data.dcache.ways,
+               boot_cpu_data.dcache.sets,
+               boot_cpu_data.dcache.way_incr);
        printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
-               current_cpu_data.dcache.entry_mask,
-               current_cpu_data.dcache.alias_mask,
-               current_cpu_data.dcache.n_aliases);
+               boot_cpu_data.dcache.entry_mask,
+               boot_cpu_data.dcache.alias_mask,
+               boot_cpu_data.dcache.n_aliases);
+
+       /*
+        * Emit Secondary Cache parameters if the CPU has a probed L2.
+        */
+       if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) {
+               printk("S-cache : n_ways=%d n_sets=%d way_incr=%d\n",
+                       boot_cpu_data.scache.ways,
+                       boot_cpu_data.scache.sets,
+                       boot_cpu_data.scache.way_incr);
+               printk("S-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
+                       boot_cpu_data.scache.entry_mask,
+                       boot_cpu_data.scache.alias_mask,
+                       boot_cpu_data.scache.n_aliases);
+       }
 
        if (!__flush_dcache_segment_fn)
                panic("unknown number of cache ways\n");
@@ -79,10 +93,11 @@ static void __init emit_cache_params(void)
  */
 void __init p3_cache_init(void)
 {
-       compute_alias(&current_cpu_data.icache);
-       compute_alias(&current_cpu_data.dcache);
+       compute_alias(&boot_cpu_data.icache);
+       compute_alias(&boot_cpu_data.dcache);
+       compute_alias(&boot_cpu_data.scache);
 
-       switch (current_cpu_data.dcache.ways) {
+       switch (boot_cpu_data.dcache.ways) {
        case 1:
                __flush_dcache_segment_fn = __flush_dcache_segment_1way;
                break;
@@ -187,13 +202,13 @@ void flush_cache_sigtramp(unsigned long addr)
                     : "m" (__m(v)));
 
        index = CACHE_IC_ADDRESS_ARRAY |
-                       (v & current_cpu_data.icache.entry_mask);
+                       (v & boot_cpu_data.icache.entry_mask);
 
        local_irq_save(flags);
        jump_to_P2();
 
-       for (i = 0; i < current_cpu_data.icache.ways;
-            i++, index += current_cpu_data.icache.way_incr)
+       for (i = 0; i < boot_cpu_data.icache.ways;
+            i++, index += boot_cpu_data.icache.way_incr)
                ctrl_outl(0, index);    /* Clear out Valid-bit */
 
        back_to_P1();
@@ -210,7 +225,7 @@ static inline void flush_cache_4096(unsigned long start,
         * All types of SH-4 require PC to be in P2 to operate on the I-cache.
         * Some types of SH-4 require PC to be in P2 to operate on the D-cache.
         */
-       if ((current_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) ||
+       if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) ||
            (start < CACHE_OC_ADDRESS_ARRAY))
                exec_offset = 0x20000000;
 
@@ -232,7 +247,7 @@ void flush_dcache_page(struct page *page)
                int i, n;
 
                /* Loop all the D-cache */
-               n = current_cpu_data.dcache.n_aliases;
+               n = boot_cpu_data.dcache.n_aliases;
                for (i = 0; i < n; i++, addr += 4096)
                        flush_cache_4096(addr, phys);
        }
@@ -264,7 +279,7 @@ static inline void flush_icache_all(void)
 
 void flush_dcache_all(void)
 {
-       (*__flush_dcache_segment_fn)(0UL, current_cpu_data.dcache.way_size);
+       (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size);
        wmb();
 }
 
@@ -278,8 +293,8 @@ static void __flush_cache_mm(struct mm_struct *mm, unsigned long start,
                             unsigned long end)
 {
        unsigned long d = 0, p = start & PAGE_MASK;
-       unsigned long alias_mask = current_cpu_data.dcache.alias_mask;
-       unsigned long n_aliases = current_cpu_data.dcache.n_aliases;
+       unsigned long alias_mask = boot_cpu_data.dcache.alias_mask;
+       unsigned long n_aliases = boot_cpu_data.dcache.n_aliases;
        unsigned long select_bit;
        unsigned long all_aliases_mask;
        unsigned long addr_offset;
@@ -366,7 +381,7 @@ void flush_cache_mm(struct mm_struct *mm)
         * If cache is only 4k-per-way, there are never any 'aliases'.  Since
         * the cache is physically tagged, the data can just be left in there.
         */
-       if (current_cpu_data.dcache.n_aliases == 0)
+       if (boot_cpu_data.dcache.n_aliases == 0)
                return;
 
        /*
@@ -403,7 +418,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
        unsigned long phys = pfn << PAGE_SHIFT;
        unsigned int alias_mask;
 
-       alias_mask = current_cpu_data.dcache.alias_mask;
+       alias_mask = boot_cpu_data.dcache.alias_mask;
 
        /* We only need to flush D-cache when we have alias */
        if ((address^phys) & alias_mask) {
@@ -417,7 +432,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
                        phys);
        }
 
-       alias_mask = current_cpu_data.icache.alias_mask;
+       alias_mask = boot_cpu_data.icache.alias_mask;
        if (vma->vm_flags & VM_EXEC) {
                /*
                 * Evict entries from the portion of the cache from which code
@@ -449,7 +464,7 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
         * If cache is only 4k-per-way, there are never any 'aliases'.  Since
         * the cache is physically tagged, the data can just be left in there.
         */
-       if (current_cpu_data.dcache.n_aliases == 0)
+       if (boot_cpu_data.dcache.n_aliases == 0)
                return;
 
        /*
@@ -510,7 +525,7 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys,
        unsigned long a, ea, p;
        unsigned long temp_pc;
 
-       dcache = &current_cpu_data.dcache;
+       dcache = &boot_cpu_data.dcache;
        /* Write this way for better assembly. */
        way_count = dcache->ways;
        way_incr = dcache->way_incr;
@@ -585,7 +600,7 @@ static void __flush_dcache_segment_1way(unsigned long start,
        base_addr = ((base_addr >> 16) << 16);
        base_addr |= start;
 
-       dcache = &current_cpu_data.dcache;
+       dcache = &boot_cpu_data.dcache;
        linesz = dcache->linesz;
        way_incr = dcache->way_incr;
        way_size = dcache->way_size;
@@ -627,7 +642,7 @@ static void __flush_dcache_segment_2way(unsigned long start,
        base_addr = ((base_addr >> 16) << 16);
        base_addr |= start;
 
-       dcache = &current_cpu_data.dcache;
+       dcache = &boot_cpu_data.dcache;
        linesz = dcache->linesz;
        way_incr = dcache->way_incr;
        way_size = dcache->way_size;
@@ -686,7 +701,7 @@ static void __flush_dcache_segment_4way(unsigned long start,
        base_addr = ((base_addr >> 16) << 16);
        base_addr |= start;
 
-       dcache = &current_cpu_data.dcache;
+       dcache = &boot_cpu_data.dcache;
        linesz = dcache->linesz;
        way_incr = dcache->way_incr;
        way_size = dcache->way_size;
index ae039f2da16271c75e3013b97fa8a523a3b97621..a81dbdb05596993a580e9fb69d876133c1990d9c 100644 (file)
@@ -141,47 +141,38 @@ ENTRY(__copy_user_page)
        .long 9999b, 6000f      ;       \
        .previous
 ENTRY(__copy_user)
-       tst     r6,r6           ! Check explicitly for zero
-       bf      1f
-       rts
-        mov    #0,r0           ! normal return
-1:
-       mov.l   r10,@-r15
-       mov.l   r9,@-r15
-       mov.l   r8,@-r15
+       ! Check if small number of bytes
+       mov     #11,r0
        mov     r4,r3
-       add     r6,r3           ! last destination address
-       mov     #12,r0          ! Check if small number of bytes
-       cmp/gt  r0,r6
-       bt      2f
-       bra     .L_cleanup_loop
-        nop
-2:
-       neg     r5,r0           ! Calculate bytes needed to align source
+       cmp/gt  r0,r6           ! r6 (len) > r0 (11)
+       bf/s    .L_cleanup_loop_no_pop
+        add    r6,r3           ! last destination address
+
+       ! Calculate bytes needed to align to src
+       mov.l   r11,@-r15
+       neg     r5,r0
+       mov.l   r10,@-r15
        add     #4,r0
+       mov.l   r9,@-r15
        and     #3,r0
+       mov.l   r8,@-r15
        tst     r0,r0
-       bt      .L_jump
-       mov     r0,r1
+       bt      2f
 
-.L_loop1:
-       ! Copy bytes to align source
-EX(    mov.b   @r5+,r0         )
-       dt      r1
-EX(    mov.b   r0,@r4          )
+1:
+       ! Copy bytes to long word align src
+EX(    mov.b   @r5+,r1         )
+       dt      r0
        add     #-1,r6
-       bf/s    .L_loop1
+EX(    mov.b   r1,@r4          )
+       bf/s    1b
         add    #1,r4
 
-.L_jump:
-       mov     r6,r2           ! Calculate number of longwords to copy
+       ! Jump to appropriate routine depending on dest
+2:     mov     #3,r1
+       mov     r6, r2
+       and     r4,r1
        shlr2   r2
-       tst     r2,r2
-       bt      .L_cleanup
-
-       mov     r4,r0           ! Jump to appropriate routine
-       and     #3,r0
-       mov     r0,r1
        shll2   r1
        mova    .L_jump_tbl,r0
        mov.l   @(r0,r1),r1
@@ -195,43 +186,97 @@ EX(       mov.b   r0,@r4          )
        .long   .L_dest10
        .long   .L_dest11
 
+/*
+ * Come here if there are less than 12 bytes to copy
+ *
+ * Keep the branch target close, so the bf/s callee doesn't overflow
+ * and result in a more expensive branch being inserted. This is the
+ * fast-path for small copies, the jump via the jump table will hit the
+ * default slow-path cleanup. -PFM.
+ */
+.L_cleanup_loop_no_pop:
+       tst     r6,r6           ! Check explicitly for zero
+       bt      1f
+
+2:
+EX(    mov.b   @r5+,r0         )
+       dt      r6
+EX(    mov.b   r0,@r4          )
+       bf/s    2b
+        add    #1,r4
+
+1:     mov     #0,r0           ! normal return
+5000:
+
+# Exception handler:
+.section .fixup, "ax"
+6000:
+       mov.l   8000f,r1
+       mov     r3,r0
+       jmp     @r1
+        sub    r4,r0
+       .align  2
+8000:  .long   5000b
+
+.previous
+       rts
+        nop
+
 ! Destination = 00
 
 .L_dest00:
-       mov     r2,r7
-       shlr2   r7
-       shlr    r7
-       tst     r7,r7
-       mov     #7,r0
-       bt/s    1f
-        and    r0,r2
-       .align 2
+       ! Skip the large copy for small transfers
+       mov     #(32+32-4), r0
+       cmp/gt  r6, r0          ! r0 (60) > r6 (len)
+       bt      1f
+
+       ! Align dest to a 32 byte boundary
+       neg     r4,r0
+       add     #0x20, r0
+       and     #0x1f, r0
+       tst     r0, r0
+       bt      2f
+
+       sub     r0, r6
+       shlr2   r0
+3:
+EX(    mov.l   @r5+,r1         )
+       dt      r0
+EX(    mov.l   r1,@r4          )
+       bf/s    3b
+        add    #4,r4
+
 2:
 EX(    mov.l   @r5+,r0         )
+EX(    mov.l   @r5+,r1         )
+EX(    mov.l   @r5+,r2         )
+EX(    mov.l   @r5+,r7         )
 EX(    mov.l   @r5+,r8         )
 EX(    mov.l   @r5+,r9         )
 EX(    mov.l   @r5+,r10        )
-EX(    mov.l   r0,@r4          )
-EX(    mov.l   r8,@(4,r4)      )
-EX(    mov.l   r9,@(8,r4)      )
-EX(    mov.l   r10,@(12,r4)    )
-EX(    mov.l   @r5+,r0         )
-EX(    mov.l   @r5+,r8         )
-EX(    mov.l   @r5+,r9         )
-EX(    mov.l   @r5+,r10        )
-       dt      r7
-EX(    mov.l   r0,@(16,r4)     )
-EX(    mov.l   r8,@(20,r4)     )
-EX(    mov.l   r9,@(24,r4)     )
-EX(    mov.l   r10,@(28,r4)    )
+EX(    mov.l   @r5+,r11        )
+EX(    movca.l r0,@r4          )
+       add     #-32, r6
+EX(    mov.l   r1,@(4,r4)      )
+       mov     #32, r0
+EX(    mov.l   r2,@(8,r4)      )
+       cmp/gt  r6, r0          ! r0 (32) > r6 (len)
+EX(    mov.l   r7,@(12,r4)     )
+EX(    mov.l   r8,@(16,r4)     )
+EX(    mov.l   r9,@(20,r4)     )
+EX(    mov.l   r10,@(24,r4)    )
+EX(    mov.l   r11,@(28,r4)    )
        bf/s    2b
         add    #32,r4
-       tst     r2,r2
+
+1:     mov     r6, r0
+       shlr2   r0
+       tst     r0, r0
        bt      .L_cleanup
 1:
-EX(    mov.l   @r5+,r0         )
-       dt      r2
-EX(    mov.l   r0,@r4          )
+EX(    mov.l   @r5+,r1         )
+       dt      r0
+EX(    mov.l   r1,@r4          )
        bf/s    1b
         add    #4,r4
 
@@ -250,7 +295,7 @@ EX( mov.l   r0,@r4          )
         and    r0,r2
 2:
        dt      r7
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
 EX(    mov.l   @r5+,r0         )
 EX(    mov.l   @r5+,r1         )
 EX(    mov.l   @r5+,r8         )
@@ -320,7 +365,7 @@ EX( mov.w   r0,@(2,r4)      )
 1:     ! Read longword, write two words per iteration
 EX(    mov.l   @r5+,r0         )
        dt      r2
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
 EX(    mov.w   r0,@r4          )
        shlr16  r0
 EX(    mov.w   r0,@(2,r4)      )
@@ -342,7 +387,7 @@ EX( mov.w   r0,@r4          )
        ! Read longword, write byte, word, byte per iteration
 EX(    mov.l   @r5+,r0         )
        dt      r2
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
 EX(    mov.b   r0,@r4          )
        shlr8   r0
        add     #1,r4
@@ -379,6 +424,7 @@ EX( mov.b   r0,@r4          )
 
 .L_exit:
        mov     #0,r0           ! normal return
+
 5000:
 
 # Exception handler:
@@ -394,5 +440,6 @@ EX( mov.b   r0,@r4          )
 .previous
        mov.l   @r15+,r8
        mov.l   @r15+,r9
+       mov.l   @r15+,r10
        rts
-        mov.l  @r15+,r10
+        mov.l  @r15+,r11
diff --git a/arch/sh/mm/fault-nommu.c b/arch/sh/mm/fault-nommu.c
deleted file mode 100644 (file)
index c6f5b51..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * arch/sh/mm/fault-nommu.c
- *
- * Copyright (C) 2002 - 2007 Paul Mundt
- *
- * Based on linux/arch/sh/mm/fault.c:
- *  Copyright (C) 1999  Niibe Yutaka
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/hardirq.h>
-#include <linux/kprobes.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/kgdb.h>
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
-                                       unsigned long writeaccess,
-                                       unsigned long address)
-{
-       trace_hardirqs_on();
-       local_irq_enable();
-
-#if defined(CONFIG_SH_KGDB)
-       if (kgdb_nofault && kgdb_bus_err_hook)
-               kgdb_bus_err_hook();
-#endif
-
-       /*
-        * Oops. The kernel tried to access some bad page. We'll have to
-        * terminate things with extreme prejudice.
-        *
-        */
-       if (address < PAGE_SIZE) {
-               printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-       } else {
-               printk(KERN_ALERT "Unable to handle kernel paging request");
-       }
-
-       printk(" at virtual address %08lx\n", address);
-       printk(KERN_ALERT "pc = %08lx\n", regs->pc);
-
-       die("Oops", regs, writeaccess);
-       do_exit(SIGKILL);
-}
-
-asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
-                                        unsigned long writeaccess,
-                                        unsigned long address)
-{
-#if defined(CONFIG_SH_KGDB)
-       if (kgdb_nofault && kgdb_bus_err_hook)
-               kgdb_bus_err_hook();
-#endif
-
-       return (address >= TASK_SIZE);
-}
index a08a4a958adda563d0472b1534011da088f0524a..7d43758dc2442276fe9391a6b75ac823d1e0454b 100644 (file)
@@ -145,7 +145,7 @@ repeat:
 
        ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
 
-#ifdef CONFIG_SH_WRITETHROUGH
+#ifdef CONFIG_CACHE_WRITETHROUGH
        /*
         * When we are in 32-bit address extended mode, CCR.CB becomes
         * invalid, so care must be taken to manually adjust cacheable
index f74cf667c8fa8e4703d5936859c550c6a257b568..2d1dd6044307e1d3b6049b74708c4e7e00aca7f9 100644 (file)
@@ -4,27 +4,14 @@
  * SH-4 specific TLB operations
  *
  * Copyright (C) 1999  Niibe Yutaka
- * Copyright (C) 2002  Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
  *
  * Released under the terms of the GNU GPL v2.0.
  */
-#include <linux/signal.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
 #include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 
@@ -34,22 +21,27 @@ void update_mmu_cache(struct vm_area_struct * vma,
        unsigned long flags;
        unsigned long pteval;
        unsigned long vpn;
-       struct page *page;
-       unsigned long pfn;
 
        /* Ptrace may call this routine. */
        if (vma && current->active_mm != vma->vm_mm)
                return;
 
-       pfn = pte_pfn(pte);
-       if (pfn_valid(pfn)) {
-               page = pfn_to_page(pfn);
-               if (!test_bit(PG_mapped, &page->flags)) {
-                       unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
-                       __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE);
-                       __set_bit(PG_mapped, &page->flags);
+#ifndef CONFIG_CACHE_OFF
+       {
+               unsigned long pfn = pte_pfn(pte);
+
+               if (pfn_valid(pfn)) {
+                       struct page *page = pfn_to_page(pfn);
+
+                       if (!test_bit(PG_mapped, &page->flags)) {
+                               unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
+                               __flush_wback_region((void *)P1SEGADDR(phys),
+                                                    PAGE_SIZE);
+                               __set_bit(PG_mapped, &page->flags);
+                       }
                }
        }
+#endif
 
        local_irq_save(flags);
 
@@ -57,16 +49,26 @@ void update_mmu_cache(struct vm_area_struct * vma,
        vpn = (address & MMU_VPN_MASK) | get_asid();
        ctrl_outl(vpn, MMU_PTEH);
 
-       pteval = pte_val(pte);
+       pteval = pte.pte_low;
 
        /* Set PTEA register */
+#ifdef CONFIG_X2TLB
+       /*
+        * For the extended mode TLB this is trivial, only the ESZ and
+        * EPR bits need to be written out to PTEA, with the remainder of
+        * the protection bits (with the exception of the compat-mode SZ
+        * and PR bits, which are cleared) being written out in PTEL.
+        */
+       ctrl_outl(pte.pte_high, MMU_PTEA);
+#else
        if (cpu_data->flags & CPU_HAS_PTEA)
                /* TODO: make this look less hacky */
                ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
+#endif
 
        /* Set PTEL register */
        pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-#ifdef CONFIG_SH_WRITETHROUGH
+#ifdef CONFIG_CACHE_WRITETHROUGH
        pteval |= _PAGE_WT;
 #endif
        /* conveniently, we want all the software flags to be 0 anyway */
@@ -93,4 +95,3 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page)
        ctrl_outl(data, addr);
        back_to_P1();
 }
-
index 5664631d8ae5af2ae76d6091e9d4d6bb1459134a..b3327ce8e82f464f2cf81adf92c8f8e30d571d0c 100644 (file)
@@ -36,6 +36,14 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config GENERIC_HARDIRQS
+       bool
+       default y
+
+config GENERIC_IRQ_PROBE
+       bool
+       default y
+
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
@@ -58,18 +66,12 @@ choice
        prompt "SuperH system type"
        default SH_SIMULATOR
 
-config SH_GENERIC
-       bool "Generic"
-
 config SH_SIMULATOR
        bool "Simulator"
 
 config SH_CAYMAN
        bool "Cayman"
 
-config SH_ROMRAM
-       bool "ROM/RAM"
-
 config SH_HARP
        bool "ST50-Harp"
 
@@ -152,60 +154,54 @@ comment "Memory options"
 
 config CACHED_MEMORY_OFFSET
        hex "Cached Area Offset"
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
        default "20000000"
 
 config MEMORY_START
        hex "Physical memory start address"
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
        default "80000000"
 
 config MEMORY_SIZE_IN_MB
-       int "Memory size (in MB)" if SH_HARP || SH_CAYMAN || SH_SIMULATOR
-       default "64" if SH_HARP || SH_CAYMAN
+       int "Memory size (in MB)"
        default "8" if SH_SIMULATOR
+       default "64"
 
 comment "Cache options"
 
-config DCACHE_DISABLED
-       bool "DCache Disabling"
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
-
 choice
        prompt "DCache mode"
-       depends on !DCACHE_DISABLED && !SH_SIMULATOR
+       default DCACHE_DISABLED if SH_SIMULATOR
        default DCACHE_WRITE_BACK
 
 config DCACHE_WRITE_BACK
        bool "Write-back"
+       depends on !SH_SIMULATOR
 
 config DCACHE_WRITE_THROUGH
        bool "Write-through"
+       depends on !SH_SIMULATOR
+
+config DCACHE_DISABLED
+       bool "Disabled"
 
 endchoice
 
 config ICACHE_DISABLED
        bool "ICache Disabling"
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
 
 config PCIDEVICE_MEMORY_START
        hex
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
        default "C0000000"
 
 config DEVICE_MEMORY_START
        hex
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
        default "E0000000"
 
 config FLASH_MEMORY_START
        hex "Flash memory/on-chip devices start address"
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
        default "00000000"
 
 config PCI_BLOCK_START
        hex "PCI block start address"
-       depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR
        default "40000000"
 
 comment "CPU Subtype specific options"
@@ -214,8 +210,10 @@ config SH64_ID2815_WORKAROUND
        bool "Include workaround for SH5-101 cut2 silicon defect ID2815"
 
 comment "Misc options"
+
 config HEARTBEAT
        bool "Heartbeat LED"
+       depends on SH_CAYMAN
 
 config HDSP253_LED
        bool "Support for HDSP-253 LED"
@@ -242,6 +240,7 @@ config SBUS
 
 config PCI
        bool "PCI support"
+       depends on SH_CAYMAN
        help
          Find out whether you have a PCI motherboard. PCI is the name of a
          bus system, i.e. the way the CPU talks to the other stuff inside
@@ -294,15 +293,3 @@ source "security/Kconfig"
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
-
-#
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_HARDIRQS
-       bool
-       default y
-
-config GENERIC_IRQ_PROBE
-       bool
-       default y
-
index 26d842c07139697a1869cd755c02ebe17315d7a9..05c07c4e4ed647d0b5d8a7a6a164ae639292b0be 100644 (file)
@@ -5,9 +5,6 @@ source "lib/Kconfig.debug"
 config EARLY_PRINTK
        bool "Early SCIF console support"
 
-config DEBUG_KERNEL_WITH_GDB_STUB
-       bool "GDB Stub kernel debug"
-
 config SH64_PROC_TLB
        bool "Debug: report TLB fill/purge activity through /proc/tlb"
        depends on PROC_FS
@@ -28,17 +25,9 @@ config POOR_MANS_STRACE
 
 config SH_ALPHANUMERIC
        bool "Enable debug outputs to on-board alphanumeric display"
+       depends on SH_CAYMAN
 
 config SH_NO_BSS_INIT
        bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
 
-config FRAME_POINTER
-       bool "Compile the kernel with frame pointers"
-       default y if KGDB
-       help
-         If you say Y here the resulting kernel image will be slightly larger
-         and slower, but it will give very useful debugging information.
-         If you don't debug the kernel, you can say N, but we may not be able
-         to solve problems without frame pointers.
-
 endmenu
index ebf20043991ce073b6e4ec3d6161a24f5bb2e141..8290c6380d7d6f09c8604457d4b4f9d8080dc2d7 100644 (file)
@@ -40,6 +40,8 @@ OBJCOPYFLAGS  := -O binary -R .note -R .comment -R .stab -R .stabstr -S
 #
 KBUILD_DEFCONFIG       := cayman_defconfig
 
+KBUILD_IMAGE           := arch/$(ARCH)/boot/zImage
+
 ifdef LOADADDR
 LINKFLAGS     += -Ttext $(word 1,$(LOADADDR))
 endif
@@ -47,7 +49,6 @@ endif
 machine-$(CONFIG_SH_CAYMAN)    := cayman
 machine-$(CONFIG_SH_SIMULATOR) := sim
 machine-$(CONFIG_SH_HARP)      := harp
-machine-$(CONFIG_SH_ROMRAM)    := romram
 
 head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o
 
@@ -106,6 +107,5 @@ arch/$(ARCH)/lib/syscalltab.h: arch/sh64/kernel/syscalls.S
 CLEAN_FILES += arch/$(ARCH)/lib/syscalltab.h
 
 define archhelp
-       @echo '  zImage                    - Compressed kernel image (arch/sh64/boot/zImage)'
+       @echo '* zImage                    - Compressed kernel image'
 endef
-
index 784434143343f547bf31b9b08b355e2a6e3c7095..91b59118c1b19f28737555b88fbdccde9613c062 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22
-# Fri Jul 20 12:28:34 2007
+# Linux kernel version: 2.6.23-rc8
+# Tue Oct  9 15:37:16 2007
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH64=y
@@ -11,21 +11,20 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
@@ -57,7 +56,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -67,7 +65,12 @@ CONFIG_SLAB=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
@@ -90,10 +93,8 @@ CONFIG_DEFAULT_IOSCHED="cfq"
 #
 # System type
 #
-# CONFIG_SH_GENERIC is not set
 # CONFIG_SH_SIMULATOR is not set
 CONFIG_SH_CAYMAN=y
-# CONFIG_SH_ROMRAM is not set
 # CONFIG_SH_HARP is not set
 CONFIG_CPU_SH5=y
 CONFIG_CPU_SUBTYPE_SH5_101=y
@@ -119,9 +120,9 @@ CONFIG_MEMORY_SIZE_IN_MB=128
 #
 # Cache options
 #
-# CONFIG_DCACHE_DISABLED is not set
 CONFIG_DCACHE_WRITE_BACK=y
 # CONFIG_DCACHE_WRITE_THROUGH is not set
+# CONFIG_DCACHE_DISABLED is not set
 # CONFIG_ICACHE_DISABLED is not set
 CONFIG_PCIDEVICE_MEMORY_START=C0000000
 CONFIG_DEVICE_MEMORY_START=E0000000
@@ -151,7 +152,6 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_NR_QUICK=1
-CONFIG_VIRT_TO_BUS=y
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -276,7 +276,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_MTD is not set
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
-# CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
@@ -325,6 +324,7 @@ CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -332,12 +332,8 @@ CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
@@ -347,7 +343,6 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
@@ -449,6 +444,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -572,7 +568,6 @@ CONFIG_WATCHDOG=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_SH_WDT is not set
 
 #
 # PCI-based Watchdog Cards
@@ -586,7 +581,59 @@ CONFIG_HW_RANDOM=y
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
 # SPI support
@@ -599,16 +646,51 @@ CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
@@ -621,8 +703,115 @@ CONFIG_HWMON=y
 #
 # Multimedia devices
 #
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_DEV=m
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_TEA5761 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_DVB_CORE=y
+# CONFIG_DVB_CORE_ATTACH is not set
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+# CONFIG_DVB_STV0299 is not set
+# CONFIG_DVB_CX24110 is not set
+# CONFIG_DVB_CX24123 is not set
+# CONFIG_DVB_TDA8083 is not set
+# CONFIG_DVB_MT312 is not set
+# CONFIG_DVB_VES1X93 is not set
+# CONFIG_DVB_S5H1420 is not set
+# CONFIG_DVB_TDA10086 is not set
+
+#
+# DVB-T (terrestrial) frontends
+#
+# CONFIG_DVB_SP8870 is not set
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_CX22700 is not set
+# CONFIG_DVB_CX22702 is not set
+# CONFIG_DVB_L64781 is not set
+# CONFIG_DVB_TDA1004X is not set
+# CONFIG_DVB_NXT6000 is not set
+# CONFIG_DVB_MT352 is not set
+# CONFIG_DVB_ZL10353 is not set
+# CONFIG_DVB_DIB3000MB is not set
+# CONFIG_DVB_DIB3000MC is not set
+# CONFIG_DVB_DIB7000M is not set
+# CONFIG_DVB_DIB7000P is not set
+
+#
+# DVB-C (cable) frontends
+#
+# CONFIG_DVB_VES1820 is not set
+# CONFIG_DVB_TDA10021 is not set
+# CONFIG_DVB_TDA10023 is not set
+# CONFIG_DVB_STV0297 is not set
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+# CONFIG_DVB_NXT200X is not set
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+# CONFIG_DVB_BCM3510 is not set
+# CONFIG_DVB_LGDT330X is not set
+
+#
+# Tuners/PLL support
+#
+# CONFIG_DVB_PLL is not set
+# CONFIG_DVB_TDA826X is not set
+# CONFIG_DVB_TDA827X is not set
+# CONFIG_DVB_TUNER_QT1010 is not set
+# CONFIG_DVB_TUNER_MT2060 is not set
+
+#
+# Miscellaneous devices
+#
+# CONFIG_DVB_LNBP21 is not set
+# CONFIG_DVB_ISL6421 is not set
+# CONFIG_DVB_TUA6100 is not set
 CONFIG_DAB=y
 
 #
@@ -635,6 +824,7 @@ CONFIG_DAB=y
 #
 # CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 # CONFIG_FB_DDC is not set
@@ -728,24 +918,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 #
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# Real Time Clock
-#
 # CONFIG_RTC_CLASS is not set
 
 #
@@ -929,9 +1103,9 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_EARLY_PRINTK is not set
-# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
 CONFIG_SH64_PROC_TLB=y
 CONFIG_SH64_PROC_ASIDS=y
 CONFIG_SH64_SR_WATCH=y
@@ -960,5 +1134,3 @@ CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
diff --git a/arch/sh64/configs/harp_defconfig b/arch/sh64/configs/harp_defconfig
new file mode 100644 (file)
index 0000000..e4b84b5
--- /dev/null
@@ -0,0 +1,756 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc8
+# Mon Oct  1 18:01:38 2007
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH64=y
+CONFIG_MMU=y
+CONFIG_QUICKLIST=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System type
+#
+# CONFIG_SH_SIMULATOR is not set
+# CONFIG_SH_CAYMAN is not set
+CONFIG_SH_HARP=y
+CONFIG_CPU_SH5=y
+CONFIG_CPU_SUBTYPE_SH5_101=y
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+CONFIG_LITTLE_ENDIAN=y
+# CONFIG_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+CONFIG_SH64_PGTABLE_2_LEVEL=y
+# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+
+#
+# Memory options
+#
+CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+CONFIG_MEMORY_START=0x80000000
+CONFIG_MEMORY_SIZE_IN_MB=128
+
+#
+# Cache options
+#
+CONFIG_DCACHE_WRITE_BACK=y
+# CONFIG_DCACHE_WRITE_THROUGH is not set
+# CONFIG_DCACHE_DISABLED is not set
+# CONFIG_ICACHE_DISABLED is not set
+CONFIG_PCIDEVICE_MEMORY_START=C0000000
+CONFIG_DEVICE_MEMORY_START=E0000000
+CONFIG_FLASH_MEMORY_START=0x00000000
+CONFIG_PCI_BLOCK_START=0x40000000
+
+#
+# CPU Subtype specific options
+#
+CONFIG_SH64_ID2815_WORKAROUND=y
+
+#
+# Misc options
+#
+# CONFIG_SH_DMA is not set
+CONFIG_PREEMPT=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
+CONFIG_SH64_PROC_TLB=y
+CONFIG_SH64_PROC_ASIDS=y
+CONFIG_SH64_SR_WATCH=y
+# CONFIG_POOR_MANS_STRACE is not set
+# CONFIG_SH_ALPHANUMERIC is not set
+# CONFIG_SH_NO_BSS_INIT is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh64/configs/sim_defconfig b/arch/sh64/configs/sim_defconfig
new file mode 100644 (file)
index 0000000..f83bae6
--- /dev/null
@@ -0,0 +1,566 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc8
+# Mon Oct  1 17:50:35 2007
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH64=y
+CONFIG_MMU=y
+CONFIG_QUICKLIST=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_USER_NS is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System type
+#
+CONFIG_SH_SIMULATOR=y
+# CONFIG_SH_CAYMAN is not set
+# CONFIG_SH_HARP is not set
+CONFIG_CPU_SH5=y
+CONFIG_CPU_SUBTYPE_SH5_101=y
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+CONFIG_LITTLE_ENDIAN=y
+# CONFIG_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+CONFIG_SH64_PGTABLE_2_LEVEL=y
+# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+
+#
+# Memory options
+#
+CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+CONFIG_MEMORY_START=0x80000000
+CONFIG_MEMORY_SIZE_IN_MB=128
+
+#
+# Cache options
+#
+# CONFIG_DCACHE_WRITE_BACK is not set
+# CONFIG_DCACHE_WRITE_THROUGH is not set
+CONFIG_DCACHE_DISABLED=y
+# CONFIG_ICACHE_DISABLED is not set
+CONFIG_PCIDEVICE_MEMORY_START=C0000000
+CONFIG_DEVICE_MEMORY_START=E0000000
+CONFIG_FLASH_MEMORY_START=0x00000000
+CONFIG_PCI_BLOCK_START=0x40000000
+
+#
+# CPU Subtype specific options
+#
+CONFIG_SH64_ID2815_WORKAROUND=y
+
+#
+# Misc options
+#
+# CONFIG_SH_DMA is not set
+CONFIG_PREEMPT=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+CONFIG_MINIX_FS=y
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
+CONFIG_SH64_PROC_TLB=y
+CONFIG_SH64_PROC_ASIDS=y
+CONFIG_SH64_SR_WATCH=y
+# CONFIG_POOR_MANS_STRACE is not set
+# CONFIG_SH_ALPHANUMERIC is not set
+CONFIG_SH_NO_BSS_INIT=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 5816657c079c5d0c7ee8d2afcb8bebdb72af5666..e3467bda6167c268d3113026a17659235fc6de3a 100644 (file)
@@ -25,7 +25,7 @@ obj-$(CONFIG_SH_DMA)          += dma.o
 obj-$(CONFIG_SH_FPU)           += fpu.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 obj-$(CONFIG_KALLSYMS)         += unwind.o
-obj-$(CONFIG_PCI)              += pci-dma.o pcibios.o
+obj-$(CONFIG_PCI)              += pcibios.o
 obj-$(CONFIG_MODULES)          += module.o
 
 ifeq ($(CONFIG_PCI),y)
index 91707c1acd70cc4aff4467a83f88164d7b49f1cc..d1619d95fbaaf564558844b6d00608bef7857aae 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 
 void mach_alphanum(int pos, unsigned char val);
-void mach_led(int pos, int val);
 
 void print_seg(char *file, int line)
 {
index 461ea3de316fa7523bc9fadcacf31d53cdb095eb..b1705acc8e64c60b643f346b9f5e1fabf79567dc 100644 (file)
@@ -31,16 +31,11 @@ extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
 
 /* platform dependent support */
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_thread);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy_nocheck);
 
-EXPORT_SYMBOL(strstr);
-
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
@@ -50,27 +45,18 @@ EXPORT_SYMBOL(__down_trylock);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(__put_user_asm_l);
 EXPORT_SYMBOL(__get_user_asm_l);
-EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(__copy_user);
 EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strlen);
-
+EXPORT_SYMBOL(udelay);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(ndelay);
+EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(flush_dcache_page);
-
-/* For ext3 */
 EXPORT_SYMBOL(sh64_page_clear);
 
 /* Ugh.  These come in from libgcc.a at link time. */
+#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
 
-extern void __sdivsi3(void);
-extern void __muldi3(void);
-extern void __udivsi3(void);
-extern char __div_table;
-EXPORT_SYMBOL(__sdivsi3);
-EXPORT_SYMBOL(__muldi3);
-EXPORT_SYMBOL(__udivsi3);
-EXPORT_SYMBOL(__div_table);
-
-
+DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__muldi3);
+DECLARE_EXPORT(__udivsi3);
index b37f4f4981d210834a1a7d9b91a4d9430ca76021..06f3c179e345744598233a04ecdd604b2090aef2 100644 (file)
@@ -476,8 +476,18 @@ static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq0  = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL};
-static struct irqaction irq1  = { sh64_rtc_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "rtc", NULL, NULL};
+static struct irqaction irq0  = {
+       .handler = timer_interrupt,
+       .flags = IRQF_DISABLED,
+       .mask = CPU_MASK_NONE,
+       .name = "timer",
+};
+static struct irqaction irq1  = {
+       .handler = sh64_rtc_interrupt,
+       .flags = IRQF_DISABLED,
+       .mask = CPU_MASK_NONE,
+       .name = "rtc",
+};
 
 void __init time_init(void)
 {
index 267b4f9af2e18ccc1117f465a4a62406710a4ee4..f533a064da5f9d03cc7ef2c63d112d748e1bca7a 100644 (file)
 #define LOAD_OFFSET    CONFIG_CACHED_MEMORY_OFFSET
 #include <asm-generic/vmlinux.lds.h>
 
-#ifdef NOTDEF
-#ifdef CONFIG_LITTLE_ENDIAN
-OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux")
-#else
-OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64")
-#endif
-#endif
-
 OUTPUT_ARCH(sh:sh5)
 
 #define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET)
@@ -74,10 +66,12 @@ SECTIONS
   __ex_table : C_PHYS(__ex_table) { *(__ex_table) }
   __stop___ex_table = .;
 
-  RODATA
-
   _etext = .;                  /* End of text section */
 
+  NOTES 
+
+  RODATA
+
   .data : C_PHYS(.data) {                      /* Data */
        DATA_DATA
        CONSTRUCTORS
@@ -86,13 +80,9 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   .data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) }
 
-  . = ALIGN(PAGE_SIZE);
-  __per_cpu_start = .;
-  .data.percpu : C_PHYS(.data.percpu) {
-       *(.data.percpu)
-       *(.data.percpu.shared_aligned)
-  }
-  __per_cpu_end = . ;
+  PERCPU(PAGE_SIZE)
+
+  . = ALIGN(L1_CACHE_BYTES);
   .data.cacheline_aligned : C_PHYS(.data.cacheline_aligned) { *(.data.cacheline_aligned) }
 
   _edata = .;                  /* End of data section */
@@ -145,38 +135,6 @@ SECTIONS
        *(.exitcall.exit)
        }
 
-  /* Stabs debugging sections.  */
-  .stab 0 : C_PHYS(.stab) { *(.stab) }
-  .stabstr 0 : C_PHYS(.stabstr) { *(.stabstr) }
-  .stab.excl 0 : C_PHYS(.stab.excl) { *(.stab.excl) }
-  .stab.exclstr 0 : C_PHYS(.stab.exclstr) { *(.stab.exclstr) }
-  .stab.index 0 : C_PHYS(.stab.index) { *(.stab.index) }
-  .stab.indexstr 0 : C_PHYS(.stab.indexstr) { *(.stab.indexstr) }
-  .comment 0 : C_PHYS(.comment) { *(.comment) }
-  /* DWARF debug sections.
-     Symbols in the DWARF debugging section are relative to the beginning
-     of the section so we begin .debug at 0.  */
-  /* DWARF 1 */
-  .debug          0 : C_PHYS(.debug) { *(.debug) }
-  .line           0 : C_PHYS(.line) { *(.line) }
-  /* GNU DWARF 1 extensions */
-  .debug_srcinfo  0 : C_PHYS(.debug_srcinfo) { *(.debug_srcinfo) }
-  .debug_sfnames  0 : C_PHYS(.debug_sfnames) { *(.debug_sfnames) }
-  /* DWARF 1.1 and DWARF 2 */
-  .debug_aranges  0 : C_PHYS(.debug_aranges) { *(.debug_aranges) }
-  .debug_pubnames 0 : C_PHYS(.debug_pubnames) { *(.debug_pubnames) }
-  /* DWARF 2 */
-  .debug_info     0 : C_PHYS(.debug_info) { *(.debug_info) }
-  .debug_abbrev   0 : C_PHYS(.debug_abbrev) { *(.debug_abbrev) }
-  .debug_line     0 : C_PHYS(.debug_line) { *(.debug_line) }
-  .debug_frame    0 : C_PHYS(.debug_frame) { *(.debug_frame) }
-  .debug_str      0 : C_PHYS(.debug_str) { *(.debug_str) }
-  .debug_loc      0 : C_PHYS(.debug_loc) { *(.debug_loc) }
-  .debug_macinfo  0 : C_PHYS(.debug_macinfo) { *(.debug_macinfo) }
-  /* SGI/MIPS DWARF 2 extensions */
-  .debug_weaknames 0 : C_PHYS(.debug_weaknames) { *(.debug_weaknames) }
-  .debug_funcnames 0 : C_PHYS(.debug_funcnames) { *(.debug_funcnames) }
-  .debug_typenames 0 : C_PHYS(.debug_typenames) { *(.debug_typenames) }
-  .debug_varnames  0 : C_PHYS(.debug_varnames) { *(.debug_varnames) }
-  /* These must appear regardless of  .  */
+  STABS_DEBUG
+  DWARF_DEBUG
 }
index bd55017602408165e9d721abacb04a22e0a5f7a6..053137abd8a00843ec374c27cc8b44a0d271c65f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
@@ -110,7 +111,7 @@ static unsigned long do_csum(const unsigned char *buff, int len)
        if (odd)
                result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
 
-       pr_debug("\nCHECKSUM is 0x%x\n", result);
+       pr_debug("\nCHECKSUM is 0x%lx\n", result);
 
       out:
        return result;
index 587baa3dffb90c848911e8271161895fe99331e0..a3f3a2b8e25ba3af6eb39b0a764c75cb0678d61d 100644 (file)
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/io.h>
 
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the SuperH architecture, we just read/write the
- * memory location directly.
- */
-
-/* This is horrible at the moment - needs more work to do something sensible */
-#define IO_DELAY()
-
-#define OUT_DELAY(x,type) \
-void out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();}
-
-#define IN_DELAY(x,type) \
-unsigned type in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;}
-
-#if 1
-OUT_DELAY(b, long) OUT_DELAY(w, long) OUT_DELAY(l, long)
- IN_DELAY(b, long) IN_DELAY(w, long) IN_DELAY(l, long)
-#endif
 /*  Now for the string version of these functions */
 void outsb(unsigned long port, const void *addr, unsigned long count)
 {
@@ -45,6 +26,7 @@ void outsb(unsigned long port, const void *addr, unsigned long count)
                outb(*p, port);
        }
 }
+EXPORT_SYMBOL(outsb);
 
 void insb(unsigned long port, void *addr, unsigned long count)
 {
@@ -55,6 +37,7 @@ void insb(unsigned long port, void *addr, unsigned long count)
                *p = inb(port);
        }
 }
+EXPORT_SYMBOL(insb);
 
 /* For the 16 and 32 bit string functions, we have to worry about alignment.
  * The SH does not do unaligned accesses, so we have to read as bytes and
@@ -74,6 +57,7 @@ void outsw(unsigned long port, const void *addr, unsigned long count)
                outw(tmp, port);
        }
 }
+EXPORT_SYMBOL(outsw);
 
 void insw(unsigned long port, void *addr, unsigned long count)
 {
@@ -87,6 +71,7 @@ void insw(unsigned long port, void *addr, unsigned long count)
                p[1] = (tmp >> 8) & 0xff;
        }
 }
+EXPORT_SYMBOL(insw);
 
 void outsl(unsigned long port, const void *addr, unsigned long count)
 {
@@ -100,6 +85,7 @@ void outsl(unsigned long port, const void *addr, unsigned long count)
                outl(tmp, port);
        }
 }
+EXPORT_SYMBOL(outsl);
 
 void insl(unsigned long port, void *addr, unsigned long count)
 {
@@ -116,6 +102,7 @@ void insl(unsigned long port, void *addr, unsigned long count)
 
        }
 }
+EXPORT_SYMBOL(insl);
 
 void memcpy_toio(void __iomem *to, const void *from, long count)
 {
@@ -126,6 +113,7 @@ void memcpy_toio(void __iomem *to, const void *from, long count)
                writeb(*p++, to++);
        }
 }
+EXPORT_SYMBOL(memcpy_toio);
 
 void memcpy_fromio(void *to, void __iomem *from, long count)
 {
@@ -137,3 +125,4 @@ void memcpy_fromio(void *to, void __iomem *from, long count)
                from++;
        }
 }
+EXPORT_SYMBOL(memcpy_fromio);
index 5cd3d5e9c762196123b0729ae53fab8194974655..253d1e351d49af3385c1fdfc297cd03cc0622d75 100644 (file)
@@ -17,12 +17,15 @@ ioport_map(unsigned long port, unsigned int len)
 {
        return (void __iomem *)port;
 }
+EXPORT_SYMBOL(ioport_map);
 
 void ioport_unmap(void __iomem *addr)
 {
        /* Nothing .. */
 }
+EXPORT_SYMBOL(ioport_unmap);
 
+#ifdef CONFIG_PCI
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
 {
        unsigned long start = pci_resource_start(dev, bar);
@@ -41,14 +44,11 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
        /* What? */
        return NULL;
 }
+EXPORT_SYMBOL(pci_iomap);
 
 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 {
        /* Nothing .. */
 }
-
-EXPORT_SYMBOL(ioport_map);
-EXPORT_SYMBOL(ioport_unmap);
-EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
-
+#endif
index c3611cc2735f1cc722524a8e6e7bc26b6ce37f37..726c520d7eb98173f439a62e0d832e96577379ba 100644 (file)
  * lethal@linux-sh.org:          15th May 2003
  *    Use the generic procfs cpuinfo interface, just return a valid board name.
  */
-
-#include <linux/stddef.h>
 #include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
 #include <linux/kernel.h>
-#include <linux/seq_file.h>
-#include <asm/processor.h>
 #include <asm/platform.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/page.h>
+#include <asm/io.h>
 
 /*
  * Platform Dependent Interrupt Priorities.
index 63f065bad2f967a217dd1b6b692509f92243e848..2f2963fa2131bbdc1b96da296d009dbdc9ea3a81 100644 (file)
@@ -1,14 +1 @@
-#
-# Makefile for the ST50 Harp specific parts of the kernel
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-O_TARGET := harp.o
-
 obj-y := setup.o
-
-include $(TOPDIR)/Rules.make
-
index fcd90afac2975373e98006729766b93eb3c0a6e0..05011cb369bb0b5eb7e6e661f2817c5f6d63c158 100644 (file)
  * lethal@linux-sh.org:          15th May 2003
  *    Use the generic procfs cpuinfo interface, just return a valid board name.
  */
-
-#include <linux/stddef.h>
 #include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
 #include <linux/kernel.h>
-#include <asm/processor.h>
 #include <asm/platform.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/page.h>
-
-#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource)))
 
 /*
  * Platform Dependent Interrupt Priorities.
@@ -78,8 +68,10 @@ struct resource io_resources[] = {
 };
 
 struct resource kram_resources[] = {
-       { "Kernel code", 0, 0 },        /* These must be last in the array */
-       { "Kernel data", 0, 0 }         /* These must be last in the array */
+       /* These must be last in the array */
+       { .name = "Kernel code", .start = 0, .end = 0 },
+       /* These must be last in the array */
+       { .name = "Kernel data", .start = 0, .end = 0 }
 };
 
 struct resource xram_resources[] = {
@@ -95,13 +87,13 @@ struct sh64_platform platform_parms = {
        .initial_root_dev =     0x0100,
        .loader_type =          1,
        .io_res_p =             io_resources,
-       .io_res_count =         RES_COUNT(io_resources),
+       .io_res_count =         ARRAY_SIZE(io_resources),
        .kram_res_p =           kram_resources,
-       .kram_res_count =       RES_COUNT(kram_resources),
+       .kram_res_count =       ARRAY_SIZE(kram_resources),
        .xram_res_p =           xram_resources,
-       .xram_res_count =       RES_COUNT(xram_resources),
+       .xram_res_count =       ARRAY_SIZE(xram_resources),
        .rom_res_p =            rom_resources,
-       .rom_res_count =        RES_COUNT(rom_resources),
+       .rom_res_count =        ARRAY_SIZE(rom_resources),
 };
 
 int platform_int_priority[NR_INTC_IRQS] = {
@@ -135,4 +127,3 @@ const char *get_system_type(void)
 {
        return "ST50 Harp";
 }
-
diff --git a/arch/sh64/mach-romram/Makefile b/arch/sh64/mach-romram/Makefile
deleted file mode 100644 (file)
index 02d05c0..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the SH-5 ROM/RAM specific parts of the kernel
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-O_TARGET := romram.o
-
-obj-y := setup.o
-
-include $(TOPDIR)/Rules.make
-
diff --git a/arch/sh64/mach-romram/setup.c b/arch/sh64/mach-romram/setup.c
deleted file mode 100644 (file)
index eb98a16..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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 more details.
- *
- * arch/sh64/mach-romram/setup.c
- *
- * SH-5 ROM/RAM Platform Support
- *
- * This file handles the architecture-dependent parts of initialization
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * benedict.gaster@superh.com:  3rd May 2002
- *    Added support for ramdisk, removing statically linked romfs at the same time. *
- *
- * lethal@linux-sh.org:          15th May 2003
- *    Use the generic procfs cpuinfo interface, just return a valid board name.
- *
- * Sean.McGoogan@superh.com    17th Feb 2004
- *     copied from arch/sh64/mach-harp/setup.c
- */
-
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <asm/processor.h>
-#include <asm/platform.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-
-#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource)))
-
-/*
- * Platform Dependent Interrupt Priorities.
- */
-
-/* Using defaults defined in irq.h */
-#define        RES NO_PRIORITY         /* Disabled */
-#define IR0 IRL0_PRIORITY      /* IRLs */
-#define IR1 IRL1_PRIORITY
-#define IR2 IRL2_PRIORITY
-#define IR3 IRL3_PRIORITY
-#define PCA INTA_PRIORITY      /* PCI Ints */
-#define PCB INTB_PRIORITY
-#define PCC INTC_PRIORITY
-#define PCD INTD_PRIORITY
-#define SER TOP_PRIORITY
-#define ERR TOP_PRIORITY
-#define PW0 TOP_PRIORITY
-#define PW1 TOP_PRIORITY
-#define PW2 TOP_PRIORITY
-#define PW3 TOP_PRIORITY
-#define DM0 NO_PRIORITY                /* DMA Ints */
-#define DM1 NO_PRIORITY
-#define DM2 NO_PRIORITY
-#define DM3 NO_PRIORITY
-#define DAE NO_PRIORITY
-#define TU0 TIMER_PRIORITY     /* TMU Ints */
-#define TU1 NO_PRIORITY
-#define TU2 NO_PRIORITY
-#define TI2 NO_PRIORITY
-#define ATI NO_PRIORITY                /* RTC Ints */
-#define PRI NO_PRIORITY
-#define CUI RTC_PRIORITY
-#define ERI SCIF_PRIORITY      /* SCIF Ints */
-#define RXI SCIF_PRIORITY
-#define BRI SCIF_PRIORITY
-#define TXI SCIF_PRIORITY
-#define ITI TOP_PRIORITY       /* WDT Ints */
-
-/*
- * Platform dependent structures: maps and parms block.
- */
-struct resource io_resources[] = {
-       /* To be updated with external devices */
-};
-
-struct resource kram_resources[] = {
-       { "Kernel code", 0, 0 },        /* These must be last in the array */
-       { "Kernel data", 0, 0 }         /* These must be last in the array */
-};
-
-struct resource xram_resources[] = {
-       /* To be updated with external devices */
-};
-
-struct resource rom_resources[] = {
-       /* To be updated with external devices */
-};
-
-struct sh64_platform platform_parms = {
-       .readonly_rootfs =      1,
-       .initial_root_dev =     0x0100,
-       .loader_type =          1,
-       .io_res_p =             io_resources,
-       .io_res_count =         RES_COUNT(io_resources),
-       .kram_res_p =           kram_resources,
-       .kram_res_count =       RES_COUNT(kram_resources),
-       .xram_res_p =           xram_resources,
-       .xram_res_count =       RES_COUNT(xram_resources),
-       .rom_res_p =            rom_resources,
-       .rom_res_count =        RES_COUNT(rom_resources),
-};
-
-int platform_int_priority[NR_INTC_IRQS] = {
-       IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ  0- 7 */
-       RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ  8-15 */
-       PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */
-       RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */
-       TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */
-       RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */
-       RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */
-       RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */
-};
-
-void __init platform_setup(void)
-{
-       /* ROM/RAM platform leaves the decision to head.S, for now */
-       platform_parms.fpu_flags = fpu_in_use;
-}
-
-void __init platform_monitor(void)
-{
-       /* Nothing yet .. */
-}
-
-void __init platform_reserve(void)
-{
-       /* Nothing yet .. */
-}
-
-const char *get_system_type(void)
-{
-       return "ROM/RAM";
-}
-
index 819c4078fdc6512c597f56cd39a5b129c90ec001..2f2963fa2131bbdc1b96da296d009dbdc9ea3a81 100644 (file)
@@ -1,14 +1 @@
-#
-# Makefile for the SH-5 Simulator specific parts of the kernel
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-O_TARGET := sim.o
-
 obj-y := setup.o
-
-include $(TOPDIR)/Rules.make
-
index f09400c1ad1b4e8b19af701915955162097ccbd3..e3386ec1ce1fa336a2ebc793e9e8a945d247b369 100644 (file)
  * lethal@linux-sh.org:          15th May 2003
  *    Use the generic procfs cpuinfo interface, just return a valid board name.
  */
-
-#include <linux/stddef.h>
 #include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
 #include <linux/kernel.h>
-#include <asm/addrspace.h>
-#include <asm/processor.h>
 #include <asm/platform.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/page.h>
-
-#ifdef CONFIG_BLK_DEV_INITRD
-#include "../rootfs/rootfs.h"
-#endif
-
-static __init void platform_monitor(void);
-static __init void platform_setup(void);
-static __init void platform_reserve(void);
-
-
-#define        PHYS_MEMORY     CONFIG_MEMORY_SIZE_IN_MB*1024*1024
-
-#if (PHYS_MEMORY < P1SEG_FOOTPRINT_RAM)
-#error "Invalid kernel configuration. Physical memory below footprint requirements."
-#endif
-
-#define RAM_DISK_START CONFIG_MEMORY_START+P1SEG_INITRD_BLOCK  /* Top of 4MB */
-#ifdef PLATFORM_ROMFS_SIZE
-#define        RAM_DISK_SIZE   (PAGE_ALIGN(PLATFORM_ROMFS_SIZE))     /* Variable Top */
-#if ((RAM_DISK_START + RAM_DISK_SIZE) > (CONFIG_MEMORY_START + PHYS_MEMORY))
-#error "Invalid kernel configuration. ROM RootFS exceeding physical memory."
-#endif
-#else
-#define RAM_DISK_SIZE  P1SEG_INITRD_BLOCK_SIZE                 /* Top of 4MB */
-#endif
-
-#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource)))
 
 /*
  * Platform Dependent Interrupt Priorities.
@@ -101,8 +65,10 @@ struct resource io_resources[] = {
 };
 
 struct resource kram_resources[] = {
-       { "Kernel code", 0, 0 },        /* These must be last in the array */
-       { "Kernel data", 0, 0 }         /* These must be last in the array */
+       /* These must be last in the array */
+       { .name = "Kernel code", .start = 0, .end = 0 },
+       /* These must be last in the array */
+       { .name = "Kernel data", .start = 0, .end = 0 }
 };
 
 struct resource xram_resources[] = {
@@ -117,16 +83,14 @@ struct sh64_platform platform_parms = {
        .readonly_rootfs =      1,
        .initial_root_dev =     0x0100,
        .loader_type =          1,
-       .initrd_start =         RAM_DISK_START,
-       .initrd_size =          RAM_DISK_SIZE,
        .io_res_p =             io_resources,
-       .io_res_count =         RES_COUNT(io_resources),
+       .io_res_count =         ARRAY_SIZE(io_resources),
        .kram_res_p =           kram_resources,
-       .kram_res_count =       RES_COUNT(kram_resources),
+       .kram_res_count =       ARRAY_SIZE(kram_resources),
        .xram_res_p =           xram_resources,
-       .xram_res_count =       RES_COUNT(xram_resources),
+       .xram_res_count =       ARRAY_SIZE(xram_resources),
        .rom_res_p =            rom_resources,
-       .rom_res_count =        RES_COUNT(rom_resources),
+       .rom_res_count =        ARRAY_SIZE(rom_resources),
 };
 
 int platform_int_priority[NR_IRQS] = {
@@ -160,4 +124,3 @@ const char *get_system_type(void)
 {
        return "SH-5 Simulator";
 }
-
index ff19378ac90af04f8f361d9140aaf97cf7c59a59..d0e813632480747dde715f2f4b0b5b13aea6507e 100644 (file)
@@ -13,7 +13,8 @@
 # unless it's something special (ie not a .c file).
 #
 
-obj-y := init.o fault.o ioremap.o extable.o cache.o tlbmiss.o tlb.o
+obj-y := cache.o consistent.o extable.o fault.o init.o ioremap.o \
+        tlbmiss.o tlb.o
 
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 
@@ -41,4 +42,3 @@ CFLAGS_tlbmiss.o += -ffixed-r7 \
        -ffixed-r41 -ffixed-r42 -ffixed-r43  \
        -ffixed-r60 -ffixed-r61 -ffixed-r62 \
        -fomit-frame-pointer
-
similarity index 92%
rename from arch/sh64/kernel/pci-dma.c
rename to arch/sh64/mm/consistent.c
index a9328f894755f57069cad1f6a73479686deae1e8..8875a2a40da72dafa6eb2f7f8315a76d60bebe67 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/module.h>
 #include <asm/io.h>
 
 void *consistent_alloc(struct pci_dev *hwdev, size_t size,
@@ -36,6 +37,7 @@ void *consistent_alloc(struct pci_dev *hwdev, size_t size,
 
        return vp;
 }
+EXPORT_SYMBOL(consistent_alloc);
 
 void consistent_free(struct pci_dev *hwdev, size_t size,
                         void *vaddr, dma_addr_t dma_handle)
@@ -47,4 +49,4 @@ void consistent_free(struct pci_dev *hwdev, size_t size,
 
        iounmap(vaddr);
 }
-
+EXPORT_SYMBOL(consistent_free);
index 559717f30d1f9cdad84a2bf8cb906aa45bc208c4..21cf42de23e222684ca502417b8419b88a6df071 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/tlb.h>
 
-#ifdef CONFIG_BLK_DEV_INITRD
-#include <linux/blk.h>
-#endif
-
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 /*
index 990857756d44db11195d23edc5eee4564a8a7556..535304e6601f6d8987baba19e39cf09dd46b485b 100644 (file)
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/io.h>
-#include <asm/pgalloc.h>
-#include <asm/tlbflush.h>
 #include <linux/ioport.h>
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
 
 static void shmedia_mapioaddr(unsigned long, unsigned long);
 static unsigned long shmedia_ioremap(struct resource *, u32, int);
@@ -80,6 +81,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
        }
        return (void *) (offset + (char *)addr);
 }
+EXPORT_SYMBOL(__ioremap);
 
 void iounmap(void *addr)
 {
@@ -94,6 +96,7 @@ void iounmap(void *addr)
 
        kfree(area);
 }
+EXPORT_SYMBOL(iounmap);
 
 static struct resource shmedia_iomap = {
        .name   = "shmedia_iomap",
index 120f6b5293485526e82b6e0f9443fe3ce76b6b9f..87dd496f15eb1bc2eb60318b99e0c75903261dd6 100644 (file)
@@ -1,5 +1,9 @@
 menu "Kernel hacking"
 
+config TRACE_IRQFLAGS_SUPPORT
+       bool
+       default y
+
 source "lib/Kconfig.debug"
 
 config DEBUG_STACK_USAGE
index b76dc03fc3187fa50c6d80213bc8609e28fc72a3..722d67d32961eb570bc762faf49dbc3dae856811 100644 (file)
@@ -56,7 +56,7 @@
 #define SMP_NOP2
 #define SMP_NOP3
 #endif /* SMP */
-unsigned long __local_irq_save(void)
+unsigned long __raw_local_irq_save(void)
 {
        unsigned long retval;
        unsigned long tmp;
@@ -74,7 +74,7 @@ unsigned long __local_irq_save(void)
        return retval;
 }
 
-void local_irq_enable(void)
+void raw_local_irq_enable(void)
 {
        unsigned long tmp;
 
@@ -89,7 +89,7 @@ void local_irq_enable(void)
                : "memory");
 }
 
-void local_irq_restore(unsigned long old_psr)
+void raw_local_irq_restore(unsigned long old_psr)
 {
        unsigned long tmp;
 
@@ -105,9 +105,9 @@ void local_irq_restore(unsigned long old_psr)
                : "memory");
 }
 
-EXPORT_SYMBOL(__local_irq_save);
-EXPORT_SYMBOL(local_irq_enable);
-EXPORT_SYMBOL(local_irq_restore);
+EXPORT_SYMBOL(__raw_local_irq_save);
+EXPORT_SYMBOL(raw_local_irq_enable);
+EXPORT_SYMBOL(raw_local_irq_restore);
 
 /*
  * Dave Redman (djhr@tadpole.co.uk)
index 36383f73d6855a425a92e60884c20f10e4c9f6be..fb2caef79cec407f0e36497567902c88c88b2418 100644 (file)
@@ -588,7 +588,10 @@ __setup("of_debug=", of_debug);
 int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
 {
        /* initialize common driver fields */
-       drv->driver.name = drv->name;
+       if (!drv->driver.name)
+               drv->driver.name = drv->name;
+       if (!drv->driver.owner)
+               drv->driver.owner = drv->owner;
        drv->driver.bus = bus;
 
        /* register with core */
index 6a25133216207df68d62f3cded23eddd12070079..4bf78a5e8e0f8f16bdbf7277eb31f817cb8c942f 100644 (file)
@@ -347,9 +347,11 @@ static struct of_device_id clock_match[] = {
 };
 
 static struct of_platform_driver clock_driver = {
-       .name           = "clock",
        .match_table    = clock_match,
        .probe          = clock_probe,
+       .driver         = {
+               .name   = "clock",
+       },
 };
 
 
index 15109c156e832cf1bd55e71454a29cbd72ba6639..a8b4200f9cc379e0bc6319e6f2c786ae3df2f4b6 100644 (file)
@@ -1,6 +1,7 @@
 /* ld script to make SparcLinux kernel */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
 
 OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc")
 OUTPUT_ARCH(sparc)
@@ -8,84 +9,104 @@ ENTRY(_start)
 jiffies = jiffies_64 + 4;
 SECTIONS
 {
-  . = 0x10000 + SIZEOF_HEADERS;
-  .text 0xf0004000 :
-  {
-    _text = .;
-    TEXT_TEXT
-    SCHED_TEXT
-    LOCK_TEXT
-    *(.gnu.warning)
-  } =0
-  _etext = .;
-  PROVIDE (etext = .);
-  RODATA
-  .data    :
-  {
-    DATA_DATA
-    CONSTRUCTORS
-  }
-  .data1   : { *(.data1) }
-  _edata  =  .;
-  PROVIDE (edata = .);
-  __start___fixup = .;
-  .fixup   : { *(.fixup) }
-  __stop___fixup = .;
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
+       . = 0x10000 + SIZEOF_HEADERS;
+       .text 0xf0004000 :
+       {
+               _text = .;
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+               *(.gnu.warning)
+       } = 0
+       _etext = .;
+       PROVIDE (etext = .);
+       RODATA
+       .data : {
+               DATA_DATA
+               CONSTRUCTORS
+       }
+       .data1 : {
+               *(.data1)
+       }
+       _edata = .;
+       PROVIDE (edata = .);
 
-  NOTES
+       .fixup : {
+               __start___fixup = .;
+               *(.fixup)
+               __stop___fixup = .;
+       }
+       __ex_table : {
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+       }
 
-  . = ALIGN(4096);
-  __init_begin = .;
-  _sinittext = .;
-  .init.text : { 
-       *(.init.text)
-  }
-  _einittext = .;
-  __init_text_end = .;
-  .init.data : { *(.init.data) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .init.setup : { *(.init.setup) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-       INITCALLS
-  }
-  __initcall_end = .;
-  __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
-  __con_initcall_end = .;
-  SECURITY_INIT
+       NOTES
+
+       . = ALIGN(PAGE_SIZE);
+       __init_begin = .;
+       .init.text : {
+               _sinittext = .;
+               *(.init.text)
+               _einittext = .;
+       }
+       __init_text_end = .;
+       .init.data : {
+               *(.init.data)
+       }
+       . = ALIGN(16);
+       .init.setup : {
+               __setup_start = .;
+               *(.init.setup)
+               __setup_end = .;
+       }
+       .initcall.init : {
+               __initcall_start = .;
+               INITCALLS
+       __initcall_end = .;
+       }
+       .con_initcall.init : {
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+       }
+       SECURITY_INIT
 
 #ifdef CONFIG_BLK_DEV_INITRD
-  . = ALIGN(4096);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.ramfs) }
-  __initramfs_end = .;
+       . = ALIGN(PAGE_SIZE);
+       .init.ramfs : {
+       __initramfs_start = .;
+               *(.init.ramfs)
+       __initramfs_end = .;
+       }
 #endif
 
-  PERCPU(4096)
-  . = ALIGN(4096);
-  __init_end = .;
-  . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  __bss_start = .;
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       :
-  {
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
-  _end = . ;
-  PROVIDE (end = .);
-  /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) }
+       PERCPU(PAGE_SIZE)
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+       . = ALIGN(32);
+       .data.cacheline_aligned : {
+               *(.data.cacheline_aligned)
+       }
 
-  STABS_DEBUG
+       __bss_start = .;
+       .sbss : {
+               *(.sbss)
+               *(.scommon) }
+       .bss : {
+               *(.dynbss)
+               *(.bss)
+               *(COMMON)
+       }
+       _end = . ;
+       PROVIDE (end = .);
+       /DISCARD/ : {
+               *(.exit.text)
+               *(.exit.data)
+               *(.exitcall.exit)
+       }
 
-  DWARF_DEBUG
+       STABS_DEBUG
+       DWARF_DEBUG
 }
index 7d07297db8782d3286d33ec85a7bd34961d0a1ec..1aa2c4048e4bd19700260aa6167e21440a7b2916 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc6
-# Sun Sep 16 09:52:11 2007
+# Linux kernel version: 2.6.23
+# Sat Oct 13 21:53:54 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -69,7 +69,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -89,6 +88,7 @@ CONFIG_KMOD=y
 CONFIG_BLOCK=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_BLK_DEV_BSG=y
+CONFIG_BLOCK_COMPAT=y
 
 #
 # IO Schedulers
@@ -111,6 +111,7 @@ CONFIG_GENERIC_HARDIRQS=y
 CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 # CONFIG_SMP is not set
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_TABLE=m
@@ -119,6 +120,8 @@ CONFIG_CPU_FREQ_STAT=m
 CONFIG_CPU_FREQ_STAT_DETAILS=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
 CONFIG_CPU_FREQ_GOV_USERSPACE=m
@@ -213,6 +216,7 @@ CONFIG_INET_TUNNEL=y
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -304,6 +308,7 @@ CONFIG_NET_TCPPROBE=m
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_FW_LOADER=y
@@ -355,6 +360,11 @@ CONFIG_IDE_PROC_FS=y
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_IDEPCI_PCIBUS_ORDER=y
@@ -391,7 +401,6 @@ CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_BLK_DEV_TC86C001 is not set
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -505,6 +514,8 @@ CONFIG_DUMMY=m
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
@@ -518,13 +529,16 @@ CONFIG_CASSINI=m
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
@@ -543,6 +557,7 @@ CONFIG_NETDEV_1000=y
 CONFIG_E1000=m
 CONFIG_E1000_NAPI=y
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000E is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
@@ -560,11 +575,14 @@ CONFIG_BNX2=m
 CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
 # CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
@@ -819,6 +837,12 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
 #
 # Multifunction device drivers
 #
@@ -1399,6 +1423,7 @@ CONFIG_ASYNC_MEMCPY=m
 CONFIG_ASYNC_XOR=m
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
 CONFIG_CRYPTO_BLKCIPHER=y
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_MANAGER=y
@@ -1417,6 +1442,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_XTS=m
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_FCRYPT=m
@@ -1431,11 +1457,13 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_HW=y
 
 #
index 40d2f3aae91eb48b3443731a6987f78516279786..112c46e6657834d4fd159ea9f3683614ce57238d 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-$(CONFIG_PCI)       += ebus.o isa.o pci_common.o \
                            pci_psycho.o pci_sabre.o pci_schizo.o \
                            pci_sun4v.o pci_sun4v_asm.o pci_fire.o
+obj-$(CONFIG_PCI_MSI)  += pci_msi.o
 obj-$(CONFIG_SMP)       += smp.o trampoline.o hvtramp.o
 obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
 obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
index 7b379761e9f85fdf398444acc871ff70032aad0c..c55f0293eacdd8f6b2cbf096044886cfe1eed130 100644 (file)
@@ -148,9 +148,11 @@ static int __devinit auxio_probe(struct of_device *dev, const struct of_device_i
 }
 
 static struct of_platform_driver auxio_driver = {
-       .name           = "auxio",
        .match_table    = auxio_match,
        .probe          = auxio_probe,
+       .driver         = {
+               .name   = "auxio",
+       },
 };
 
 static int __init auxio_init(void)
index 8059531bf0ac0ff55d604ef77a06aeddd40e090f..c9b0d7af64ae217897c9fff0d5c94576619f7a69 100644 (file)
@@ -429,16 +429,16 @@ do_ivec:
        stxa            %g0, [%g0] ASI_INTR_RECEIVE
        membar          #Sync
 
-       sethi           %hi(ivector_table), %g2
-       sllx            %g3, 3, %g3
-       or              %g2, %lo(ivector_table), %g2
+       sethi           %hi(ivector_table_pa), %g2
+       ldx             [%g2 + %lo(ivector_table_pa)], %g2
+       sllx            %g3, 4, %g3
        add             %g2, %g3, %g3
 
-       TRAP_LOAD_IRQ_WORK(%g6, %g1)
+       TRAP_LOAD_IRQ_WORK_PA(%g6, %g1)
 
-       lduw            [%g6], %g5              /* g5 = irq_work(cpu) */
-       stw             %g5, [%g3 + 0x00]       /* bucket->irq_chain = g5 */
-       stw             %g3, [%g6]              /* irq_work(cpu) = bucket */
+       ldx             [%g6], %g5
+       stxa            %g5, [%g3] ASI_PHYS_USE_EC
+       stx             %g3, [%g6]
        wr              %g0, 1 << PIL_DEVICE_IRQ, %set_softint
        retry
 do_ivec_xcall:
index 23956096b3bf2f4044628eea93332251afe12adf..f3922e5a89f6c52330b5d6b1cf9ed23353bafba5 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/seq_file.h>
 #include <linux/bootmem.h>
 #include <linux/irq.h>
-#include <linux/msi.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -43,6 +42,7 @@
 #include <asm/auxio.h>
 #include <asm/head.h>
 #include <asm/hypervisor.h>
+#include <asm/cacheflush.h>
 
 /* UPA nodes send interrupt packet to UltraSparc with first data reg
  * value low 5 (7 on Starfire) bits holding the IRQ identifier being
  * To make processing these packets efficient and race free we use
  * an array of irq buckets below.  The interrupt vector handler in
  * entry.S feeds incoming packets into per-cpu pil-indexed lists.
- * The IVEC handler does not need to act atomically, the PIL dispatch
- * code uses CAS to get an atomic snapshot of the list and clear it
- * at the same time.
  *
  * If you make changes to ino_bucket, please update hand coded assembler
  * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S
  */
 struct ino_bucket {
-       /* Next handler in per-CPU IRQ worklist.  We know that
-        * bucket pointers have the high 32-bits clear, so to
-        * save space we only store the bits we need.
-        */
-/*0x00*/unsigned int irq_chain;
+/*0x00*/unsigned long __irq_chain_pa;
 
        /* Virtual interrupt number assigned to this INO.  */
-/*0x04*/unsigned int virt_irq;
+/*0x08*/unsigned int __virt_irq;
+/*0x0c*/unsigned int __pad;
 };
 
 #define NUM_IVECS      (IMAP_INR + 1)
-struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
-
-#define __irq_ino(irq) \
-        (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0])
-#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
-#define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
-
-/* This has to be in the main kernel image, it cannot be
- * turned into per-cpu data.  The reason is that the main
- * kernel image is locked into the TLB and this structure
- * is accessed from the vectored interrupt trap handler.  If
- * access to this structure takes a TLB miss it could cause
- * the 5-level sparc v9 trap stack to overflow.
+struct ino_bucket *ivector_table;
+unsigned long ivector_table_pa;
+
+/* On several sun4u processors, it is illegal to mix bypass and
+ * non-bypass accesses.  Therefore we access all INO buckets
+ * using bypass accesses only.
  */
-#define irq_work(__cpu)        &(trap_block[(__cpu)].irq_worklist)
+static unsigned long bucket_get_chain_pa(unsigned long bucket_pa)
+{
+       unsigned long ret;
+
+       __asm__ __volatile__("ldxa      [%1] %2, %0"
+                            : "=&r" (ret)
+                            : "r" (bucket_pa +
+                                   offsetof(struct ino_bucket,
+                                            __irq_chain_pa)),
+                              "i" (ASI_PHYS_USE_EC));
+
+       return ret;
+}
+
+static void bucket_clear_chain_pa(unsigned long bucket_pa)
+{
+       __asm__ __volatile__("stxa      %%g0, [%0] %1"
+                            : /* no outputs */
+                            : "r" (bucket_pa +
+                                   offsetof(struct ino_bucket,
+                                            __irq_chain_pa)),
+                              "i" (ASI_PHYS_USE_EC));
+}
+
+static unsigned int bucket_get_virt_irq(unsigned long bucket_pa)
+{
+       unsigned int ret;
+
+       __asm__ __volatile__("lduwa     [%1] %2, %0"
+                            : "=&r" (ret)
+                            : "r" (bucket_pa +
+                                   offsetof(struct ino_bucket,
+                                            __virt_irq)),
+                              "i" (ASI_PHYS_USE_EC));
+
+       return ret;
+}
+
+static void bucket_set_virt_irq(unsigned long bucket_pa,
+                               unsigned int virt_irq)
+{
+       __asm__ __volatile__("stwa      %0, [%1] %2"
+                            : /* no outputs */
+                            : "r" (virt_irq),
+                              "r" (bucket_pa +
+                                   offsetof(struct ino_bucket,
+                                            __virt_irq)),
+                              "i" (ASI_PHYS_USE_EC));
+}
+
+#define irq_work_pa(__cpu)     &(trap_block[(__cpu)].irq_worklist_pa)
 
 static struct {
-       unsigned int irq;
        unsigned int dev_handle;
        unsigned int dev_ino;
-} virt_to_real_irq_table[NR_IRQS];
+       unsigned int in_use;
+} virt_irq_table[NR_IRQS];
+static DEFINE_SPINLOCK(virt_irq_alloc_lock);
 
-static unsigned char virt_irq_alloc(unsigned int real_irq)
+unsigned char virt_irq_alloc(unsigned int dev_handle,
+                            unsigned int dev_ino)
 {
+       unsigned long flags;
        unsigned char ent;
 
        BUILD_BUG_ON(NR_IRQS >= 256);
 
+       spin_lock_irqsave(&virt_irq_alloc_lock, flags);
+
        for (ent = 1; ent < NR_IRQS; ent++) {
-               if (!virt_to_real_irq_table[ent].irq)
+               if (!virt_irq_table[ent].in_use)
                        break;
        }
        if (ent >= NR_IRQS) {
                printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
-               return 0;
+               ent = 0;
+       } else {
+               virt_irq_table[ent].dev_handle = dev_handle;
+               virt_irq_table[ent].dev_ino = dev_ino;
+               virt_irq_table[ent].in_use = 1;
        }
 
-       virt_to_real_irq_table[ent].irq = real_irq;
+       spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
 
        return ent;
 }
 
 #ifdef CONFIG_PCI_MSI
-static void virt_irq_free(unsigned int virt_irq)
+void virt_irq_free(unsigned int virt_irq)
 {
-       unsigned int real_irq;
+       unsigned long flags;
 
        if (virt_irq >= NR_IRQS)
                return;
 
-       real_irq = virt_to_real_irq_table[virt_irq].irq;
-       virt_to_real_irq_table[virt_irq].irq = 0;
+       spin_lock_irqsave(&virt_irq_alloc_lock, flags);
 
-       __bucket(real_irq)->virt_irq = 0;
-}
-#endif
+       virt_irq_table[virt_irq].in_use = 0;
 
-static unsigned int virt_to_real_irq(unsigned char virt_irq)
-{
-       return virt_to_real_irq_table[virt_irq].irq;
+       spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
 }
+#endif
 
 /*
  * /proc/interrupts printing:
@@ -217,38 +259,8 @@ struct irq_handler_data {
        void            (*pre_handler)(unsigned int, void *, void *);
        void            *pre_handler_arg1;
        void            *pre_handler_arg2;
-
-       u32             msi;
 };
 
-void sparc64_set_msi(unsigned int virt_irq, u32 msi)
-{
-       struct irq_handler_data *data = get_irq_chip_data(virt_irq);
-
-       if (data)
-               data->msi = msi;
-}
-
-u32 sparc64_get_msi(unsigned int virt_irq)
-{
-       struct irq_handler_data *data = get_irq_chip_data(virt_irq);
-
-       if (data)
-               return data->msi;
-       return 0xffffffff;
-}
-
-static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq)
-{
-       unsigned int real_irq = virt_to_real_irq(virt_irq);
-       struct ino_bucket *bucket = NULL;
-
-       if (likely(real_irq))
-               bucket = __bucket(real_irq);
-
-       return bucket;
-}
-
 #ifdef CONFIG_SMP
 static int irq_choose_cpu(unsigned int virt_irq)
 {
@@ -348,201 +360,152 @@ static void sun4u_irq_end(unsigned int virt_irq)
 
 static void sun4v_irq_enable(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
-
-       if (likely(bucket)) {
-               unsigned long cpuid;
-               int err;
+       unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+       unsigned long cpuid = irq_choose_cpu(virt_irq);
+       int err;
 
-               cpuid = irq_choose_cpu(virt_irq);
-
-               err = sun4v_intr_settarget(ino, cpuid);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
-                              "err(%d)\n", ino, cpuid, err);
-               err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_intr_setstate(%x): "
-                              "err(%d)\n", ino, err);
-               err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
-                              ino, err);
-       }
+       err = sun4v_intr_settarget(ino, cpuid);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+                      "err(%d)\n", ino, cpuid, err);
+       err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_intr_setstate(%x): "
+                      "err(%d)\n", ino, err);
+       err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
+                      ino, err);
 }
 
 static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
+       unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+       unsigned long cpuid = irq_choose_cpu(virt_irq);
+       int err;
 
-       if (likely(bucket)) {
-               unsigned long cpuid;
-               int err;
-
-               cpuid = irq_choose_cpu(virt_irq);
-
-               err = sun4v_intr_settarget(ino, cpuid);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
-                              "err(%d)\n", ino, cpuid, err);
-       }
+       err = sun4v_intr_settarget(ino, cpuid);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+                      "err(%d)\n", ino, cpuid, err);
 }
 
 static void sun4v_irq_disable(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
-
-       if (likely(bucket)) {
-               int err;
-
-               err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_intr_setenabled(%x): "
-                              "err(%d)\n", ino, err);
-       }
-}
-
-#ifdef CONFIG_PCI_MSI
-static void sun4v_msi_enable(unsigned int virt_irq)
-{
-       sun4v_irq_enable(virt_irq);
-       unmask_msi_irq(virt_irq);
-}
+       unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+       int err;
 
-static void sun4v_msi_disable(unsigned int virt_irq)
-{
-       mask_msi_irq(virt_irq);
-       sun4v_irq_disable(virt_irq);
+       err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_intr_setenabled(%x): "
+                      "err(%d)\n", ino, err);
 }
-#endif
 
 static void sun4v_irq_end(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
+       unsigned int ino = virt_irq_table[virt_irq].dev_ino;
        struct irq_desc *desc = irq_desc + virt_irq;
+       int err;
 
        if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
                return;
 
-       if (likely(bucket)) {
-               int err;
-
-               err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_intr_setstate(%x): "
-                              "err(%d)\n", ino, err);
-       }
+       err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_intr_setstate(%x): "
+                      "err(%d)\n", ino, err);
 }
 
 static void sun4v_virq_enable(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-
-       if (likely(bucket)) {
-               unsigned long cpuid, dev_handle, dev_ino;
-               int err;
-
-               cpuid = irq_choose_cpu(virt_irq);
-
-               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
-               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
-               err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
-                              "err(%d)\n",
-                              dev_handle, dev_ino, cpuid, err);
-               err = sun4v_vintr_set_state(dev_handle, dev_ino,
-                                           HV_INTR_STATE_IDLE);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
-                               "HV_INTR_STATE_IDLE): err(%d)\n",
-                              dev_handle, dev_ino, err);
-               err = sun4v_vintr_set_valid(dev_handle, dev_ino,
-                                           HV_INTR_ENABLED);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
-                              "HV_INTR_ENABLED): err(%d)\n",
-                              dev_handle, dev_ino, err);
-       }
+       unsigned long cpuid, dev_handle, dev_ino;
+       int err;
+
+       cpuid = irq_choose_cpu(virt_irq);
+
+       dev_handle = virt_irq_table[virt_irq].dev_handle;
+       dev_ino = virt_irq_table[virt_irq].dev_ino;
+
+       err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
+                      "err(%d)\n",
+                      dev_handle, dev_ino, cpuid, err);
+       err = sun4v_vintr_set_state(dev_handle, dev_ino,
+                                   HV_INTR_STATE_IDLE);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+                      "HV_INTR_STATE_IDLE): err(%d)\n",
+                      dev_handle, dev_ino, err);
+       err = sun4v_vintr_set_valid(dev_handle, dev_ino,
+                                   HV_INTR_ENABLED);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+                      "HV_INTR_ENABLED): err(%d)\n",
+                      dev_handle, dev_ino, err);
 }
 
 static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+       unsigned long cpuid, dev_handle, dev_ino;
+       int err;
 
-       if (likely(bucket)) {
-               unsigned long cpuid, dev_handle, dev_ino;
-               int err;
+       cpuid = irq_choose_cpu(virt_irq);
 
-               cpuid = irq_choose_cpu(virt_irq);
+       dev_handle = virt_irq_table[virt_irq].dev_handle;
+       dev_ino = virt_irq_table[virt_irq].dev_ino;
 
-               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
-               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
-               err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
-                              "err(%d)\n",
-                              dev_handle, dev_ino, cpuid, err);
-       }
+       err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
+                      "err(%d)\n",
+                      dev_handle, dev_ino, cpuid, err);
 }
 
 static void sun4v_virq_disable(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+       unsigned long dev_handle, dev_ino;
+       int err;
 
-       if (likely(bucket)) {
-               unsigned long dev_handle, dev_ino;
-               int err;
+       dev_handle = virt_irq_table[virt_irq].dev_handle;
+       dev_ino = virt_irq_table[virt_irq].dev_ino;
 
-               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
-               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
-               err = sun4v_vintr_set_valid(dev_handle, dev_ino,
-                                           HV_INTR_DISABLED);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
-                              "HV_INTR_DISABLED): err(%d)\n",
-                              dev_handle, dev_ino, err);
-       }
+       err = sun4v_vintr_set_valid(dev_handle, dev_ino,
+                                   HV_INTR_DISABLED);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+                      "HV_INTR_DISABLED): err(%d)\n",
+                      dev_handle, dev_ino, err);
 }
 
 static void sun4v_virq_end(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
        struct irq_desc *desc = irq_desc + virt_irq;
+       unsigned long dev_handle, dev_ino;
+       int err;
 
        if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
                return;
 
-       if (likely(bucket)) {
-               unsigned long dev_handle, dev_ino;
-               int err;
+       dev_handle = virt_irq_table[virt_irq].dev_handle;
+       dev_ino = virt_irq_table[virt_irq].dev_ino;
 
-               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
-               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
-
-               err = sun4v_vintr_set_state(dev_handle, dev_ino,
-                                           HV_INTR_STATE_IDLE);
-               if (err != HV_EOK)
-                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
-                               "HV_INTR_STATE_IDLE): err(%d)\n",
-                              dev_handle, dev_ino, err);
-       }
+       err = sun4v_vintr_set_state(dev_handle, dev_ino,
+                                   HV_INTR_STATE_IDLE);
+       if (err != HV_EOK)
+               printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+                      "HV_INTR_STATE_IDLE): err(%d)\n",
+                      dev_handle, dev_ino, err);
 }
 
 static void run_pre_handler(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
        struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+       unsigned int ino;
 
+       ino = virt_irq_table[virt_irq].dev_ino;
        if (likely(data->pre_handler)) {
-               data->pre_handler(__irq_ino(__irq(bucket)),
+               data->pre_handler(ino,
                                  data->pre_handler_arg1,
                                  data->pre_handler_arg2);
        }
@@ -573,28 +536,6 @@ static struct irq_chip sun4v_irq = {
        .set_affinity   = sun4v_set_affinity,
 };
 
-static struct irq_chip sun4v_irq_ack = {
-       .typename       = "sun4v+ack",
-       .enable         = sun4v_irq_enable,
-       .disable        = sun4v_irq_disable,
-       .ack            = run_pre_handler,
-       .end            = sun4v_irq_end,
-       .set_affinity   = sun4v_set_affinity,
-};
-
-#ifdef CONFIG_PCI_MSI
-static struct irq_chip sun4v_msi = {
-       .typename       = "sun4v+msi",
-       .mask           = mask_msi_irq,
-       .unmask         = unmask_msi_irq,
-       .enable         = sun4v_msi_enable,
-       .disable        = sun4v_msi_disable,
-       .ack            = run_pre_handler,
-       .end            = sun4v_irq_end,
-       .set_affinity   = sun4v_set_affinity,
-};
-#endif
-
 static struct irq_chip sun4v_virq = {
        .typename       = "vsun4v",
        .enable         = sun4v_virq_enable,
@@ -603,59 +544,48 @@ static struct irq_chip sun4v_virq = {
        .set_affinity   = sun4v_virt_set_affinity,
 };
 
-static struct irq_chip sun4v_virq_ack = {
-       .typename       = "vsun4v+ack",
-       .enable         = sun4v_virq_enable,
-       .disable        = sun4v_virq_disable,
-       .ack            = run_pre_handler,
-       .end            = sun4v_virq_end,
-       .set_affinity   = sun4v_virt_set_affinity,
-};
-
 void irq_install_pre_handler(int virt_irq,
                             void (*func)(unsigned int, void *, void *),
                             void *arg1, void *arg2)
 {
        struct irq_handler_data *data = get_irq_chip_data(virt_irq);
-       struct irq_chip *chip;
+       struct irq_chip *chip = get_irq_chip(virt_irq);
+
+       if (WARN_ON(chip == &sun4v_irq || chip == &sun4v_virq)) {
+               printk(KERN_ERR "IRQ: Trying to install pre-handler on "
+                      "sun4v irq %u\n", virt_irq);
+               return;
+       }
 
        data->pre_handler = func;
        data->pre_handler_arg1 = arg1;
        data->pre_handler_arg2 = arg2;
 
-       chip = get_irq_chip(virt_irq);
-       if (chip == &sun4u_irq_ack ||
-           chip == &sun4v_irq_ack ||
-           chip == &sun4v_virq_ack
-#ifdef CONFIG_PCI_MSI
-           || chip == &sun4v_msi
-#endif
-           )
+       if (chip == &sun4u_irq_ack)
                return;
 
-       chip = (chip == &sun4u_irq ?
-               &sun4u_irq_ack :
-               (chip == &sun4v_irq ?
-                &sun4v_irq_ack : &sun4v_virq_ack));
-       set_irq_chip(virt_irq, chip);
+       set_irq_chip(virt_irq, &sun4u_irq_ack);
 }
 
 unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
 {
        struct ino_bucket *bucket;
        struct irq_handler_data *data;
+       unsigned int virt_irq;
        int ino;
 
        BUG_ON(tlb_type == hypervisor);
 
        ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
        bucket = &ivector_table[ino];
-       if (!bucket->virt_irq) {
-               bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-               set_irq_chip(bucket->virt_irq, &sun4u_irq);
+       virt_irq = bucket_get_virt_irq(__pa(bucket));
+       if (!virt_irq) {
+               virt_irq = virt_irq_alloc(0, ino);
+               bucket_set_virt_irq(__pa(bucket), virt_irq);
+               set_irq_chip(virt_irq, &sun4u_irq);
        }
 
-       data = get_irq_chip_data(bucket->virt_irq);
+       data = get_irq_chip_data(virt_irq);
        if (unlikely(data))
                goto out;
 
@@ -664,13 +594,13 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
                prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
                prom_halt();
        }
-       set_irq_chip_data(bucket->virt_irq, data);
+       set_irq_chip_data(virt_irq, data);
 
        data->imap  = imap;
        data->iclr  = iclr;
 
 out:
-       return bucket->virt_irq;
+       return virt_irq;
 }
 
 static unsigned int sun4v_build_common(unsigned long sysino,
@@ -678,16 +608,19 @@ static unsigned int sun4v_build_common(unsigned long sysino,
 {
        struct ino_bucket *bucket;
        struct irq_handler_data *data;
+       unsigned int virt_irq;
 
        BUG_ON(tlb_type != hypervisor);
 
        bucket = &ivector_table[sysino];
-       if (!bucket->virt_irq) {
-               bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-               set_irq_chip(bucket->virt_irq, chip);
+       virt_irq = bucket_get_virt_irq(__pa(bucket));
+       if (!virt_irq) {
+               virt_irq = virt_irq_alloc(0, sysino);
+               bucket_set_virt_irq(__pa(bucket), virt_irq);
+               set_irq_chip(virt_irq, chip);
        }
 
-       data = get_irq_chip_data(bucket->virt_irq);
+       data = get_irq_chip_data(virt_irq);
        if (unlikely(data))
                goto out;
 
@@ -696,7 +629,7 @@ static unsigned int sun4v_build_common(unsigned long sysino,
                prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
                prom_halt();
        }
-       set_irq_chip_data(bucket->virt_irq, data);
+       set_irq_chip_data(virt_irq, data);
 
        /* Catch accidental accesses to these things.  IMAP/ICLR handling
         * is done by hypervisor calls on sun4v platforms, not by direct
@@ -706,7 +639,7 @@ static unsigned int sun4v_build_common(unsigned long sysino,
        data->iclr = ~0UL;
 
 out:
-       return bucket->virt_irq;
+       return virt_irq;
 }
 
 unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
@@ -718,86 +651,52 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
 
 unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
 {
-       unsigned long sysino, hv_err;
-       unsigned int virq;
-
-       BUG_ON(devhandle & devino);
-
-       sysino = devhandle | devino;
-       BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
-
-       hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
-       if (hv_err) {
-               prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
-                           "err=%lu\n", devhandle, devino, hv_err);
-               prom_halt();
-       }
-
-       virq = sun4v_build_common(sysino, &sun4v_virq);
-
-       virt_to_real_irq_table[virq].dev_handle = devhandle;
-       virt_to_real_irq_table[virq].dev_ino = devino;
-
-       return virq;
-}
-
-#ifdef CONFIG_PCI_MSI
-unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
-                            unsigned int msi_start, unsigned int msi_end)
-{
-       struct ino_bucket *bucket;
        struct irq_handler_data *data;
-       unsigned long sysino;
-       unsigned int devino;
-
-       BUG_ON(tlb_type != hypervisor);
-
-       /* Find a free devino in the given range.  */
-       for (devino = msi_start; devino < msi_end; devino++) {
-               sysino = sun4v_devino_to_sysino(devhandle, devino);
-               bucket = &ivector_table[sysino];
-               if (!bucket->virt_irq)
-                       break;
-       }
-       if (devino >= msi_end)
-               return -ENOSPC;
+       struct ino_bucket *bucket;
+       unsigned long hv_err, cookie;
+       unsigned int virt_irq;
 
-       sysino = sun4v_devino_to_sysino(devhandle, devino);
-       bucket = &ivector_table[sysino];
-       bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-       *virt_irq_p = bucket->virt_irq;
-       set_irq_chip(bucket->virt_irq, &sun4v_msi);
+       bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
+       if (unlikely(!bucket))
+               return 0;
+       __flush_dcache_range((unsigned long) bucket,
+                            ((unsigned long) bucket +
+                             sizeof(struct ino_bucket)));
 
-       data = get_irq_chip_data(bucket->virt_irq);
-       if (unlikely(data))
-               return devino;
+       virt_irq = virt_irq_alloc(devhandle, devino);
+       bucket_set_virt_irq(__pa(bucket), virt_irq);
+       set_irq_chip(virt_irq, &sun4v_virq);
 
        data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
-       if (unlikely(!data)) {
-               virt_irq_free(*virt_irq_p);
-               return -ENOMEM;
-       }
-       set_irq_chip_data(bucket->virt_irq, data);
+       if (unlikely(!data))
+               return 0;
+
+       set_irq_chip_data(virt_irq, data);
 
+       /* Catch accidental accesses to these things.  IMAP/ICLR handling
+        * is done by hypervisor calls on sun4v platforms, not by direct
+        * register accesses.
+        */
        data->imap = ~0UL;
        data->iclr = ~0UL;
 
-       return devino;
-}
+       cookie = ~__pa(bucket);
+       hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie);
+       if (hv_err) {
+               prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
+                           "err=%lu\n", devhandle, devino, hv_err);
+               prom_halt();
+       }
 
-void sun4v_destroy_msi(unsigned int virt_irq)
-{
-       virt_irq_free(virt_irq);
+       return virt_irq;
 }
-#endif
 
 void ack_bad_irq(unsigned int virt_irq)
 {
-       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = 0xdeadbeef;
+       unsigned int ino = virt_irq_table[virt_irq].dev_ino;
 
-       if (bucket)
-               ino = bucket - &ivector_table[0];
+       if (!ino)
+               ino = 0xdeadbeef;
 
        printk(KERN_CRIT "Unexpected IRQ from ino[%x] virt_irq[%u]\n",
               ino, virt_irq);
@@ -805,7 +704,7 @@ void ack_bad_irq(unsigned int virt_irq)
 
 void handler_irq(int irq, struct pt_regs *regs)
 {
-       struct ino_bucket *bucket;
+       unsigned long pstate, bucket_pa;
        struct pt_regs *old_regs;
 
        clear_softint(1 << irq);
@@ -813,15 +712,28 @@ void handler_irq(int irq, struct pt_regs *regs)
        old_regs = set_irq_regs(regs);
        irq_enter();
 
-       /* Sliiiick... */
-       bucket = __bucket(xchg32(irq_work(smp_processor_id()), 0));
-       while (bucket) {
-               struct ino_bucket *next = __bucket(bucket->irq_chain);
+       /* Grab an atomic snapshot of the pending IVECs.  */
+       __asm__ __volatile__("rdpr      %%pstate, %0\n\t"
+                            "wrpr      %0, %3, %%pstate\n\t"
+                            "ldx       [%2], %1\n\t"
+                            "stx       %%g0, [%2]\n\t"
+                            "wrpr      %0, 0x0, %%pstate\n\t"
+                            : "=&r" (pstate), "=&r" (bucket_pa)
+                            : "r" (irq_work_pa(smp_processor_id())),
+                              "i" (PSTATE_IE)
+                            : "memory");
+
+       while (bucket_pa) {
+               unsigned long next_pa;
+               unsigned int virt_irq;
 
-               bucket->irq_chain = 0;
-               __do_IRQ(bucket->virt_irq);
+               next_pa = bucket_get_chain_pa(bucket_pa);
+               virt_irq = bucket_get_virt_irq(bucket_pa);
+               bucket_clear_chain_pa(bucket_pa);
 
-               bucket = next;
+               __do_IRQ(virt_irq);
+
+               bucket_pa = next_pa;
        }
 
        irq_exit();
@@ -921,7 +833,7 @@ void init_irqwork_curcpu(void)
 {
        int cpu = hard_smp_processor_id();
 
-       trap_block[cpu].irq_worklist = 0;
+       trap_block[cpu].irq_worklist_pa = 0UL;
 }
 
 /* Please be very careful with register_one_mondo() and
@@ -1035,9 +947,21 @@ static struct irqaction timer_irq_action = {
 /* Only invoked on boot processor. */
 void __init init_IRQ(void)
 {
+       unsigned long size;
+
        map_prom_timers();
        kill_prom_timer();
-       memset(&ivector_table[0], 0, sizeof(ivector_table));
+
+       size = sizeof(struct ino_bucket) * NUM_IVECS;
+       ivector_table = alloc_bootmem_low(size);
+       if (!ivector_table) {
+               prom_printf("Fatal error, cannot allocate ivector_table\n");
+               prom_halt();
+       }
+       __flush_dcache_range((unsigned long) ivector_table,
+                            ((unsigned long) ivector_table) + size);
+
+       ivector_table_pa = __pa(ivector_table);
 
        if (tlb_type == hypervisor)
                sun4v_init_mondo_queues();
index 4cc77485f53602ba54714e88b42d61e1bb062047..42d779866fba394135bf7063d5b6a04e29fe1c7b 100644 (file)
@@ -872,7 +872,10 @@ __setup("of_debug=", of_debug);
 int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
 {
        /* initialize common driver fields */
-       drv->driver.name = drv->name;
+       if (!drv->driver.name)
+               drv->driver.name = drv->name;
+       if (!drv->driver.owner)
+               drv->driver.owner = drv->owner;
        drv->driver.bus = bus;
 
        /* register with core */
index e8dac81d8a0d01e9be9ffb2914c37d7570a36d6a..9b808640a193d5c941cbb2dd16e4ec5bbffb465a 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "pci_impl.h"
 
-unsigned long pci_memspace_mask = 0xffffffffUL;
-
 #ifndef CONFIG_PCI
 /* A "nop" PCI implementation. */
 asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
@@ -1066,8 +1064,8 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
        return 0;
 }
 
-/* Adjust vm_pgoff of VMA such that it is the physical page offset corresponding
- * to the 32-bit pci bus offset for DEV requested by the user.
+/* Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
  *
  * Basically, the user finds the base address for his device which he wishes
  * to mmap.  They read the 32-bit value from the config space base register,
@@ -1076,21 +1074,35 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
  *
  * Returns negative error code on failure, zero on success.
  */
-static int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+static int __pci_mmap_make_offset(struct pci_dev *pdev,
+                                 struct vm_area_struct *vma,
                                  enum pci_mmap_state mmap_state)
 {
-       unsigned long user_offset = vma->vm_pgoff << PAGE_SHIFT;
-       unsigned long user32 = user_offset & pci_memspace_mask;
-       unsigned long largest_base, this_base, addr32;
-       int i;
+       unsigned long user_paddr, user_size;
+       int i, err;
 
-       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-               return __pci_mmap_make_offset_bus(dev, vma, mmap_state);
+       /* First compute the physical address in vma->vm_pgoff,
+        * making sure the user offset is within range in the
+        * appropriate PCI space.
+        */
+       err = __pci_mmap_make_offset_bus(pdev, vma, mmap_state);
+       if (err)
+               return err;
+
+       /* If this is a mapping on a host bridge, any address
+        * is OK.
+        */
+       if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+               return err;
+
+       /* Otherwise make sure it's in the range for one of the
+        * device's resources.
+        */
+       user_paddr = vma->vm_pgoff << PAGE_SHIFT;
+       user_size = vma->vm_end - vma->vm_start;
 
-       /* Figure out which base address this is for. */
-       largest_base = 0UL;
        for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-               struct resource *rp = &dev->resource[i];
+               struct resource *rp = &pdev->resource[i];
 
                /* Active? */
                if (!rp->flags)
@@ -1108,26 +1120,14 @@ static int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vm
                                continue;
                }
 
-               this_base = rp->start;
-
-               addr32 = (this_base & PAGE_MASK) & pci_memspace_mask;
-
-               if (mmap_state == pci_mmap_io)
-                       addr32 &= 0xffffff;
-
-               if (addr32 <= user32 && this_base > largest_base)
-                       largest_base = this_base;
+               if ((rp->start <= user_paddr) &&
+                   (user_paddr + user_size) <= (rp->end + 1UL))
+                       break;
        }
 
-       if (largest_base == 0UL)
+       if (i > PCI_ROM_RESOURCE)
                return -EINVAL;
 
-       /* Now construct the final physical address. */
-       if (mmap_state == pci_mmap_io)
-               vma->vm_pgoff = (((largest_base & ~0xffffffUL) | user32) >> PAGE_SHIFT);
-       else
-               vma->vm_pgoff = (((largest_base & ~(pci_memspace_mask)) | user32) >> PAGE_SHIFT);
-
        return 0;
 }
 
index 14d67fe21ab2c1a4aa8343a97352e0ab7573f0c7..fef3b37487bf4fc92f850afc2053afbd22c6cad2 100644 (file)
@@ -6,9 +6,12 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/msi.h>
+#include <linux/irq.h>
 
 #include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/irq.h>
 
 #include "pci_impl.h"
 
@@ -84,6 +87,266 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
        return 0;
 }
 
+#ifdef CONFIG_PCI_MSI
+struct pci_msiq_entry {
+       u64             word0;
+#define MSIQ_WORD0_RESV                        0x8000000000000000UL
+#define MSIQ_WORD0_FMT_TYPE            0x7f00000000000000UL
+#define MSIQ_WORD0_FMT_TYPE_SHIFT      56
+#define MSIQ_WORD0_LEN                 0x00ffc00000000000UL
+#define MSIQ_WORD0_LEN_SHIFT           46
+#define MSIQ_WORD0_ADDR0               0x00003fff00000000UL
+#define MSIQ_WORD0_ADDR0_SHIFT         32
+#define MSIQ_WORD0_RID                 0x00000000ffff0000UL
+#define MSIQ_WORD0_RID_SHIFT           16
+#define MSIQ_WORD0_DATA0               0x000000000000ffffUL
+#define MSIQ_WORD0_DATA0_SHIFT         0
+
+#define MSIQ_TYPE_MSG                  0x6
+#define MSIQ_TYPE_MSI32                        0xb
+#define MSIQ_TYPE_MSI64                        0xf
+
+       u64             word1;
+#define MSIQ_WORD1_ADDR1               0xffffffffffff0000UL
+#define MSIQ_WORD1_ADDR1_SHIFT         16
+#define MSIQ_WORD1_DATA1               0x000000000000ffffUL
+#define MSIQ_WORD1_DATA1_SHIFT         0
+
+       u64             resv[6];
+};
+
+/* All MSI registers are offset from pbm->pbm_regs */
+#define EVENT_QUEUE_BASE_ADDR_REG      0x010000UL
+#define  EVENT_QUEUE_BASE_ADDR_ALL_ONES        0xfffc000000000000UL
+
+#define EVENT_QUEUE_CONTROL_SET(EQ)    (0x011000UL + (EQ) * 0x8UL)
+#define  EVENT_QUEUE_CONTROL_SET_OFLOW 0x0200000000000000UL
+#define  EVENT_QUEUE_CONTROL_SET_EN    0x0000100000000000UL
+
+#define EVENT_QUEUE_CONTROL_CLEAR(EQ)  (0x011200UL + (EQ) * 0x8UL)
+#define  EVENT_QUEUE_CONTROL_CLEAR_OF  0x0200000000000000UL
+#define  EVENT_QUEUE_CONTROL_CLEAR_E2I 0x0000800000000000UL
+#define  EVENT_QUEUE_CONTROL_CLEAR_DIS 0x0000100000000000UL
+
+#define EVENT_QUEUE_STATE(EQ)          (0x011400UL + (EQ) * 0x8UL)
+#define  EVENT_QUEUE_STATE_MASK                0x0000000000000007UL
+#define  EVENT_QUEUE_STATE_IDLE                0x0000000000000001UL
+#define  EVENT_QUEUE_STATE_ACTIVE      0x0000000000000002UL
+#define  EVENT_QUEUE_STATE_ERROR       0x0000000000000004UL
+
+#define EVENT_QUEUE_TAIL(EQ)           (0x011600UL + (EQ) * 0x8UL)
+#define  EVENT_QUEUE_TAIL_OFLOW                0x0200000000000000UL
+#define  EVENT_QUEUE_TAIL_VAL          0x000000000000007fUL
+
+#define EVENT_QUEUE_HEAD(EQ)           (0x011800UL + (EQ) * 0x8UL)
+#define  EVENT_QUEUE_HEAD_VAL          0x000000000000007fUL
+
+#define MSI_MAP(MSI)                   (0x020000UL + (MSI) * 0x8UL)
+#define  MSI_MAP_VALID                 0x8000000000000000UL
+#define  MSI_MAP_EQWR_N                        0x4000000000000000UL
+#define  MSI_MAP_EQNUM                 0x000000000000003fUL
+
+#define MSI_CLEAR(MSI)                 (0x028000UL + (MSI) * 0x8UL)
+#define  MSI_CLEAR_EQWR_N              0x4000000000000000UL
+
+#define IMONDO_DATA0                   0x02C000UL
+#define  IMONDO_DATA0_DATA             0xffffffffffffffc0UL
+
+#define IMONDO_DATA1                   0x02C008UL
+#define  IMONDO_DATA1_DATA             0xffffffffffffffffUL
+
+#define MSI_32BIT_ADDR                 0x034000UL
+#define  MSI_32BIT_ADDR_VAL            0x00000000ffff0000UL
+
+#define MSI_64BIT_ADDR                 0x034008UL
+#define  MSI_64BIT_ADDR_VAL            0xffffffffffff0000UL
+
+static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+                            unsigned long *head)
+{
+       *head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
+       return 0;
+}
+
+static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
+                               unsigned long *head, unsigned long *msi)
+{
+       unsigned long type_fmt, type, msi_num;
+       struct pci_msiq_entry *base, *ep;
+
+       base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) * 8192));
+       ep = &base[*head];
+
+       if ((ep->word0 & MSIQ_WORD0_FMT_TYPE) == 0)
+               return 0;
+
+       type_fmt = ((ep->word0 & MSIQ_WORD0_FMT_TYPE) >>
+                   MSIQ_WORD0_FMT_TYPE_SHIFT);
+       type = (type_fmt >> 3);
+       if (unlikely(type != MSIQ_TYPE_MSI32 &&
+                    type != MSIQ_TYPE_MSI64))
+               return -EINVAL;
+
+       *msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
+                         MSIQ_WORD0_DATA0_SHIFT);
+
+       fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
+                  MSI_CLEAR_EQWR_N);
+
+       /* Clear the entry.  */
+       ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
+
+       /* Go to next entry in ring.  */
+       (*head)++;
+       if (*head >= pbm->msiq_ent_count)
+               *head = 0;
+
+       return 1;
+}
+
+static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+                            unsigned long head)
+{
+       fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
+       return 0;
+}
+
+static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
+                             unsigned long msi, int is_msi64)
+{
+       u64 val;
+
+       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val &= ~(MSI_MAP_EQNUM);
+       val |= msiqid;
+       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+
+       fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
+                  MSI_CLEAR_EQWR_N);
+
+       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val |= MSI_MAP_VALID;
+       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+
+       return 0;
+}
+
+static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
+{
+       unsigned long msiqid;
+       u64 val;
+
+       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       msiqid = (val & MSI_MAP_EQNUM);
+
+       val &= ~MSI_MAP_VALID;
+
+       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+
+       return 0;
+}
+
+static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm)
+{
+       unsigned long pages, order, i;
+
+       order = get_order(512 * 1024);
+       pages = __get_free_pages(GFP_KERNEL | __GFP_COMP, order);
+       if (pages == 0UL) {
+               printk(KERN_ERR "MSI: Cannot allocate MSI queues (o=%lu).\n",
+                      order);
+               return -ENOMEM;
+       }
+       memset((char *)pages, 0, PAGE_SIZE << order);
+       pbm->msi_queues = (void *) pages;
+
+       fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
+                  (EVENT_QUEUE_BASE_ADDR_ALL_ONES |
+                   __pa(pbm->msi_queues)));
+
+       fire_write(pbm->pbm_regs + IMONDO_DATA0,
+                  pbm->portid << 6);
+       fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
+
+       fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
+                  pbm->msi32_start);
+       fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
+                  pbm->msi64_start);
+
+       for (i = 0; i < pbm->msiq_num; i++) {
+               fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
+               fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
+       }
+
+       return 0;
+}
+
+static void pci_fire_msiq_free(struct pci_pbm_info *pbm)
+{
+       unsigned long pages, order;
+
+       order = get_order(512 * 1024);
+       pages = (unsigned long) pbm->msi_queues;
+
+       free_pages(pages, order);
+
+       pbm->msi_queues = NULL;
+}
+
+static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
+                                  unsigned long msiqid,
+                                  unsigned long devino)
+{
+       unsigned long cregs = (unsigned long) pbm->pbm_regs;
+       unsigned long imap_reg, iclr_reg, int_ctrlr;
+       unsigned int virt_irq;
+       int fixup;
+       u64 val;
+
+       imap_reg = cregs + (0x001000UL + (devino * 0x08UL));
+       iclr_reg = cregs + (0x001400UL + (devino * 0x08UL));
+
+       /* XXX iterate amongst the 4 IRQ controllers XXX */
+       int_ctrlr = (1UL << 6);
+
+       val = fire_read(imap_reg);
+       val |= (1UL << 63) | int_ctrlr;
+       fire_write(imap_reg, val);
+
+       fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
+
+       virt_irq = build_irq(fixup, iclr_reg, imap_reg);
+       if (!virt_irq)
+               return -ENOMEM;
+
+       fire_write(pbm->pbm_regs +
+                  EVENT_QUEUE_CONTROL_SET(msiqid),
+                  EVENT_QUEUE_CONTROL_SET_EN);
+
+       return virt_irq;
+}
+
+static const struct sparc64_msiq_ops pci_fire_msiq_ops = {
+       .get_head       =       pci_fire_get_head,
+       .dequeue_msi    =       pci_fire_dequeue_msi,
+       .set_head       =       pci_fire_set_head,
+       .msi_setup      =       pci_fire_msi_setup,
+       .msi_teardown   =       pci_fire_msi_teardown,
+       .msiq_alloc     =       pci_fire_msiq_alloc,
+       .msiq_free      =       pci_fire_msiq_free,
+       .msiq_build_irq =       pci_fire_msiq_build_irq,
+};
+
+static void pci_fire_msi_init(struct pci_pbm_info *pbm)
+{
+       sparc64_pbm_msi_init(pbm, &pci_fire_msiq_ops);
+}
+#else /* CONFIG_PCI_MSI */
+static void pci_fire_msi_init(struct pci_pbm_info *pbm)
+{
+}
+#endif /* !(CONFIG_PCI_MSI) */
+
 /* Based at pbm->controller_regs */
 #define FIRE_PARITY_CONTROL    0x470010UL
 #define  FIRE_PARITY_ENAB      0x8000000000000000UL
@@ -176,6 +439,7 @@ static int pci_fire_pbm_init(struct pci_controller_info *p,
 {
        const struct linux_prom64_registers *regs;
        struct pci_pbm_info *pbm;
+       int err;
 
        if ((portid & 1) == 0)
                pbm = &p->pbm_A;
@@ -208,7 +472,13 @@ static int pci_fire_pbm_init(struct pci_controller_info *p,
 
        pci_fire_hw_init(pbm);
 
-       return pci_fire_pbm_iommu_init(pbm);
+       err = pci_fire_pbm_iommu_init(pbm);
+       if (err)
+               return err;
+
+       pci_fire_msi_init(pbm);
+
+       return 0;
 }
 
 static inline int portid_compare(u32 x, u32 y)
@@ -249,13 +519,6 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
 
        p->pbm_B.iommu = iommu;
 
-       /* XXX MSI support XXX */
-
-       /* Like PSYCHO and SCHIZO we have a 2GB aligned area
-        * for memory space.
-        */
-       pci_memspace_mask = 0x7fffffffUL;
-
        if (pci_fire_pbm_init(p, dp, portid))
                goto fatal_memory_error;
 
index f660c2b685ebfe6c8682dff6facfe8f8acaf9e8f..4a50da13ce4899d7641cceb667e13652a2d46c32 100644 (file)
 #define PCI_STC_FLUSHFLAG_SET(STC) \
        (*((STC)->strbuf_flushflag) != 0UL)
 
+#ifdef CONFIG_PCI_MSI
+struct pci_pbm_info;
+struct sparc64_msiq_ops {
+       int (*get_head)(struct pci_pbm_info *pbm, unsigned long msiqid,
+                       unsigned long *head);
+       int (*dequeue_msi)(struct pci_pbm_info *pbm, unsigned long msiqid,
+                          unsigned long *head, unsigned long *msi);
+       int (*set_head)(struct pci_pbm_info *pbm, unsigned long msiqid,
+                       unsigned long head);
+       int (*msi_setup)(struct pci_pbm_info *pbm, unsigned long msiqid,
+                        unsigned long msi, int is_msi64);
+       int (*msi_teardown)(struct pci_pbm_info *pbm, unsigned long msi);
+       int (*msiq_alloc)(struct pci_pbm_info *pbm);
+       void (*msiq_free)(struct pci_pbm_info *pbm);
+       int (*msiq_build_irq)(struct pci_pbm_info *pbm, unsigned long msiqid,
+                             unsigned long devino);
+};
+
+extern void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
+                                const struct sparc64_msiq_ops *ops);
+
+struct sparc64_msiq_cookie {
+       struct pci_pbm_info *pbm;
+       unsigned long msiqid;
+};
+#endif
+
 struct pci_controller_info;
 
 struct pci_pbm_info {
@@ -90,6 +117,8 @@ struct pci_pbm_info {
        u32                             msiq_ent_count;
        u32                             msiq_first;
        u32                             msiq_first_devino;
+       u32                             msiq_rotor;
+       struct sparc64_msiq_cookie      *msiq_irq_cookies;
        u32                             msi_num;
        u32                             msi_first;
        u32                             msi_data_mask;
@@ -100,9 +129,11 @@ struct pci_pbm_info {
        u32                             msi64_len;
        void                            *msi_queues;
        unsigned long                   *msi_bitmap;
+       unsigned int                    *msi_irq_table;
        int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
                             struct msi_desc *entry);
        void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
+       const struct sparc64_msiq_ops   *msi_ops;
 #endif /* !(CONFIG_PCI_MSI) */
 
        /* This PBM's streaming buffer. */
@@ -126,7 +157,6 @@ struct pci_controller_info {
 };
 
 extern struct pci_pbm_info *pci_pbm_root;
-extern unsigned long pci_memspace_mask;
 
 extern int pci_num_pbms;
 
diff --git a/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c
new file mode 100644 (file)
index 0000000..31a165f
--- /dev/null
@@ -0,0 +1,433 @@
+/* pci_msi.c: Sparc64 MSI support common layer.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include "pci_impl.h"
+
+static irqreturn_t sparc64_msiq_interrupt(int irq, void *cookie)
+{
+       struct sparc64_msiq_cookie *msiq_cookie = cookie;
+       struct pci_pbm_info *pbm = msiq_cookie->pbm;
+       unsigned long msiqid = msiq_cookie->msiqid;
+       const struct sparc64_msiq_ops *ops;
+       unsigned long orig_head, head;
+       int err;
+
+       ops = pbm->msi_ops;
+
+       err = ops->get_head(pbm, msiqid, &head);
+       if (unlikely(err < 0))
+               goto err_get_head;
+
+       orig_head = head;
+       for (;;) {
+               unsigned long msi;
+
+               err = ops->dequeue_msi(pbm, msiqid, &head, &msi);
+               if (likely(err > 0))
+                       __do_IRQ(pbm->msi_irq_table[msi - pbm->msi_first]);
+
+               if (unlikely(err < 0))
+                       goto err_dequeue;
+
+               if (err == 0)
+                       break;
+       }
+       if (likely(head != orig_head)) {
+               err = ops->set_head(pbm, msiqid, head);
+               if (unlikely(err < 0))
+                       goto err_set_head;
+       }
+       return IRQ_HANDLED;
+
+err_get_head:
+       printk(KERN_EMERG "MSI: Get head on msiqid[%lu] gives error %d\n",
+              msiqid, err);
+       goto err_out;
+
+err_dequeue:
+       printk(KERN_EMERG "MSI: Dequeue head[%lu] from msiqid[%lu] "
+              "gives error %d\n",
+              head, msiqid, err);
+       goto err_out;
+
+err_set_head:
+       printk(KERN_EMERG "MSI: Set head[%lu] on msiqid[%lu] "
+              "gives error %d\n",
+              head, msiqid, err);
+       goto err_out;
+
+err_out:
+       return IRQ_NONE;
+}
+
+static u32 pick_msiq(struct pci_pbm_info *pbm)
+{
+       static DEFINE_SPINLOCK(rotor_lock);
+       unsigned long flags;
+       u32 ret, rotor;
+
+       spin_lock_irqsave(&rotor_lock, flags);
+
+       rotor = pbm->msiq_rotor;
+       ret = pbm->msiq_first + rotor;
+
+       if (++rotor >= pbm->msiq_num)
+               rotor = 0;
+       pbm->msiq_rotor = rotor;
+
+       spin_unlock_irqrestore(&rotor_lock, flags);
+
+       return ret;
+}
+
+
+static int alloc_msi(struct pci_pbm_info *pbm)
+{
+       int i;
+
+       for (i = 0; i < pbm->msi_num; i++) {
+               if (!test_and_set_bit(i, pbm->msi_bitmap))
+                       return i + pbm->msi_first;
+       }
+
+       return -ENOENT;
+}
+
+static void free_msi(struct pci_pbm_info *pbm, int msi_num)
+{
+       msi_num -= pbm->msi_first;
+       clear_bit(msi_num, pbm->msi_bitmap);
+}
+
+static struct irq_chip msi_irq = {
+       .typename       = "PCI-MSI",
+       .mask           = mask_msi_irq,
+       .unmask         = unmask_msi_irq,
+       .enable         = unmask_msi_irq,
+       .disable        = mask_msi_irq,
+       /* XXX affinity XXX */
+};
+
+int sparc64_setup_msi_irq(unsigned int *virt_irq_p,
+                         struct pci_dev *pdev,
+                         struct msi_desc *entry)
+{
+       struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
+       const struct sparc64_msiq_ops *ops = pbm->msi_ops;
+       struct msi_msg msg;
+       int msi, err;
+       u32 msiqid;
+
+       *virt_irq_p = virt_irq_alloc(0, 0);
+       err = -ENOMEM;
+       if (!*virt_irq_p)
+               goto out_err;
+
+       set_irq_chip(*virt_irq_p, &msi_irq);
+
+       err = alloc_msi(pbm);
+       if (unlikely(err < 0))
+               goto out_virt_irq_free;
+
+       msi = err;
+
+       msiqid = pick_msiq(pbm);
+
+       err = ops->msi_setup(pbm, msiqid, msi,
+                            (entry->msi_attrib.is_64 ? 1 : 0));
+       if (err)
+               goto out_msi_free;
+
+       pbm->msi_irq_table[msi - pbm->msi_first] = *virt_irq_p;
+
+       if (entry->msi_attrib.is_64) {
+               msg.address_hi = pbm->msi64_start >> 32;
+               msg.address_lo = pbm->msi64_start & 0xffffffff;
+       } else {
+               msg.address_hi = 0;
+               msg.address_lo = pbm->msi32_start;
+       }
+       msg.data = msi;
+
+       set_irq_msi(*virt_irq_p, entry);
+       write_msi_msg(*virt_irq_p, &msg);
+
+       return 0;
+
+out_msi_free:
+       free_msi(pbm, msi);
+
+out_virt_irq_free:
+       set_irq_chip(*virt_irq_p, NULL);
+       virt_irq_free(*virt_irq_p);
+       *virt_irq_p = 0;
+
+out_err:
+       return err;
+}
+
+void sparc64_teardown_msi_irq(unsigned int virt_irq,
+                             struct pci_dev *pdev)
+{
+       struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
+       const struct sparc64_msiq_ops *ops = pbm->msi_ops;
+       unsigned int msi_num;
+       int i, err;
+
+       for (i = 0; i < pbm->msi_num; i++) {
+               if (pbm->msi_irq_table[i] == virt_irq)
+                       break;
+       }
+       if (i >= pbm->msi_num) {
+               printk(KERN_ERR "%s: teardown: No MSI for irq %u\n",
+                      pbm->name, virt_irq);
+               return;
+       }
+
+       msi_num = pbm->msi_first + i;
+       pbm->msi_irq_table[i] = ~0U;
+
+       err = ops->msi_teardown(pbm, msi_num);
+       if (err) {
+               printk(KERN_ERR "%s: teardown: ops->teardown() on MSI %u, "
+                      "irq %u, gives error %d\n",
+                      pbm->name, msi_num, virt_irq, err);
+               return;
+       }
+
+       free_msi(pbm, msi_num);
+
+       set_irq_chip(virt_irq, NULL);
+       virt_irq_free(virt_irq);
+}
+
+static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
+{
+       unsigned long size, bits_per_ulong;
+
+       bits_per_ulong = sizeof(unsigned long) * 8;
+       size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
+       size /= 8;
+       BUG_ON(size % sizeof(unsigned long));
+
+       pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
+       if (!pbm->msi_bitmap)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void msi_bitmap_free(struct pci_pbm_info *pbm)
+{
+       kfree(pbm->msi_bitmap);
+       pbm->msi_bitmap = NULL;
+}
+
+static int msi_table_alloc(struct pci_pbm_info *pbm)
+{
+       int size, i;
+
+       size = pbm->msiq_num * sizeof(struct sparc64_msiq_cookie);
+       pbm->msiq_irq_cookies = kzalloc(size, GFP_KERNEL);
+       if (!pbm->msiq_irq_cookies)
+               return -ENOMEM;
+
+       for (i = 0; i < pbm->msiq_num; i++) {
+               struct sparc64_msiq_cookie *p;
+
+               p = &pbm->msiq_irq_cookies[i];
+               p->pbm = pbm;
+               p->msiqid = pbm->msiq_first + i;
+       }
+
+       size = pbm->msi_num * sizeof(unsigned int);
+       pbm->msi_irq_table = kzalloc(size, GFP_KERNEL);
+       if (!pbm->msi_irq_table) {
+               kfree(pbm->msiq_irq_cookies);
+               pbm->msiq_irq_cookies = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void msi_table_free(struct pci_pbm_info *pbm)
+{
+       kfree(pbm->msiq_irq_cookies);
+       pbm->msiq_irq_cookies = NULL;
+
+       kfree(pbm->msi_irq_table);
+       pbm->msi_irq_table = NULL;
+}
+
+static int bringup_one_msi_queue(struct pci_pbm_info *pbm,
+                                const struct sparc64_msiq_ops *ops,
+                                unsigned long msiqid,
+                                unsigned long devino)
+{
+       int irq = ops->msiq_build_irq(pbm, msiqid, devino);
+       int err;
+
+       if (irq < 0)
+               return irq;
+
+       err = request_irq(irq, sparc64_msiq_interrupt, 0,
+                         "MSIQ",
+                         &pbm->msiq_irq_cookies[msiqid - pbm->msiq_first]);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int sparc64_bringup_msi_queues(struct pci_pbm_info *pbm,
+                                     const struct sparc64_msiq_ops *ops)
+{
+       int i;
+
+       for (i = 0; i < pbm->msiq_num; i++) {
+               unsigned long msiqid = i + pbm->msiq_first;
+               unsigned long devino = i + pbm->msiq_first_devino;
+               int err;
+
+               err = bringup_one_msi_queue(pbm, ops, msiqid, devino);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
+                         const struct sparc64_msiq_ops *ops)
+{
+       const u32 *val;
+       int len;
+
+       val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+       if (!val || len != 4)
+               goto no_msi;
+       pbm->msiq_num = *val;
+       if (pbm->msiq_num) {
+               const struct msiq_prop {
+                       u32 first_msiq;
+                       u32 num_msiq;
+                       u32 first_devino;
+               } *mqp;
+               const struct msi_range_prop {
+                       u32 first_msi;
+                       u32 num_msi;
+               } *mrng;
+               const struct addr_range_prop {
+                       u32 msi32_high;
+                       u32 msi32_low;
+                       u32 msi32_len;
+                       u32 msi64_high;
+                       u32 msi64_low;
+                       u32 msi64_len;
+               } *arng;
+
+               val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+
+               pbm->msiq_ent_count = *val;
+
+               mqp = of_get_property(pbm->prom_node,
+                                     "msi-eq-to-devino", &len);
+               if (!mqp)
+                       mqp = of_get_property(pbm->prom_node,
+                                             "msi-eq-devino", &len);
+               if (!mqp || len != sizeof(struct msiq_prop))
+                       goto no_msi;
+
+               pbm->msiq_first = mqp->first_msiq;
+               pbm->msiq_first_devino = mqp->first_devino;
+
+               val = of_get_property(pbm->prom_node, "#msi", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+               pbm->msi_num = *val;
+
+               mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+               if (!mrng || len != sizeof(struct msi_range_prop))
+                       goto no_msi;
+               pbm->msi_first = mrng->first_msi;
+
+               val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+               pbm->msi_data_mask = *val;
+
+               val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+               pbm->msix_data_width = *val;
+
+               arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+                                      &len);
+               if (!arng || len != sizeof(struct addr_range_prop))
+                       goto no_msi;
+               pbm->msi32_start = ((u64)arng->msi32_high << 32) |
+                       (u64) arng->msi32_low;
+               pbm->msi64_start = ((u64)arng->msi64_high << 32) |
+                       (u64) arng->msi64_low;
+               pbm->msi32_len = arng->msi32_len;
+               pbm->msi64_len = arng->msi64_len;
+
+               if (msi_bitmap_alloc(pbm))
+                       goto no_msi;
+
+               if (msi_table_alloc(pbm)) {
+                       msi_bitmap_free(pbm);
+                       goto no_msi;
+               }
+
+               if (ops->msiq_alloc(pbm)) {
+                       msi_table_free(pbm);
+                       msi_bitmap_free(pbm);
+                       goto no_msi;
+               }
+
+               if (sparc64_bringup_msi_queues(pbm, ops)) {
+                       ops->msiq_free(pbm);
+                       msi_table_free(pbm);
+                       msi_bitmap_free(pbm);
+                       goto no_msi;
+               }
+
+               printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
+                      "devino[0x%x]\n",
+                      pbm->name,
+                      pbm->msiq_first, pbm->msiq_num,
+                      pbm->msiq_ent_count,
+                      pbm->msiq_first_devino);
+               printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
+                      "width[%u]\n",
+                      pbm->name,
+                      pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
+                      pbm->msix_data_width);
+               printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
+                      "addr64[0x%lx:0x%x]\n",
+                      pbm->name,
+                      pbm->msi32_start, pbm->msi32_len,
+                      pbm->msi64_start, pbm->msi64_len);
+               printk(KERN_INFO "%s: MSI queues at RA [%016lx]\n",
+                      pbm->name,
+                      __pa(pbm->msi_queues));
+
+               pbm->msi_ops = ops;
+               pbm->setup_msi_irq = sparc64_setup_msi_irq;
+               pbm->teardown_msi_irq = sparc64_teardown_msi_irq;
+       }
+       return;
+
+no_msi:
+       pbm->msiq_num = 0;
+       printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
+}
index b6b4cfea5b5f55bdc7f23e87b1ddd577a8a25f64..d27ee5d528a2d6bfb3ef79f64aa7e225f5caa330 100644 (file)
@@ -1058,12 +1058,6 @@ void psycho_init(struct device_node *dp, char *model_name)
        p->pbm_A.config_space = p->pbm_B.config_space =
                (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
 
-       /*
-        * Psycho's PCI MEM space is mapped to a 2GB aligned area, so
-        * we need to adjust our MEM space mask.
-        */
-       pci_memspace_mask = 0x7fffffffUL;
-
        psycho_controller_hwinit(&p->pbm_A);
 
        if (psycho_iommu_init(&p->pbm_A))
index 3c30bfa1f3a37a9c0d7be4c6a43d7501a5ed26cd..9546ba9f5dee5c5b16b76c77c1324aeacb484b68 100644 (file)
@@ -1464,9 +1464,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
 
        p->pbm_B.iommu = iommu;
 
-       /* Like PSYCHO we have a 2GB aligned area for memory space. */
-       pci_memspace_mask = 0x7fffffffUL;
-
        if (schizo_pbm_init(p, dp, portid, chip_type))
                goto fatal_memory_error;
 
index da724b13e89e45eaf567bdfb380268bbd7fcecf9..95de1444ee674c912a4fc51cf66a2b0b2f64754b 100644 (file)
@@ -748,111 +748,102 @@ struct pci_sun4v_msiq_entry {
        u64             reserved2;
 };
 
-/* For now this just runs as a pre-handler for the real interrupt handler.
- * So we just walk through the queue and ACK all the entries, update the
- * head pointer, and return.
- *
- * In the longer term it would be nice to do something more integrated
- * wherein we can pass in some of this MSI info to the drivers.  This
- * would be most useful for PCIe fabric error messages, although we could
- * invoke those directly from the loop here in order to pass the info around.
- */
-static void pci_sun4v_msi_prehandler(unsigned int ino, void *data1, void *data2)
+static int pci_sun4v_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+                             unsigned long *head)
 {
-       struct pci_pbm_info *pbm = data1;
-       struct pci_sun4v_msiq_entry *base, *ep;
-       unsigned long msiqid, orig_head, head, type, err;
-
-       msiqid = (unsigned long) data2;
+       unsigned long err, limit;
 
-       head = 0xdeadbeef;
-       err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, &head);
+       err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, head);
        if (unlikely(err))
-               goto hv_error_get;
-
-       if (unlikely(head >= (pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry))))
-               goto bad_offset;
-
-       head /= sizeof(struct pci_sun4v_msiq_entry);
-       orig_head = head;
-       base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) *
-                                  (pbm->msiq_ent_count *
-                                   sizeof(struct pci_sun4v_msiq_entry))));
-       ep = &base[head];
-       while ((ep->version_type & MSIQ_TYPE_MASK) != 0) {
-               type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT;
-               if (unlikely(type != MSIQ_TYPE_MSI32 &&
-                            type != MSIQ_TYPE_MSI64))
-                       goto bad_type;
-
-               pci_sun4v_msi_setstate(pbm->devhandle,
-                                      ep->msi_data /* msi_num */,
-                                      HV_MSISTATE_IDLE);
-
-               /* Clear the entry.  */
-               ep->version_type &= ~MSIQ_TYPE_MASK;
-
-               /* Go to next entry in ring.  */
-               head++;
-               if (head >= pbm->msiq_ent_count)
-                       head = 0;
-               ep = &base[head];
-       }
+               return -ENXIO;
 
-       if (likely(head != orig_head)) {
-               /* ACK entries by updating head pointer.  */
-               head *= sizeof(struct pci_sun4v_msiq_entry);
-               err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head);
-               if (unlikely(err))
-                       goto hv_error_set;
-       }
-       return;
+       limit = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry);
+       if (unlikely(*head >= limit))
+               return -EFBIG;
 
-hv_error_set:
-       printk(KERN_EMERG "MSI: Hypervisor set head gives error %lu\n", err);
-       goto hv_error_cont;
+       return 0;
+}
 
-hv_error_get:
-       printk(KERN_EMERG "MSI: Hypervisor get head gives error %lu\n", err);
+static int pci_sun4v_dequeue_msi(struct pci_pbm_info *pbm,
+                                unsigned long msiqid, unsigned long *head,
+                                unsigned long *msi)
+{
+       struct pci_sun4v_msiq_entry *ep;
+       unsigned long err, type;
 
-hv_error_cont:
-       printk(KERN_EMERG "MSI: devhandle[%x] msiqid[%lx] head[%lu]\n",
-              pbm->devhandle, msiqid, head);
-       return;
+       /* Note: void pointer arithmetic, 'head' is a byte offset  */
+       ep = (pbm->msi_queues + ((msiqid - pbm->msiq_first) *
+                                (pbm->msiq_ent_count *
+                                 sizeof(struct pci_sun4v_msiq_entry))) +
+             *head);
 
-bad_offset:
-       printk(KERN_EMERG "MSI: Hypervisor gives bad offset %lx max(%lx)\n",
-              head, pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry));
-       return;
+       if ((ep->version_type & MSIQ_TYPE_MASK) == 0)
+               return 0;
 
-bad_type:
-       printk(KERN_EMERG "MSI: Entry has bad type %lx\n", type);
-       return;
+       type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT;
+       if (unlikely(type != MSIQ_TYPE_MSI32 &&
+                    type != MSIQ_TYPE_MSI64))
+               return -EINVAL;
+
+       *msi = ep->msi_data;
+
+       err = pci_sun4v_msi_setstate(pbm->devhandle,
+                                    ep->msi_data /* msi_num */,
+                                    HV_MSISTATE_IDLE);
+       if (unlikely(err))
+               return -ENXIO;
+
+       /* Clear the entry.  */
+       ep->version_type &= ~MSIQ_TYPE_MASK;
+
+       (*head) += sizeof(struct pci_sun4v_msiq_entry);
+       if (*head >=
+           (pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry)))
+               *head = 0;
+
+       return 1;
 }
 
-static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
+static int pci_sun4v_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
+                             unsigned long head)
 {
-       unsigned long size, bits_per_ulong;
+       unsigned long err;
 
-       bits_per_ulong = sizeof(unsigned long) * 8;
-       size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
-       size /= 8;
-       BUG_ON(size % sizeof(unsigned long));
+       err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head);
+       if (unlikely(err))
+               return -EINVAL;
 
-       pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
-       if (!pbm->msi_bitmap)
-               return -ENOMEM;
+       return 0;
+}
 
+static int pci_sun4v_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
+                              unsigned long msi, int is_msi64)
+{
+       if (pci_sun4v_msi_setmsiq(pbm->devhandle, msi, msiqid,
+                                 (is_msi64 ?
+                                  HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32)))
+               return -ENXIO;
+       if (pci_sun4v_msi_setstate(pbm->devhandle, msi, HV_MSISTATE_IDLE))
+               return -ENXIO;
+       if (pci_sun4v_msi_setvalid(pbm->devhandle, msi, HV_MSIVALID_VALID))
+               return -ENXIO;
        return 0;
 }
 
-static void msi_bitmap_free(struct pci_pbm_info *pbm)
+static int pci_sun4v_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
 {
-       kfree(pbm->msi_bitmap);
-       pbm->msi_bitmap = NULL;
+       unsigned long err, msiqid;
+
+       err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi, &msiqid);
+       if (err)
+               return -ENXIO;
+
+       pci_sun4v_msi_setvalid(pbm->devhandle, msi, HV_MSIVALID_INVALID);
+
+       return 0;
 }
 
-static int msi_queue_alloc(struct pci_pbm_info *pbm)
+static int pci_sun4v_msiq_alloc(struct pci_pbm_info *pbm)
 {
        unsigned long q_size, alloc_size, pages, order;
        int i;
@@ -906,232 +897,59 @@ h_error:
        return -EINVAL;
 }
 
-
-static int alloc_msi(struct pci_pbm_info *pbm)
+static void pci_sun4v_msiq_free(struct pci_pbm_info *pbm)
 {
+       unsigned long q_size, alloc_size, pages, order;
        int i;
 
-       for (i = 0; i < pbm->msi_num; i++) {
-               if (!test_and_set_bit(i, pbm->msi_bitmap))
-                       return i + pbm->msi_first;
-       }
-
-       return -ENOENT;
-}
-
-static void free_msi(struct pci_pbm_info *pbm, int msi_num)
-{
-       msi_num -= pbm->msi_first;
-       clear_bit(msi_num, pbm->msi_bitmap);
-}
-
-static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
-                                  struct pci_dev *pdev,
-                                  struct msi_desc *entry)
-{
-       struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       unsigned long devino, msiqid;
-       struct msi_msg msg;
-       int msi_num, err;
-
-       *virt_irq_p = 0;
-
-       msi_num = alloc_msi(pbm);
-       if (msi_num < 0)
-               return msi_num;
-
-       err = sun4v_build_msi(pbm->devhandle, virt_irq_p,
-                             pbm->msiq_first_devino,
-                             (pbm->msiq_first_devino +
-                              pbm->msiq_num));
-       if (err < 0)
-               goto out_err;
-       devino = err;
-
-       msiqid = ((devino - pbm->msiq_first_devino) +
-                 pbm->msiq_first);
-
-       err = -EINVAL;
-       if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
-       if (err)
-               goto out_err;
-
-       if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
-               goto out_err;
-
-       if (pci_sun4v_msi_setmsiq(pbm->devhandle,
-                                 msi_num, msiqid,
-                                 (entry->msi_attrib.is_64 ?
-                                  HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32)))
-               goto out_err;
-
-       if (pci_sun4v_msi_setstate(pbm->devhandle, msi_num, HV_MSISTATE_IDLE))
-               goto out_err;
-
-       if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID))
-               goto out_err;
-
-       sparc64_set_msi(*virt_irq_p, msi_num);
+       for (i = 0; i < pbm->msiq_num; i++) {
+               unsigned long msiqid = pbm->msiq_first + i;
 
-       if (entry->msi_attrib.is_64) {
-               msg.address_hi = pbm->msi64_start >> 32;
-               msg.address_lo = pbm->msi64_start & 0xffffffff;
-       } else {
-               msg.address_hi = 0;
-               msg.address_lo = pbm->msi32_start;
+               (void) pci_sun4v_msiq_conf(pbm->devhandle, msiqid, 0UL, 0);
        }
-       msg.data = msi_num;
-
-       set_irq_msi(*virt_irq_p, entry);
-       write_msi_msg(*virt_irq_p, &msg);
 
-       irq_install_pre_handler(*virt_irq_p,
-                               pci_sun4v_msi_prehandler,
-                               pbm, (void *) msiqid);
+       q_size = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry);
+       alloc_size = (pbm->msiq_num * q_size);
+       order = get_order(alloc_size);
 
-       return 0;
+       pages = (unsigned long) pbm->msi_queues;
 
-out_err:
-       free_msi(pbm, msi_num);
-       return err;
+       free_pages(pages, order);
 
+       pbm->msi_queues = NULL;
 }
 
-static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
-                                      struct pci_dev *pdev)
+static int pci_sun4v_msiq_build_irq(struct pci_pbm_info *pbm,
+                                   unsigned long msiqid,
+                                   unsigned long devino)
 {
-       struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       unsigned long msiqid, err;
-       unsigned int msi_num;
-
-       msi_num = sparc64_get_msi(virt_irq);
-       err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid);
-       if (err) {
-               printk(KERN_ERR "%s: getmsiq gives error %lu\n",
-                      pbm->name, err);
-               return;
-       }
+       unsigned int virt_irq = sun4v_build_irq(pbm->devhandle, devino);
 
-       pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_INVALID);
-       pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_INVALID);
+       if (!virt_irq)
+               return -ENOMEM;
 
-       free_msi(pbm, msi_num);
+       if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
+               return -EINVAL;
+       if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
+               return -EINVAL;
 
-       /* The sun4v_destroy_msi() will liberate the devino and thus the MSIQ
-        * allocation.
-        */
-       sun4v_destroy_msi(virt_irq);
+       return virt_irq;
 }
 
+static const struct sparc64_msiq_ops pci_sun4v_msiq_ops = {
+       .get_head       =       pci_sun4v_get_head,
+       .dequeue_msi    =       pci_sun4v_dequeue_msi,
+       .set_head       =       pci_sun4v_set_head,
+       .msi_setup      =       pci_sun4v_msi_setup,
+       .msi_teardown   =       pci_sun4v_msi_teardown,
+       .msiq_alloc     =       pci_sun4v_msiq_alloc,
+       .msiq_free      =       pci_sun4v_msiq_free,
+       .msiq_build_irq =       pci_sun4v_msiq_build_irq,
+};
+
 static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 {
-       const u32 *val;
-       int len;
-
-       val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
-       if (!val || len != 4)
-               goto no_msi;
-       pbm->msiq_num = *val;
-       if (pbm->msiq_num) {
-               const struct msiq_prop {
-                       u32 first_msiq;
-                       u32 num_msiq;
-                       u32 first_devino;
-               } *mqp;
-               const struct msi_range_prop {
-                       u32 first_msi;
-                       u32 num_msi;
-               } *mrng;
-               const struct addr_range_prop {
-                       u32 msi32_high;
-                       u32 msi32_low;
-                       u32 msi32_len;
-                       u32 msi64_high;
-                       u32 msi64_low;
-                       u32 msi64_len;
-               } *arng;
-
-               val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-
-               pbm->msiq_ent_count = *val;
-
-               mqp = of_get_property(pbm->prom_node,
-                                     "msi-eq-to-devino", &len);
-               if (!mqp || len != sizeof(struct msiq_prop))
-                       goto no_msi;
-
-               pbm->msiq_first = mqp->first_msiq;
-               pbm->msiq_first_devino = mqp->first_devino;
-
-               val = of_get_property(pbm->prom_node, "#msi", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-               pbm->msi_num = *val;
-
-               mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
-               if (!mrng || len != sizeof(struct msi_range_prop))
-                       goto no_msi;
-               pbm->msi_first = mrng->first_msi;
-
-               val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-               pbm->msi_data_mask = *val;
-
-               val = of_get_property(pbm->prom_node, "msix-data-width", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-               pbm->msix_data_width = *val;
-
-               arng = of_get_property(pbm->prom_node, "msi-address-ranges",
-                                      &len);
-               if (!arng || len != sizeof(struct addr_range_prop))
-                       goto no_msi;
-               pbm->msi32_start = ((u64)arng->msi32_high << 32) |
-                       (u64) arng->msi32_low;
-               pbm->msi64_start = ((u64)arng->msi64_high << 32) |
-                       (u64) arng->msi64_low;
-               pbm->msi32_len = arng->msi32_len;
-               pbm->msi64_len = arng->msi64_len;
-
-               if (msi_bitmap_alloc(pbm))
-                       goto no_msi;
-
-               if (msi_queue_alloc(pbm)) {
-                       msi_bitmap_free(pbm);
-                       goto no_msi;
-               }
-
-               printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
-                      "devino[0x%x]\n",
-                      pbm->name,
-                      pbm->msiq_first, pbm->msiq_num,
-                      pbm->msiq_ent_count,
-                      pbm->msiq_first_devino);
-               printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
-                      "width[%u]\n",
-                      pbm->name,
-                      pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
-                      pbm->msix_data_width);
-               printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
-                      "addr64[0x%lx:0x%x]\n",
-                      pbm->name,
-                      pbm->msi32_start, pbm->msi32_len,
-                      pbm->msi64_start, pbm->msi64_len);
-               printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
-                      pbm->name,
-                      pbm->msi_queues);
-       }
-       pbm->setup_msi_irq = pci_sun4v_setup_msi_irq;
-       pbm->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
-
-       return;
-
-no_msi:
-       pbm->msiq_num = 0;
-       printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
+       sparc64_pbm_msi_init(pbm, &pci_sun4v_msiq_ops);
 }
 #else /* CONFIG_PCI_MSI */
 static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
@@ -1237,11 +1055,6 @@ void __init sun4v_pci_init(struct device_node *dp, char *model_name)
 
        p->pbm_B.iommu = iommu;
 
-       /* Like PSYCHO and SCHIZO we have a 2GB aligned area
-        * for memory space.
-        */
-       pci_memspace_mask = 0x7fffffffUL;
-
        pci_sun4v_pbm_init(p, dp, devhandle);
        return;
 
index 881a09ee4c4c15ae4a2fac487184fad0a6c8fd06..850cdffdd69c8f816f7f259bfc8b628c42b3f404 100644 (file)
@@ -105,9 +105,11 @@ static struct of_device_id power_match[] = {
 };
 
 static struct of_platform_driver power_driver = {
-       .name           = "power",
        .match_table    = power_match,
        .probe          = power_probe,
+       .driver         = {
+               .name   = "power",
+       },
 };
 
 void __init power_init(void)
index 574bc248bca6f9edf5f5116e399ae1fe1024f65a..e2f8e1b4882a7f8cbc0c9a77c4eef33f473b7cac 100644 (file)
@@ -96,19 +96,21 @@ sun4v_dev_mondo:
        stxa    %g2, [%g4] ASI_QUEUE
        membar  #Sync
 
-       /* Get &__irq_work[smp_processor_id()] into %g1.  */
-       TRAP_LOAD_IRQ_WORK(%g1, %g4)
+       TRAP_LOAD_IRQ_WORK_PA(%g1, %g4)
 
-       /* Get &ivector_table[IVEC] into %g4.  */
-       sethi   %hi(ivector_table), %g4
-       sllx    %g3, 3, %g3
-       or      %g4, %lo(ivector_table), %g4
+       /* For VIRQs, cookie is encoded as ~bucket_phys_addr  */
+       brlz,pt %g3, 1f
+        xnor   %g3, %g0, %g4
+
+       /* Get __pa(&ivector_table[IVEC]) into %g4.  */
+       sethi   %hi(ivector_table_pa), %g4
+       ldx     [%g4 + %lo(ivector_table_pa)], %g4
+       sllx    %g3, 4, %g3
        add     %g4, %g3, %g4
 
-       /* Insert ivector_table[] entry into __irq_work[] queue.  */
-       lduw    [%g1], %g2              /* g2 = irq_work(cpu) */
-       stw     %g2, [%g4 + 0x00]       /* bucket->irq_chain = g2 */
-       stw     %g4, [%g1]              /* irq_work(cpu) = bucket */
+1:     ldx     [%g1], %g2
+       stxa    %g2, [%g4] ASI_PHYS_USE_EC
+       stx     %g4, [%g1]
 
        /* Signal the interrupt by setting (1 << pil) in %softint.  */
        wr      %g0, 1 << PIL_DEVICE_IRQ, %set_softint
index d108eeb0734fe2fe3586d01a8c2e2fdf5aaf25e4..0d5c50264945e7b2f91dd738cde7d30a3d1a87ea 100644 (file)
@@ -436,7 +436,7 @@ out:
 asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second,
                        unsigned long third, void __user *ptr, long fifth)
 {
-       int err;
+       long err;
 
        /* No need for backward compatibility. We can start fresh... */
        if (call <= SEMCTL) {
@@ -453,16 +453,9 @@ asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second,
                        err = sys_semget(first, (int)second, (int)third);
                        goto out;
                case SEMCTL: {
-                       union semun fourth;
-                       err = -EINVAL;
-                       if (!ptr)
-                               goto out;
-                       err = -EFAULT;
-                       if (get_user(fourth.__pad,
-                                    (void __user * __user *) ptr))
-                               goto out;
-                       err = sys_semctl(first, (int)second | IPC_64,
-                                        (int)third, fourth);
+                       err = sys_semctl(first, third,
+                                        (int)second | IPC_64,
+                                        (union semun) ptr);
                        goto out;
                }
                default:
index 69cad1b653c14f55a57a2ec5ad0a5e2abf5ad801..cd8c740cba1da72fccf69c78736b662383e8539b 100644 (file)
@@ -764,9 +764,11 @@ static struct of_device_id clock_match[] = {
 };
 
 static struct of_platform_driver clock_driver = {
-       .name           = "clock",
        .match_table    = clock_match,
        .probe          = clock_probe,
+       .driver         = {
+               .name   = "clock",
+       },
 };
 
 static int __init clock_init(void)
index 6ef42b8e53d84dff82b67797d81764f0d9d1a359..34573a55b6e5a92d65a420ca2daf168c65bfda65 100644 (file)
@@ -2569,8 +2569,8 @@ void __init trap_init(void)
             offsetof(struct trap_per_cpu, tsb_huge)) ||
            (TRAP_PER_CPU_TSB_HUGE_TEMP !=
             offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
-           (TRAP_PER_CPU_IRQ_WORKLIST !=
-            offsetof(struct trap_per_cpu, irq_worklist)) ||
+           (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
+            offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
            (TRAP_PER_CPU_CPU_MONDO_QMASK !=
             offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
            (TRAP_PER_CPU_DEV_MONDO_QMASK !=
index b982fa3dd748a545f8b7b29eeee1ac7901fcfb67..9fcd503bc04ad5574488379dc43787cf4cabfec3 100644 (file)
@@ -10,105 +10,138 @@ ENTRY(_start)
 jiffies = jiffies_64;
 SECTIONS
 {
-  swapper_low_pmd_dir = 0x0000000000402000;
-  . = 0x4000;
-  .text 0x0000000000404000 :
-  {
-    _text = .;
-    TEXT_TEXT
-    SCHED_TEXT
-    LOCK_TEXT
-    KPROBES_TEXT
-    *(.gnu.warning)
-  } =0
-  _etext = .;
-  PROVIDE (etext = .);
+       swapper_low_pmd_dir = 0x0000000000402000;
+       . = 0x4000;
+       .text 0x0000000000404000 : {
+               _text = .;
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+               KPROBES_TEXT
+               *(.gnu.warning)
+       } = 0
+       _etext = .;
+       PROVIDE (etext = .);
 
-  RO_DATA(PAGE_SIZE)
+       RO_DATA(PAGE_SIZE)
+       .data : {
+               DATA_DATA
+               CONSTRUCTORS
+       }
+       .data1 : {
+               *(.data1)
+       }
+       . = ALIGN(64);
+       .data.cacheline_aligned : {
+               *(.data.cacheline_aligned)
+       }
+       . = ALIGN(64);
+       .data.read_mostly : {
+               *(.data.read_mostly)
+       }
+       _edata = .;
+       PROVIDE (edata = .);
+       .fixup : {
+               *(.fixup)
+       }
+       . = ALIGN(16);
+       __ex_table : {
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+       }
+       NOTES
 
-  .data    :
-  {
-    DATA_DATA
-    CONSTRUCTORS
-  }
-  .data1   : { *(.data1) }
-  . = ALIGN(64);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-  . = ALIGN(64);
-  .data.read_mostly : { *(.data.read_mostly) }
-  _edata  =  .;
-  PROVIDE (edata = .);
-  .fixup   : { *(.fixup) }
+       . = ALIGN(PAGE_SIZE);
+       .init.text : {
+               __init_begin = .;
+               _sinittext = .;
+               *(.init.text)
+               _einittext = .;
+       }
+       .init.data : {
+               *(.init.data)
+       }
+       . = ALIGN(16);
+       .init.setup : {
+               __setup_start = .;
+               *(.init.setup)
+               __setup_end = .;
+       }
+       .initcall.init : {
+               __initcall_start = .;
+               INITCALLS
+               __initcall_end = .;
+       }
+       .con_initcall.init : {
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+       }
+       SECURITY_INIT
 
-  . = ALIGN(16);
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
+       . = ALIGN(4);
+       .tsb_ldquad_phys_patch : {
+               __tsb_ldquad_phys_patch = .;
+               *(.tsb_ldquad_phys_patch)
+               __tsb_ldquad_phys_patch_end = .;
+       }
 
-  NOTES
+       .tsb_phys_patch : {
+               __tsb_phys_patch = .;
+               *(.tsb_phys_patch)
+               __tsb_phys_patch_end = .;
+       }
 
-  . = ALIGN(PAGE_SIZE);
-  __init_begin = .;
-  .init.text : { 
-       _sinittext = .;
-       *(.init.text)
-       _einittext = .;
-  }
-  .init.data : { *(.init.data) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .init.setup : { *(.init.setup) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-       INITCALLS
-  }
-  __initcall_end = .;
-  __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
-  __con_initcall_end = .;
-  SECURITY_INIT
-  . = ALIGN(4);
-  __tsb_ldquad_phys_patch = .;
-  .tsb_ldquad_phys_patch : { *(.tsb_ldquad_phys_patch) }
-  __tsb_ldquad_phys_patch_end = .;
-  __tsb_phys_patch = .;
-  .tsb_phys_patch : { *(.tsb_phys_patch) }
-  __tsb_phys_patch_end = .;
-  __cpuid_patch = .;
-  .cpuid_patch : { *(.cpuid_patch) }
-  __cpuid_patch_end = .;
-  __sun4v_1insn_patch = .;
-  .sun4v_1insn_patch : { *(.sun4v_1insn_patch) }
-  __sun4v_1insn_patch_end = .;
-  __sun4v_2insn_patch = .;
-  .sun4v_2insn_patch : { *(.sun4v_2insn_patch) }
-  __sun4v_2insn_patch_end = .;
+       .cpuid_patch : {
+               __cpuid_patch = .;
+               *(.cpuid_patch)
+               __cpuid_patch_end = .;
+       }
+
+       .sun4v_1insn_patch : {
+               __sun4v_1insn_patch = .;
+               *(.sun4v_1insn_patch)
+               __sun4v_1insn_patch_end = .;
+       }
+       .sun4v_2insn_patch : {
+               __sun4v_2insn_patch = .;
+               *(.sun4v_2insn_patch)
+               __sun4v_2insn_patch_end = .;
+       }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-  . = ALIGN(PAGE_SIZE);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.ramfs) }
-  __initramfs_end = .;
+       . = ALIGN(PAGE_SIZE);
+       .init.ramfs : {
+               __initramfs_start = .;
+               *(.init.ramfs)
+               __initramfs_end = .;
+       }
 #endif
 
-  PERCPU(PAGE_SIZE)
+       PERCPU(PAGE_SIZE)
 
-  . = ALIGN(PAGE_SIZE);
-  __init_end = .;
-  __bss_start = .;
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       :
-  {
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
-  _end = . ;
-  PROVIDE (end = .);
-  /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) }
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+       __bss_start = .;
+       .sbss : {
+               *(.sbss)
+               *(.scommon)
+       }
+       .bss : {
+               *(.dynbss)
+               *(.bss)
+               *(COMMON)
+       }
+       _end = . ;
+       PROVIDE (end = .);
 
-  STABS_DEBUG
+       /DISCARD/ : {
+               *(.exit.text)
+               *(.exit.data)
+               *(.exitcall.exit)
+       }
 
-  DWARF_DEBUG
+       STABS_DEBUG
+       DWARF_DEBUG
 }
index a79c8888170d938a2d60b033b19cce5e0a214a8b..f44f58f40234c51962bd22cd15d119bcc99651b5 100644 (file)
@@ -491,12 +491,12 @@ xor_niagara_4:            /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */
        ldda            [%i1 + 0x10] %asi, %i2  /* %i2/%i3 = src1 + 0x10 */
        xor             %g2, %i4, %g2
        xor             %g3, %i5, %g3
-       ldda            [%i7 + 0x10] %asi, %i4  /* %i4/%i5 = src2 + 0x10 */
+       ldda            [%l7 + 0x10] %asi, %i4  /* %i4/%i5 = src2 + 0x10 */
        xor             %l0, %g2, %l0
        xor             %l1, %g3, %l1
        stxa            %l0, [%i0 + 0x00] %asi
        stxa            %l1, [%i0 + 0x08] %asi
-       ldda            [%i6 + 0x10] %asi, %g2  /* %g2/%g3 = src3 + 0x10 */
+       ldda            [%l6 + 0x10] %asi, %g2  /* %g2/%g3 = src3 + 0x10 */
        ldda            [%i0 + 0x10] %asi, %l0  /* %l0/%l1 = dest + 0x10 */
 
        xor             %i4, %i2, %i4
@@ -504,12 +504,12 @@ xor_niagara_4:            /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */
        ldda            [%i1 + 0x20] %asi, %i2  /* %i2/%i3 = src1 + 0x20 */
        xor             %g2, %i4, %g2
        xor             %g3, %i5, %g3
-       ldda            [%i7 + 0x20] %asi, %i4  /* %i4/%i5 = src2 + 0x20 */
+       ldda            [%l7 + 0x20] %asi, %i4  /* %i4/%i5 = src2 + 0x20 */
        xor             %l0, %g2, %l0
        xor             %l1, %g3, %l1
        stxa            %l0, [%i0 + 0x10] %asi
        stxa            %l1, [%i0 + 0x18] %asi
-       ldda            [%i6 + 0x20] %asi, %g2  /* %g2/%g3 = src3 + 0x20 */
+       ldda            [%l6 + 0x20] %asi, %g2  /* %g2/%g3 = src3 + 0x20 */
        ldda            [%i0 + 0x20] %asi, %l0  /* %l0/%l1 = dest + 0x20 */
 
        xor             %i4, %i2, %i4
@@ -517,12 +517,12 @@ xor_niagara_4:            /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */
        ldda            [%i1 + 0x30] %asi, %i2  /* %i2/%i3 = src1 + 0x30 */
        xor             %g2, %i4, %g2
        xor             %g3, %i5, %g3
-       ldda            [%i7 + 0x30] %asi, %i4  /* %i4/%i5 = src2 + 0x30 */
+       ldda            [%l7 + 0x30] %asi, %i4  /* %i4/%i5 = src2 + 0x30 */
        xor             %l0, %g2, %l0
        xor             %l1, %g3, %l1
        stxa            %l0, [%i0 + 0x20] %asi
        stxa            %l1, [%i0 + 0x28] %asi
-       ldda            [%i6 + 0x30] %asi, %g2  /* %g2/%g3 = src3 + 0x30 */
+       ldda            [%l6 + 0x30] %asi, %g2  /* %g2/%g3 = src3 + 0x30 */
        ldda            [%i0 + 0x30] %asi, %l0  /* %l0/%l1 = dest + 0x30 */
 
        prefetch        [%i1 + 0x40], #one_read
index 3010227fe24313ccddc630068c9503aa77b7c409..f0ab9aab308faeedf072657d3b35a22e55fc0367 100644 (file)
@@ -631,7 +631,6 @@ void prom_world(int enter)
        __asm__ __volatile__("flushw");
 }
 
-#ifdef DCACHE_ALIASING_POSSIBLE
 void __flush_dcache_range(unsigned long start, unsigned long end)
 {
        unsigned long va;
@@ -655,7 +654,6 @@ void __flush_dcache_range(unsigned long start, unsigned long end)
                                               "i" (ASI_DCACHE_INVALIDATE));
        }
 }
-#endif /* DCACHE_ALIASING_POSSIBLE */
 
 /* get_new_mmu_context() uses "cache + 1".  */
 DEFINE_SPINLOCK(ctx_alloc_lock);
index 989224f21346b5ddc223d66b3f72735084016b4c..0666729eb976a55290ddb99725f285d27dbc084d 100644 (file)
@@ -176,9 +176,9 @@ include/asm-um/arch:
        @echo '  SYMLINK $@'
 ifneq ($(KBUILD_SRC),)
        $(Q)mkdir -p $(objtree)/include/asm-um
-       $(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch
+       $(Q)ln -fsn $(srctree)/include/asm-$(HEADER_ARCH) include/asm-um/arch
 else
-       $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
+       $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(HEADER_ARCH) arch
 endif
 
 $(objtree)/$(ARCH_DIR)/include:
@@ -232,4 +232,4 @@ $(ARCH_DIR)/include/kern_constants.h: $(objtree)/$(ARCH_DIR)/include
        @echo '  SYMLINK $@'
        $(Q)ln -sf ../../../include/asm-um/asm-offsets.h $@
 
-export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS
+export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS HEADER_ARCH
index c9f1c5b24c9a34f723d0521111eb7e777d165302..60107ed4905b4ee4f3d31504779d1f370b324a5d 100644 (file)
@@ -1,4 +1,4 @@
-core-y += arch/um/sys-i386/ arch/i386/crypto/
+core-y += arch/um/sys-i386/ arch/x86/crypto/
 
 TOP_ADDR := $(CONFIG_TOP_ADDR)
 
@@ -12,6 +12,7 @@ LDFLAGS                       += -m elf_i386
 ELF_ARCH               := $(SUBARCH)
 ELF_FORMAT             := elf32-$(SUBARCH)
 OBJCOPYFLAGS           := -O binary -R .note -R .comment -S
+HEADER_ARCH            := x86
 
 ifeq ("$(origin SUBARCH)", "command line")
 ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)")
@@ -24,6 +25,11 @@ export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS
 endif
 endif
 
+CFLAGS                 += -DCONFIG_X86_32
+AFLAGS                 += -DCONFIG_X86_32
+CONFIG_X86_32          := y
+export CONFIG_X86_32
+
 ARCH_KERNEL_DEFINES += -U__$(SUBARCH)__ -U$(SUBARCH)
 
 # First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y.
index 69ecea63fdae35f56a32115e417efb64ac822741..8a00e5f6934c84f5b2ee94e7312dba33a781d426 100644 (file)
@@ -1,7 +1,7 @@
 # Copyright 2003 - 2004 Pathscale, Inc
 # Released under the GPL
 
-core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/
+core-y += arch/um/sys-x86_64/ arch/x86/crypto/
 START := 0x60000000
 
 _extra_flags_ = -fno-builtin -m64
@@ -18,6 +18,7 @@ CPPFLAGS += -m64
 
 ELF_ARCH := i386:x86-64
 ELF_FORMAT := elf64-x86-64
+HEADER_ARCH := x86
 
 # Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example.
 
index a9a4b85ca51633e13c783070457e7b949d6220ba..bf23dd3e24d0f86d748ba846f11c0442994dec00 100644 (file)
@@ -28,5 +28,5 @@ endef
 
 ifdef subarch-obj-y
 obj-y += subarch.o
-subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y))
+subarch-y = $(addprefix ../../$(HEADER_ARCH)/,$(subarch-obj-y))
 endif
index d6b3ecd4b77e8af96c9e0f5761ef217fa70a906a..a4618b6b85b926f59207e42ed630d42f9eff3c00 100644 (file)
@@ -4,9 +4,9 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
 
 obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
 
-subarch-obj-y = lib/bitops.o lib/semaphore.o lib/string.o
-subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module.o
+subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o
+subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o
 
 USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
 
index 4d9e5efa6fb900025c9319f7a12a91825ba7417d..ea8185d85404ce2c30bdfcef33fd05a99ff3fd90 100644 (file)
@@ -11,8 +11,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
 obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
 obj-$(CONFIG_MODULES) += um_module.o
 
-subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module.o
+subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o
 
 ldt-y = ../sys-i386/ldt.o
 
index bd72d94e713e68d75a902b725424c27bb9d39421..11b03d3c6fdaf36a65f2d86aa769eddd44e914e6 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/pgtable.h>
 #include <asm/mce.h>
 #include <asm/nmi.h>
+#include <asm/vsyscall.h>
 
 #define MAX_PATCH_LEN (255-1)
 
index 395928de28eae96a72c7ecc49ef7bdbc79889edb..09b82093bc759e5aa9eb1f9003bf7d4c822d0679 100644 (file)
@@ -964,8 +964,34 @@ void __init setup_boot_APIC_clock (void)
        setup_APIC_timer();
 }
 
+/*
+ * AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the
+ * C1E flag only in the secondary CPU, so when we detect the wreckage
+ * we already have enabled the boot CPU local apic timer. Check, if
+ * disable_apic_timer is set and the DUMMY flag is cleared. If yes,
+ * set the DUMMY flag again and force the broadcast mode in the
+ * clockevents layer.
+ */
+void __cpuinit check_boot_apic_timer_broadcast(void)
+{
+       struct clock_event_device *levt = &per_cpu(lapic_events, boot_cpu_id);
+
+       if (!disable_apic_timer ||
+           (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY))
+               return;
+
+       printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n");
+       lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;
+       levt->features |= CLOCK_EVT_FEAT_DUMMY;
+
+       local_irq_enable();
+       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, &boot_cpu_id);
+       local_irq_disable();
+}
+
 void __cpuinit setup_secondary_APIC_clock(void)
 {
+       check_boot_apic_timer_broadcast();
        setup_APIC_timer();
 }
 
index 4e5e9d364d63d09243f21295b4ce9cd0abc2ebf5..9a189cef64043a8968a465f1c34c0424354956f2 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  arch/x86_64/kernel/bugs.c
- *
  *  Copyright (C) 1994  Linus Torvalds
  *  Copyright (C) 2000  SuSE
  */
index 59266f03d1cd021b3a51f9875cdb95fc62094211..205fd5ba57f7a588d594800916c3e13cec220db1 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  arch/i386/cpu/bugs.c
- *
  *  Copyright (C) 1994  Linus Torvalds
  *
  *  Cyrix stuff, June 1998 by:
index 5c2faa10e9fac42f604d0af086af0618835c289d..f4548c93ccf5d0cf9fcd6e557e2457cd92ee75bd 100644 (file)
@@ -11,8 +11,6 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * cpuid.c
- *
  * x86 CPUID access device
  *
  * This device is accessed by lseek() to the appropriate CPUID level
index 3f532df488bca29e3cd03be11205df9d3d2808ac..32e75d0731a901681c118fb073944992a082fa1c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     kernel/crash_dump.c - Memory preserving reboot related code.
+ *     Memory preserving reboot related code.
  *
  *     Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
  *     Copyright (C) IBM Corporation, 2004. All rights reserved
index 942deac4d43aa1e2b8eb0e3118933f9b4a140e58..15e6c6bc4a46644490cfe565c342b562cddb383d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     kernel/crash_dump.c - Memory preserving reboot related code.
+ *     Memory preserving reboot related code.
  *
  *     Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
  *     Copyright (C) IBM Corporation, 2004. All rights reserved
index 290b7bc82da3c91d25c00aee470183f53a99c63c..8099fea0a72f1a959362f9a17763ee534d6316c2 100644 (file)
@@ -251,6 +251,7 @@ check_userspace:
        jb resume_kernel                # not returning to v8086 or userspace
 
 ENTRY(resume_userspace)
+       LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
@@ -338,6 +339,7 @@ sysenter_past_esp:
        jae syscall_badsys
        call *sys_call_table(,%eax,4)
        movl %eax,PT_EAX(%esp)
+       LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_ANY)
        TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
@@ -377,6 +379,7 @@ syscall_call:
        call *sys_call_table(,%eax,4)
        movl %eax,PT_EAX(%esp)          # store the return value
 syscall_exit:
+       LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
@@ -467,6 +470,7 @@ work_pending:
        jz work_notifysig
 work_resched:
        call schedule
+       LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
index 1d232e5f5658e889ef8642fc98301b3f9527fbe1..f1cacd4897f74892eea1e8c4399b1891c6b523ad 100644 (file)
@@ -244,6 +244,7 @@ ret_from_sys_call:
        movl $_TIF_ALLWORK_MASK,%edi
        /* edi: flagmask */
 sysret_check:          
+       LOCKDEP_SYS_EXIT
        GET_THREAD_INFO(%rcx)
        cli
        TRACE_IRQS_OFF
@@ -333,6 +334,7 @@ int_ret_from_sys_call:
        movl $_TIF_ALLWORK_MASK,%edi
        /* edi: mask to check */
 int_with_check:
+       LOCKDEP_SYS_EXIT_IRQ
        GET_THREAD_INFO(%rcx)
        movl threadinfo_flags(%rcx),%edx
        andl %edi,%edx
@@ -544,11 +546,13 @@ exit_intr:
 retint_with_reschedule:
        movl $_TIF_WORK_MASK,%edi
 retint_check:
+       LOCKDEP_SYS_EXIT_IRQ
        movl threadinfo_flags(%rcx),%edx
        andl %edi,%edx
        CFI_REMEMBER_STATE
        jnz  retint_careful
-retint_swapgs:         
+
+retint_swapgs:         /* return to user-space */
        /*
         * The iretq could re-enable interrupts:
         */
@@ -557,7 +561,7 @@ retint_swapgs:
        swapgs 
        jmp restore_args
 
-retint_restore_args:                           
+retint_restore_args:   /* return to kernel space */
        cli
        /*
         * The iretq could re-enable interrupts:
@@ -866,26 +870,21 @@ error_sti:
        movq ORIG_RAX(%rsp),%rsi        /* get error code */ 
        movq $-1,ORIG_RAX(%rsp)
        call *%rax
-       /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */     
-error_exit:            
-       movl %ebx,%eax          
+       /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
+error_exit:
+       movl %ebx,%eax
        RESTORE_REST
        cli
        TRACE_IRQS_OFF
        GET_THREAD_INFO(%rcx)   
        testl %eax,%eax
        jne  retint_kernel
+       LOCKDEP_SYS_EXIT_IRQ
        movl  threadinfo_flags(%rcx),%edx
        movl  $_TIF_WORK_MASK,%edi
        andl  %edi,%edx
        jnz  retint_careful
-       /*
-        * The iret might restore flags:
-        */
-       TRACE_IRQS_IRETQ
-       swapgs 
-       RESTORE_ARGS 0,8,0                                              
-       jmp iret_label
+       jmp retint_swapgs
        CFI_ENDPROC
 
 error_kernelspace:
index 6c34bdd22e2634df6bdb41cc1db8aba482ddf33f..8561f626edad129ca13d2d4603cac32a6ed30b96 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/x86_64/kernel/head64.c -- prepare to run common code
+ *  prepare to run common code
  *
  *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
  */
index 665847281ed25fe963e51a250c1e933eaea217b6..7d2e12f6c78b144ab7fca21ea5bd48627d1654f8 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/i386/kernel/i387.c
- *
  *  Copyright (C) 1994 Linus Torvalds
  *
  *  Pentium III FXSR, SSE support
index 1d58c13bc6bc0d16d0b859846e3549c7131c5d61..56c1f11471099103292b5aa291a388113d27fa9b 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86_64/kernel/i387.c
- *
  *  Copyright (C) 1994 Linus Torvalds
  *  Copyright (C) 2002 Andi Kleen, SuSE Labs
  *
index 6f508e8d7c57433085feec900a851b9a312747d2..29313832df0c082409641e1e06f234320d72b254 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * i8237.c: 8237A DMA controller suspend functions.
+ * 8237A DMA controller suspend functions.
  *
  * Written by Pierre Ossman, 2005.
  *
index ac15e4cbd9c1982574ff9cd608b0e0fd5fcaad13..5cc8841ca2c695bfeb6c514f0e461f1294312cc0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * i8253.c  8253/PIT functions
+ * 8253/PIT functions
  *
  */
 #include <linux/clockchips.h>
index 3d310a946d7610479ad86cb06f740fa974b4772a..4ed48dc8df1e76fa925f15e11febe5ebc79481fa 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *     linux/arch/i386/kernel/ioport.c
- *
  * This contains the io-permission bitmap code - written by obz, with changes
  * by Linus.
  */
index 653efa30b0f4107dd1878dcf73a9e97af7e36724..5f62fad64dabdcbb8e50cbbd8725f9fe2c768645 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *     linux/arch/x86_64/kernel/ioport.c
- *
  * This contains the io-permission bitmap code - written by obz, with changes
  * by Linus.
  */
index 4f681bcdb1fc3b1afac4676359ff1116dc3454bf..e173b763f148ad6ae032e68b590f87f519ecb159 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *     linux/arch/i386/kernel/irq.c
- *
  *     Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
  *
  * This file contains the lowest level x86-specific interrupt
index bd11e42b22bfa6b66ebf2dcf897845a1baaa25f9..865669efc540fe0904201792115531b3d31924d2 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *     linux/arch/x86_64/kernel/irq.c
- *
  *     Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
  *
  * This file contains the lowest level x86_64-specific interrupt
index 448a50b1324c94636d1a2b71f672f901991eedc6..e7d0d3c2ef6473faeb460e7e77e20e579eedeb23 100644 (file)
@@ -1,6 +1,5 @@
 /*
  *  Kernel Probes (KProbes)
- *  arch/i386/kernel/kprobes.c
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -558,6 +557,12 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
 
        resume_execution(cur, regs, kcb);
        regs->eflags |= kcb->kprobe_saved_eflags;
+#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
+       if (raw_irqs_disabled_flags(regs->eflags))
+               trace_hardirqs_off();
+       else
+               trace_hardirqs_on();
+#endif
 
        /*Restore back the original saved kprobes variables and continue. */
        if (kcb->kprobe_status == KPROBE_REENTER) {
@@ -695,6 +700,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
                        MIN_STACK_SIZE(addr));
        regs->eflags &= ~IF_MASK;
+       trace_hardirqs_off();
        regs->eip = (unsigned long)(jp->entry);
        return 1;
 }
index a30e004682e2dc60fe81a7e1caf007fbbcf314a7..62e28e52d784c8da494ebb6d2e045f5d8a9cb2b6 100644 (file)
@@ -1,6 +1,5 @@
 /*
  *  Kernel Probes (KProbes)
- *  arch/x86_64/kernel/kprobes.c
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -545,6 +544,12 @@ int __kprobes post_kprobe_handler(struct pt_regs *regs)
 
        resume_execution(cur, regs, kcb);
        regs->eflags |= kcb->kprobe_saved_rflags;
+#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
+       if (raw_irqs_disabled_flags(regs->eflags))
+               trace_hardirqs_off();
+       else
+               trace_hardirqs_on();
+#endif
 
        /* Restore the original saved kprobes variables and continue. */
        if (kcb->kprobe_status == KPROBE_REENTER) {
@@ -685,6 +690,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
                        MIN_STACK_SIZE(addr));
        regs->eflags &= ~IF_MASK;
+       trace_hardirqs_off();
        regs->rip = (unsigned long)(jp->entry);
        return 1;
 }
index e0b2d17f4f10a879758419116a1cadae42f93a71..a8b18421863a78fa4231bcf089fcff820002ef87 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/arch/i386/kernel/ldt.c
- *
  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  */
index bc9ffd5c19cc6d19f628cd8e70c8b0390da2a642..3796523d616a8d91f5decfe76a2e669a975a9700 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/arch/x86_64/kernel/ldt.c
- *
  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  * Copyright (C) 2002 Andi Kleen
index 91966bafb3dc7efe54fb1f73d368e1a192c5c7cf..deda9a221cf2109950f190e19669f30284c99b21 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * machine_kexec.c - handle transition of Linux booting another kernel
+ * handle transition of Linux booting another kernel
  * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
  *
  * This source code is licensed under the GNU General Public License,
index c3a554703672ec5097ab52d5a981d3e809bd606c..cd1899a2f0c54b4e46db9847500b2b1d5ab3bcb0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * machine_kexec.c - handle transition of Linux booting another kernel
+ * handle transition of Linux booting another kernel
  * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
  *
  * This source code is licensed under the GNU General Public License,
index b83672b895278798957b4a9748e96965c3d23e08..9482033ed0fe0514778158bd57765c68e8e53525 100644 (file)
@@ -1,5 +1,4 @@
 /*
- *  linux/arch/i386/kernel/mca.c
  *  Written by Martin Kolinek, February 1996
  *
  * Changes:
index 0c1069b8d638031571618701a6f2e09044fd4b59..c044de310b691901c05453c046fe48796d0d5182 100644 (file)
@@ -11,8 +11,6 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * msr.c
- *
  * x86 MSR access device
  *
  * This device is accessed by lseek() to the appropriate register number
index 95d3fc203cf7176d89df480a17d64ea0f899d00e..f803ed0ed1c41ffea809a87ad70bb5e655346cfe 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/i386/nmi.c
- *
  *  NMI watchdog support on APIC systems
  *
  *  Started by Ingo Molnar <mingo@redhat.com>
index e60ac0da528393751dc466eb1fbbe623713d6f97..a576fd740062d3a7190f2ae5e5566c8baf2400c7 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86_64/nmi.c
- *
  *  NMI watchdog support on APIC systems
  *
  *  Started by Ingo Molnar <mingo@redhat.com>
index 84664710b78442d1bad1dd220c6de6f9d0033a63..097aeafce5fff14bf9c02874f5ca69f68aaa4f42 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/i386/kernel/process.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *
  *  Pentium III FXSR, SSE support
index 6f9dbbe65eef7c109e9d986dfca3bdda69072e9e..7352d4b377e6d0f411bf1a6cf9d26e9266afacaa 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86-64/kernel/process.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *
  *  Pentium III FXSR, SSE support
index 7c1b92522e95c1177bfb2fb70df497c9262a4856..0cecd7513c9788fe1e13bee6a0f35c43b9b164ea 100644 (file)
@@ -1,4 +1,3 @@
-/* ptrace.c */
 /* By Ross Biro 1/23/92 */
 /*
  * Pentium III FXSR, SSE support
index eea3702427b409d28c83c7e02a88c093a5c26232..c0cac42df3b6441010b7424788ad5e45b6a7119f 100644 (file)
@@ -1,4 +1,3 @@
-/* ptrace.c */
 /* By Ross Biro 1/23/92 */
 /*
  * Pentium III FXSR, SSE support
index b37ed226830aa78c081fcd2698e800ec83b44ea6..9e2269d00918c13948b03b92532498015e95460b 100644 (file)
@@ -1,7 +1,3 @@
-/*
- *  linux/arch/i386/kernel/reboot.c
- */
-
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/delay.h>
index 139eb03490f5d4f5de597874fad7479add8b86c1..8b30b26ad0698161276c2b87c4c64594887aa4ad 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/arch/i386/kernel/reboot_fixups.c
- *
  * This is a good place to put board specific reboot fixups.
  *
  * List of supported fixups:
index c7d3df23f589422b9753266f9de8617415650531..87bc159d29dfeaa8fdf0563a0e63128608c6fa1f 100644 (file)
@@ -1,8 +1,8 @@
-/* linux/arch/i386/kernel/scx200.c 
-
-   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
  National Semiconductor SCx200 support. */
+/*
+ *  Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+ *
+ *  National Semiconductor SCx200 support.
+ */
 
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -24,7 +24,7 @@ MODULE_DESCRIPTION("NatSemi SCx200 Driver");
 MODULE_LICENSE("GPL");
 
 unsigned scx200_gpio_base = 0;
-long scx200_gpio_shadow[2];
+unsigned long scx200_gpio_shadow[2];
 
 unsigned scx200_cb_base = 0;
 
index d474cd639bcb8ece22f706d285950926a50541ac..c8e1bc38d421e79b6957100b485dd017a367a4ae 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/i386/kernel/setup.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *
  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
index 32054bf5ba405674ba4b008ab0aa4b998158643a..b7da90e79c78d6660102a115ac38d7f6ea8b3831 100644 (file)
@@ -1,10 +1,5 @@
 /*
- *  linux/arch/x86-64/kernel/setup.c
- *
  *  Copyright (C) 1995  Linus Torvalds
- *
- *  Nov 2001 Dave Jones <davej@suse.de>
- *  Forked from i386 setup code.
  */
 
 /*
index c03570f7fe8e16482a5c348745f679db6ec79aec..d01d51fcce2a44b24ce98481b2a56c296df74836 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/i386/kernel/signal.c
- *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
index 739175b01e06ee9553760729c5b8e6dbd6bf89cb..683802bec419121944a9ec54fc68c013e86bb600 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86_64/kernel/signal.c
- *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
  *
index 57ccf7cb6b913315263c06548b6fc37ec6f6f380..720a7d1f8862be153b8e356e582c57727cbdaaef 100644 (file)
@@ -335,11 +335,6 @@ void __cpuinit start_secondary(void)
         */
        check_tsc_sync_target();
 
-       Dprintk("cpu %d: setting up apic clock\n", smp_processor_id());         
-       setup_secondary_APIC_clock();
-
-       Dprintk("cpu %d: enabling apic timer\n", smp_processor_id());
-
        if (nmi_watchdog == NMI_IO_APIC) {
                disable_8259A_irq(0);
                enable_NMI_through_LVT0(NULL);
@@ -374,6 +369,8 @@ void __cpuinit start_secondary(void)
 
        unlock_ipi_call_lock();
 
+       setup_secondary_APIC_clock();
+
        cpu_idle();
 }
 
index cb910911358407583ae5d2babf847f743f4a0882..413e527cdeb97394bbccb245d182338b463fcde4 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/x86_64/kernel/stacktrace.c
- *
  * Stack trace management functions
  *
  *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
index d0e01a3acf350222e63cf98889b5f1ee1aa1cca7..91c7acc8d999305f17c613798748d92a07b3b93e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/i386/kernel/summit.c - IBM Summit-Specific Code
+ * IBM Summit-Specific Code
  *
  * Written By: Matthew Dobson, IBM Corporation
  *
index 42147304de8855e8d0667249ba43f76bcb7efcde..f8bae9ba0324b44fb510f5a323c6986f08452bdd 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/arch/i386/kernel/sys_i386.c
- *
  * This file contains various random system calls that
  * have a non-standard calling sequence on the Linux/i386
  * platform.
index 4770b7a2052cf22774d09d06efd7dadf74d34df8..907942ee6e7660bcf3a404ebfeedd12a46c9c334 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * linux/arch/x86_64/kernel/sys_x86_64.c
- */
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/syscalls.h>
index 4eb2e408764f7bab8e81a7310616e3366cb1a29c..5a2d951e26088e59263e6dc3df5223e7e9db7ad3 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/arch/i386/kernel/sysenter.c
- *
  * (C) Copyright 2002 Linus Torvalds
  * Portions based on the vdso-randomization code from exec-shield:
  * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
index 56dadfc2f41c58cfd106cd622f19bdb090bc4321..8a322c96bc23fdb9465e3b59e7d035b0094e0132 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/i386/kernel/time.c
- *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
  *
  * This file contains the PC-specific time handling details:
index e0134d6c88da045ac23efe0f0cf439781a14ebaf..c821edc32216b88c674d2a704f105fdf063c1014 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86-64/kernel/time.c
- *
  *  "High Precision Event Timer" based timekeeping.
  *
  *  Copyright (c) 1991,1992,1995  Linus Torvalds
index 45782356a618d27432f2b8648ef914d4442771d8..c25f23eb397cceebe5e73afc62191815fce53455 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/i386/kernel/topology.c - Populate sysfs with topology information
+ * Populate sysfs with topology information
  *
  * Written by: Matthew Dobson, IBM Corporation
  * Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL
index 47b0bef335bd87e5b37c0ece5320e1192770e05b..05c27ecaf2a7162c489dbfae18212ae83bf13200 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/i386/traps.c
- *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
  *  Pentium III FXSR, SSE support
index 03888420775d03320f0cea3c40989e100fea3e7c..bc7116acf8fff425ca30fad69d339f550e79411b 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86-64/traps.c
- *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
  *
index 3ed0ae8c918ddfd95da7fa452157c80f2a84e1b0..b85ad754f70eeebd29d993dcebc28158ff0fc06a 100644 (file)
@@ -1,9 +1,3 @@
-/*
- * This code largely moved from arch/i386/kernel/timer/timer_tsc.c
- * which was originally moved from arch/i386/kernel/time.c.
- * See comments there for proper credits.
- */
-
 #include <linux/sched.h>
 #include <linux/clocksource.h>
 #include <linux/workqueue.h>
index 355f5f506c8133d2a97108ae211f52839199510b..9125efe66a06bf1b572dc3b136ef92452c03245e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/x86_64/kernel/tsc_sync.c: check TSC synchronization.
+ * check TSC synchronization.
  *
  * Copyright (C) 2006, Red Hat, Inc., Ingo Molnar
  *
index f2dcd1d27c0a6341bc76925f0c0f703960f0543d..157e4bedd3c5ae359bbc924f3d18c9ed6170bb23 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/kernel/vm86.c
- *
  *  Copyright (C) 1994  Linus Torvalds
  *
  *  29 dec 2001 - Fixed oopses caused by unchecked access to the vm86
index 06c34949bfdc9d09e90a219765aeb711c67e85a4..93847d848157b6bd8b14d3314d342fb889aca543 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86_64/kernel/vsyscall.c
- *
  *  Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
  *  Copyright 2003 Andi Kleen, SuSE Labs.
  *
index 4620efb12f132a59cd6a2fdf8758fa5e0e88f596..5196762b3b0ea3017cbb43e97f253c68055a1a7f 100644 (file)
@@ -117,6 +117,7 @@ ENTRY(__copy_user_nocache)
        popq %rbx
        CFI_ADJUST_CFA_OFFSET -8
        CFI_RESTORE rbx
+       sfence
        ret
        CFI_RESTORE_STATE
 
index 55e586d352d3c444d35fe7399726666ba94b9adf..6ea73f3de5677320c835234b70613413e746db35 100644 (file)
        thunk trace_hardirqs_on_thunk,trace_hardirqs_on
        thunk trace_hardirqs_off_thunk,trace_hardirqs_off
 #endif
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       thunk lockdep_sys_exit_thunk,lockdep_sys_exit
+#endif
        
        /* SAVE_ARGS below is used only for the .cfi directives it contains. */
        CFI_STARTPROC
index 27a391da9a987d595d69aa660e93b7fe0c59bb52..2d88f7c6d6ac901a3f2f2ffe2f64f680706b435a 100644 (file)
@@ -6,7 +6,7 @@
 #include <asm/numa.h>
 #include "pci.h"
 
-static int __devinit can_skip_ioresource_align(struct dmi_system_id *d)
+static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
 {
        pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
        printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);
index 13369b45563f759928f263187654cdee637c76ad..a736ef7bdee4726e3ef03c50b8fd1100c4b7b6ad 100644 (file)
@@ -362,7 +362,7 @@ static unsigned long write_video(const char *buffer, unsigned long count)
        int crt_out = -1;
        int tv_out = -1;
        u32 hci_result;
-       int video_out;
+       u32 video_out;
 
        /* scan expression.  Multiple expressions may be delimited with ;
         *
index 4672066167e35ab8e66065f9fdc1450f8e306c9c..33f5eb038773afa73b893c4d0f91825a24bf2f37 100644 (file)
@@ -272,6 +272,15 @@ config PATA_CS5535
 
          If unsure, say N.
 
+config PATA_CS5536
+       tristate "CS5536 PATA support (Experimental)"
+       depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+       help
+         This option enables support for the AMD CS5536
+         companion chip used with the Geode LX processor family.
+
+         If unsure, say N.
+
 config PATA_CYPRESS
        tristate "Cypress CY82C693 PATA support (Very Experimental)"
        depends on PCI && EXPERIMENTAL
index 2a63645003eb7eb7242c843fa05b72390413e8fa..6bdc307649e67fc66e12feb505017c29b5886395 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_PATA_CMD64X)     += pata_cmd64x.o
 obj-$(CONFIG_PATA_CS5520)      += pata_cs5520.o
 obj-$(CONFIG_PATA_CS5530)      += pata_cs5530.o
 obj-$(CONFIG_PATA_CS5535)      += pata_cs5535.o
+obj-$(CONFIG_PATA_CS5536)      += pata_cs5536.o
 obj-$(CONFIG_PATA_CYPRESS)     += pata_cypress.o
 obj-$(CONFIG_PATA_EFAR)                += pata_efar.o
 obj-$(CONFIG_PATA_HPT366)      += pata_hpt366.o
index e783e678acf5c33e03c93ad5361a407ded66c744..3c6f43e381f4e441ca891a05f4b7856fc4ac3b24 100644 (file)
@@ -130,6 +130,7 @@ enum {
        ich8_sata_ahci          = 9,
        piix_pata_mwdma         = 10,   /* PIIX3 MWDMA only */
        tolapai_sata_ahci       = 11,
+       ich9_2port_sata         = 12,
 
        /* constants for mapping table */
        P0                      = 0,  /* port 0 */
@@ -238,19 +239,19 @@ static const struct pci_device_id piix_pci_tbl[] = {
        /* SATA Controller 1 IDE (ICH8) */
        { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
        /* SATA Controller 2 IDE (ICH8) */
-       { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+       { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
        /* Mobile SATA Controller IDE (ICH8M) */
        { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
        /* SATA Controller IDE (ICH9) */
        { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
        /* SATA Controller IDE (ICH9) */
-       { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+       { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
        /* SATA Controller IDE (ICH9) */
-       { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+       { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
        /* SATA Controller IDE (ICH9M) */
-       { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+       { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
        /* SATA Controller IDE (ICH9M) */
-       { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+       { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
        /* SATA Controller IDE (ICH9M) */
        { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
        /* SATA Controller IDE (Tolapai) */
@@ -448,6 +449,18 @@ static const struct piix_map_db tolapai_map_db = {
        },
 };
 
+static const struct piix_map_db ich9_2port_map_db = {
+       .mask = 0x3,
+       .port_enable = 0x3,
+       .map = {
+               /* PM   PS   SM   SS       MAP */
+               {  P0,  NA,  P1,  NA }, /* 00b */
+               {  RV,  RV,  RV,  RV }, /* 01b */
+               {  RV,  RV,  RV,  RV }, /* 10b */
+               {  RV,  RV,  RV,  RV },
+       },
+};
+
 static const struct piix_map_db *piix_map_db_table[] = {
        [ich5_sata]             = &ich5_map_db,
        [ich6_sata]             = &ich6_map_db,
@@ -455,6 +468,7 @@ static const struct piix_map_db *piix_map_db_table[] = {
        [ich6m_sata_ahci]       = &ich6m_map_db,
        [ich8_sata_ahci]        = &ich8_map_db,
        [tolapai_sata_ahci]     = &tolapai_map_db,
+       [ich9_2port_sata]       = &ich9_2port_map_db,
 };
 
 static struct ata_port_info piix_port_info[] = {
@@ -570,6 +584,17 @@ static struct ata_port_info piix_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
+
+       [ich9_2port_sata] =
+       {
+               .sht            = &piix_sht,
+               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
+                                 PIIX_FLAG_AHCI,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &piix_sata_ops,
+       },
 };
 
 static struct pci_bits piix_enable_bits[] = {
@@ -1122,7 +1147,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
                                         const struct piix_map_db *map_db)
 {
        struct piix_host_priv *hpriv = pinfo[0].private_data;
-       const unsigned int *map;
+       const int *map;
        int i, invalid_map = 0;
        u8 map_value;
 
index b05384a8c3261d1eb2b3e9c9108f82cf0763dd25..68699b3e799843249086f7ae4f944b6dd893fe1a 100644 (file)
@@ -3984,6 +3984,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "ST9120822AS",        "3.CLF",        ATA_HORKAGE_NONCQ, },
        { "ST9160821AS",        "3.CLF",        ATA_HORKAGE_NONCQ, },
        { "ST9160821AS",        "3.ALD",        ATA_HORKAGE_NONCQ, },
+       { "ST9160821AS",        "3.CCD",        ATA_HORKAGE_NONCQ, },
        { "ST3160812AS",        "3.ADJ",        ATA_HORKAGE_NONCQ, },
        { "ST980813AS",         "3.ADB",        ATA_HORKAGE_NONCQ, },
        { "SAMSUNG HD401LJ",    "ZZ100-15",     ATA_HORKAGE_NONCQ, },
@@ -4013,8 +4014,14 @@ int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
        p = strchr(patt, wildchar);
        if (p && ((*(p + 1)) == 0))
                len = p - patt;
-       else
+       else {
                len = strlen(name);
+               if (!len) {
+                       if (!*patt)
+                               return 0;
+                       return -1;
+               }
+       }
 
        return strncmp(patt, name, len);
 }
index ea53e6a570b428e88cef5018c1318923c2d75667..d63c81ed084f7d016c70b55448804f0ad60d554e 100644 (file)
@@ -1363,6 +1363,7 @@ nothing_to_do:
 static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
+       struct ata_eh_info *ehi = &qc->dev->link->eh_info;
        struct scsi_cmnd *cmd = qc->scsicmd;
        u8 *cdb = cmd->cmnd;
        int need_sense = (qc->err_mask != 0);
@@ -1376,14 +1377,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
                case ATA_CMD_SET_FEATURES:
                        if ((qc->tf.feature == SETFEATURES_WC_ON) ||
                            (qc->tf.feature == SETFEATURES_WC_OFF)) {
-                               ap->link.eh_info.action |= ATA_EH_REVALIDATE;
+                               ehi->action |= ATA_EH_REVALIDATE;
                                ata_port_schedule_eh(ap);
                        }
                        break;
 
                case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
                case ATA_CMD_SET_MULTI: /* multi_count changed */
-                       ap->link.eh_info.action |= ATA_EH_REVALIDATE;
+                       ehi->action |= ATA_EH_REVALIDATE;
                        ata_port_schedule_eh(ap);
                        break;
                }
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
new file mode 100644 (file)
index 0000000..21405bf
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * pata_cs5536.c       - CS5536 PATA for new ATA layer
+ *                       (C) 2007 Martin K. Petersen <mkp@mkp.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307         USA
+ *
+ * Documentation:
+ *     Available from AMD web site.
+ *
+ * The IDE timing registers for the CS5536 live in the Geode Machine
+ * Specific Register file and not PCI config space.  Most BIOSes
+ * virtualize the PCI registers so the chip looks like a standard IDE
+ * controller. Unfortunately not all implementations get this right.
+ * In particular some have problems with unaligned accesses to the
+ * virtualized PCI registers.  This driver always does full dword
+ * writes to work around the issue.  Also, in case of a bad BIOS this
+ * driver can be loaded with the "msr=1" parameter which forces using
+ * the Machine Specific Registers to configure the device.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/libata.h>
+#include <scsi/scsi_host.h>
+#include <asm/msr.h>
+
+#define DRV_NAME       "pata_cs5536"
+#define DRV_VERSION    "0.0.5"
+
+enum {
+       CFG                     = 0,
+       DTC                     = 1,
+       CAST                    = 2,
+       ETC                     = 3,
+
+       MSR_IDE_BASE            = 0x51300000,
+       MSR_IDE_CFG             = (MSR_IDE_BASE + 0x10),
+       MSR_IDE_DTC             = (MSR_IDE_BASE + 0x12),
+       MSR_IDE_CAST            = (MSR_IDE_BASE + 0x13),
+       MSR_IDE_ETC             = (MSR_IDE_BASE + 0x14),
+
+       PCI_IDE_CFG             = 0x40,
+       PCI_IDE_DTC             = 0x48,
+       PCI_IDE_CAST            = 0x4c,
+       PCI_IDE_ETC             = 0x50,
+
+       IDE_CFG_CHANEN          = 0x2,
+       IDE_CFG_CABLE           = 0x10000,
+
+       IDE_D0_SHIFT            = 24,
+       IDE_D1_SHIFT            = 16,
+       IDE_DRV_MASK            = 0xff,
+
+       IDE_CAST_D0_SHIFT       = 6,
+       IDE_CAST_D1_SHIFT       = 4,
+       IDE_CAST_DRV_MASK       = 0x3,
+       IDE_CAST_CMD_MASK       = 0xff,
+       IDE_CAST_CMD_SHIFT      = 24,
+
+       IDE_ETC_NODMA           = 0x03,
+};
+
+static int use_msr;
+
+static const u32 msr_reg[4] = {
+       MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC,
+};
+
+static const u8 pci_reg[4] = {
+       PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC,
+};
+
+static inline int cs5536_read(struct pci_dev *pdev, int reg, int *val)
+{
+       if (unlikely(use_msr)) {
+               u32 dummy;
+
+               rdmsr(msr_reg[reg], *val, dummy);
+               return 0;
+       }
+
+       return pci_read_config_dword(pdev, pci_reg[reg], val);
+}
+
+static inline int cs5536_write(struct pci_dev *pdev, int reg, int val)
+{
+       if (unlikely(use_msr)) {
+               wrmsr(msr_reg[reg], val, 0);
+               return 0;
+       }
+
+       return pci_write_config_dword(pdev, pci_reg[reg], val);
+}
+
+/**
+ *     cs5536_cable_detect     -       detect cable type
+ *     @ap: Port to detect on
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Perform cable detection for ATA66 capable cable. Return a libata
+ *     cable type.
+ */
+
+static int cs5536_cable_detect(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u32 cfg;
+
+       cs5536_read(pdev, CFG, &cfg);
+
+       if (cfg & (IDE_CFG_CABLE << ap->port_no))
+               return ATA_CBL_PATA80;
+       else
+               return ATA_CBL_PATA40;
+}
+
+/**
+ *     cs5536_set_piomode              -       PIO setup
+ *     @ap: ATA interface
+ *     @adev: device on the interface
+ */
+
+static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       static const u8 drv_timings[5] = {
+               0x98, 0x55, 0x32, 0x21, 0x20,
+       };
+
+       static const u8 addr_timings[5] = {
+               0x2, 0x1, 0x0, 0x0, 0x0,
+       };
+
+       static const u8 cmd_timings[5] = {
+               0x99, 0x92, 0x90, 0x22, 0x20,
+       };
+
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       struct ata_device *pair = ata_dev_pair(adev);
+       int mode = adev->pio_mode - XFER_PIO_0;
+       int cmdmode = mode;
+       int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+       int cshift = ap->port_no ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
+       u32 dtc, cast, etc;
+
+       if (pair)
+               cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);
+
+       cs5536_read(pdev, DTC, &dtc);
+       cs5536_read(pdev, CAST, &cast);
+       cs5536_read(pdev, ETC, &etc);
+
+       dtc &= ~(IDE_DRV_MASK << dshift);
+       dtc |= drv_timings[mode] << dshift;
+
+       cast &= ~(IDE_CAST_DRV_MASK << cshift);
+       cast |= addr_timings[mode] << cshift;
+
+       cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
+       cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;
+
+       etc &= ~(IDE_DRV_MASK << dshift);
+       etc |= IDE_ETC_NODMA << dshift;
+
+       cs5536_write(pdev, DTC, dtc);
+       cs5536_write(pdev, CAST, cast);
+       cs5536_write(pdev, ETC, etc);
+}
+
+/**
+ *     cs5536_set_dmamode              -       DMA timing setup
+ *     @ap: ATA interface
+ *     @adev: Device being configured
+ *
+ */
+
+static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+       static const u8 udma_timings[6] = {
+               0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
+       };
+
+       static const u8 mwdma_timings[3] = {
+               0x67, 0x21, 0x20,
+       };
+
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u32 dtc, etc;
+       int mode = adev->dma_mode;
+       int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+
+       if (mode >= XFER_UDMA_0) {
+               cs5536_read(pdev, ETC, &etc);
+
+               etc &= ~(IDE_DRV_MASK << dshift);
+               etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
+
+               cs5536_write(pdev, ETC, etc);
+       } else { /* MWDMA */
+               cs5536_read(pdev, DTC, &dtc);
+
+               dtc &= ~(IDE_DRV_MASK << dshift);
+               dtc |= mwdma_timings[mode] << dshift;
+
+               cs5536_write(pdev, DTC, dtc);
+       }
+}
+
+static struct scsi_host_template cs5536_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .ioctl                  = ata_scsi_ioctl,
+       .queuecommand           = ata_scsi_queuecmd,
+       .can_queue              = ATA_DEF_QUEUE,
+       .this_id                = ATA_SHT_THIS_ID,
+       .sg_tablesize           = LIBATA_MAX_PRD,
+       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
+       .emulated               = ATA_SHT_EMULATED,
+       .use_clustering         = ATA_SHT_USE_CLUSTERING,
+       .proc_name              = DRV_NAME,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
+       .slave_configure        = ata_scsi_slave_config,
+       .slave_destroy          = ata_scsi_slave_destroy,
+       .bios_param             = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5536_port_ops = {
+       .port_disable           = ata_port_disable,
+       .set_piomode            = cs5536_set_piomode,
+       .set_dmamode            = cs5536_set_dmamode,
+       .mode_filter            = ata_pci_default_filter,
+
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .exec_command           = ata_exec_command,
+       .dev_select             = ata_std_dev_select,
+
+       .freeze                 = ata_bmdma_freeze,
+       .thaw                   = ata_bmdma_thaw,
+       .error_handler          = ata_bmdma_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = cs5536_cable_detect,
+
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
+       .bmdma_stop             = ata_bmdma_stop,
+       .bmdma_status           = ata_bmdma_status,
+
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+
+       .data_xfer              = ata_data_xfer,
+
+       .irq_handler            = ata_interrupt,
+       .irq_clear              = ata_bmdma_irq_clear,
+       .irq_on                 = ata_irq_on,
+       .irq_ack                = ata_irq_ack,
+
+       .port_start             = ata_port_start,
+};
+
+/**
+ *     cs5536_init_one
+ *     @dev: PCI device
+ *     @id: Entry in match table
+ *
+ */
+
+static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       static const struct ata_port_info info = {
+               .sht = &cs5536_sht,
+               .flags = ATA_FLAG_SLAVE_POSS,
+               .pio_mask = 0x1f,
+               .mwdma_mask = 0x07,
+               .udma_mask = ATA_UDMA5,
+               .port_ops = &cs5536_port_ops,
+       };
+
+       const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+       u32 cfg;
+
+       if (use_msr)
+               printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n");
+
+       cs5536_read(dev, CFG, &cfg);
+
+       if ((cfg & IDE_CFG_CHANEN) == 0) {
+               printk(KERN_ERR DRV_NAME ": disabled by BIOS\n");
+               return -ENODEV;
+       }
+
+       return ata_pci_init_one(dev, ppi);
+}
+
+static const struct pci_device_id cs5536[] = {
+       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_IDE), },
+       { },
+};
+
+static struct pci_driver cs5536_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = cs5536,
+       .probe          = cs5536_init_one,
+       .remove         = ata_pci_remove_one,
+#ifdef CONFIG_PM
+       .suspend        = ata_pci_device_suspend,
+       .resume         = ata_pci_device_resume,
+#endif
+};
+
+static int __init cs5536_init(void)
+{
+       return pci_register_driver(&cs5536_pci_driver);
+}
+
+static void __exit cs5536_exit(void)
+{
+       pci_unregister_driver(&cs5536_pci_driver);
+}
+
+MODULE_AUTHOR("Martin K. Petersen");
+MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cs5536);
+MODULE_VERSION(DRV_VERSION);
+module_param_named(msr, use_msr, int, 0644);
+MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
+
+module_init(cs5536_init);
+module_exit(cs5536_exit);
index 412140f02853e687456c58969983814c009518aa..50c56e2814c1e0c6a777ed7ef80534d8e9012d73 100644 (file)
@@ -308,7 +308,6 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
        struct ata_host *host;
        struct ata_port *ap;
        struct ata_ioports *aio;
-       int rc;
 
        host = ata_host_alloc(dev, 1);
        if (!host)
index 782ff4ada9d1f1c90299ff127e336a5ac911e749..5db2013230b31c048798f242a4c91a66f36d5f50 100644 (file)
@@ -353,6 +353,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
 
 static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_FUNC_ID(4),
+       PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
        PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
        PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),        /* I-O Data CFA */
        PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),        /* Mitsubishi CFA */
@@ -378,6 +379,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
        PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
        PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+       PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
        PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
        PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
        PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
index 2eb75cd74a961cb70bf2281598b417f17f47b521..4dc2e73298fdeae67bfdbcc81a8031ed5a9b97bc 100644 (file)
@@ -279,7 +279,7 @@ static struct ata_port_operations sil680_port_ops = {
  *     Returns the final clock settings.
  */
 
-static u8 sil680_init_chip(struct pci_dev *pdev)
+static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
 {
        u32 class_rev   = 0;
        u8 tmpbyte      = 0;
@@ -297,6 +297,8 @@ static u8 sil680_init_chip(struct pci_dev *pdev)
        dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n",
                tmpbyte & 1, tmpbyte & 0x30);
 
+       *try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
+
        switch(tmpbyte & 0x30) {
                case 0x00:
                        /* 133 clock attempt to force it on */
@@ -361,25 +363,76 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
        static int printed_version;
+       struct ata_host *host;
+       void __iomem *mmio_base;
+       int rc, try_mmio;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
-       switch(sil680_init_chip(pdev))
-       {
+       switch (sil680_init_chip(pdev, &try_mmio)) {
                case 0:
                        ppi[0] = &info_slow;
                        break;
                case 0x30:
                        return -ENODEV;
        }
+
+       if (!try_mmio)
+               goto use_ioports;
+
+       /* Try to acquire MMIO resources and fallback to PIO if
+        * that fails
+        */
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+       rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME);
+       if (rc)
+               goto use_ioports;
+
+       /* Allocate host and set it up */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+       if (!host)
+               return -ENOMEM;
+       host->iomap = pcim_iomap_table(pdev);
+
+       /* Setup DMA masks */
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+       pci_set_master(pdev);
+
+       /* Get MMIO base and initialize port addresses */
+       mmio_base = host->iomap[SIL680_MMIO_BAR];
+       host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x00;
+       host->ports[0]->ioaddr.cmd_addr = mmio_base + 0x80;
+       host->ports[0]->ioaddr.ctl_addr = mmio_base + 0x8a;
+       host->ports[0]->ioaddr.altstatus_addr = mmio_base + 0x8a;
+       ata_std_ports(&host->ports[0]->ioaddr);
+       host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x08;
+       host->ports[1]->ioaddr.cmd_addr = mmio_base + 0xc0;
+       host->ports[1]->ioaddr.ctl_addr = mmio_base + 0xca;
+       host->ports[1]->ioaddr.altstatus_addr = mmio_base + 0xca;
+       ata_std_ports(&host->ports[1]->ioaddr);
+
+       /* Register & activate */
+       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+                                &sil680_sht);
+
+use_ioports:
        return ata_pci_init_one(pdev, ppi);
 }
 
 #ifdef CONFIG_PM
 static int sil680_reinit_one(struct pci_dev *pdev)
 {
-       sil680_init_chip(pdev);
+       int try_mmio;
+
+       sil680_init_chip(pdev, &try_mmio);
        return ata_pci_device_resume(pdev);
 }
 #endif
index 40557fe2ffdf98c74a8822a754d063f7ab0c4b7a..240a8920d0bda4384090bcea86a7ffdfc763c459 100644 (file)
@@ -169,6 +169,35 @@ enum {
        NV_ADMA_PORT_REGISTER_MODE      = (1 << 0),
        NV_ADMA_ATAPI_SETUP_COMPLETE    = (1 << 1),
 
+       /* MCP55 reg offset */
+       NV_CTL_MCP55                    = 0x400,
+       NV_INT_STATUS_MCP55             = 0x440,
+       NV_INT_ENABLE_MCP55             = 0x444,
+       NV_NCQ_REG_MCP55                = 0x448,
+
+       /* MCP55 */
+       NV_INT_ALL_MCP55                = 0xffff,
+       NV_INT_PORT_SHIFT_MCP55         = 16,   /* each port occupies 16 bits */
+       NV_INT_MASK_MCP55               = NV_INT_ALL_MCP55 & 0xfffd,
+
+       /* SWNCQ ENABLE BITS*/
+       NV_CTL_PRI_SWNCQ                = 0x02,
+       NV_CTL_SEC_SWNCQ                = 0x04,
+
+       /* SW NCQ status bits*/
+       NV_SWNCQ_IRQ_DEV                = (1 << 0),
+       NV_SWNCQ_IRQ_PM                 = (1 << 1),
+       NV_SWNCQ_IRQ_ADDED              = (1 << 2),
+       NV_SWNCQ_IRQ_REMOVED            = (1 << 3),
+
+       NV_SWNCQ_IRQ_BACKOUT            = (1 << 4),
+       NV_SWNCQ_IRQ_SDBFIS             = (1 << 5),
+       NV_SWNCQ_IRQ_DHREGFIS           = (1 << 6),
+       NV_SWNCQ_IRQ_DMASETUP           = (1 << 7),
+
+       NV_SWNCQ_IRQ_HOTPLUG            = NV_SWNCQ_IRQ_ADDED |
+                                         NV_SWNCQ_IRQ_REMOVED,
+
 };
 
 /* ADMA Physical Region Descriptor - one SG segment */
@@ -226,6 +255,42 @@ struct nv_host_priv {
        unsigned long           type;
 };
 
+struct defer_queue {
+       u32             defer_bits;
+       unsigned int    head;
+       unsigned int    tail;
+       unsigned int    tag[ATA_MAX_QUEUE];
+};
+
+enum ncq_saw_flag_list {
+       ncq_saw_d2h     = (1U << 0),
+       ncq_saw_dmas    = (1U << 1),
+       ncq_saw_sdb     = (1U << 2),
+       ncq_saw_backout = (1U << 3),
+};
+
+struct nv_swncq_port_priv {
+       struct ata_prd  *prd;    /* our SG list */
+       dma_addr_t      prd_dma; /* and its DMA mapping */
+       void __iomem    *sactive_block;
+       void __iomem    *irq_block;
+       void __iomem    *tag_block;
+       u32             qc_active;
+
+       unsigned int    last_issue_tag;
+
+       /* fifo circular queue to store deferral command */
+       struct defer_queue defer_queue;
+
+       /* for NCQ interrupt analysis */
+       u32             dhfis_bits;
+       u32             dmafis_bits;
+       u32             sdbfis_bits;
+
+       unsigned int    ncq_flags;
+};
+
+
 #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
 
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -263,13 +328,29 @@ static void nv_adma_host_stop(struct ata_host *host);
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
 static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 
+static void nv_mcp55_thaw(struct ata_port *ap);
+static void nv_mcp55_freeze(struct ata_port *ap);
+static void nv_swncq_error_handler(struct ata_port *ap);
+static int nv_swncq_slave_config(struct scsi_device *sdev);
+static int nv_swncq_port_start(struct ata_port *ap);
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc);
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc);
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc);
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis);
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance);
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int nv_swncq_port_resume(struct ata_port *ap);
+#endif
+
 enum nv_host_type
 {
        GENERIC,
        NFORCE2,
        NFORCE3 = NFORCE2,      /* NF2 == NF3 as far as sata_nv is concerned */
        CK804,
-       ADMA
+       ADMA,
+       SWNCQ,
 };
 
 static const struct pci_device_id nv_pci_tbl[] = {
@@ -280,13 +361,13 @@ static const struct pci_device_id nv_pci_tbl[] = {
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
        { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
-       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), SWNCQ },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), SWNCQ },
+       { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), SWNCQ },
 
        { } /* terminate list */
 };
@@ -339,6 +420,25 @@ static struct scsi_host_template nv_adma_sht = {
        .bios_param             = ata_std_bios_param,
 };
 
+static struct scsi_host_template nv_swncq_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .ioctl                  = ata_scsi_ioctl,
+       .queuecommand           = ata_scsi_queuecmd,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .can_queue              = ATA_MAX_QUEUE,
+       .this_id                = ATA_SHT_THIS_ID,
+       .sg_tablesize           = LIBATA_MAX_PRD,
+       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
+       .emulated               = ATA_SHT_EMULATED,
+       .use_clustering         = ATA_SHT_USE_CLUSTERING,
+       .proc_name              = DRV_NAME,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
+       .slave_configure        = nv_swncq_slave_config,
+       .slave_destroy          = ata_scsi_slave_destroy,
+       .bios_param             = ata_std_bios_param,
+};
+
 static const struct ata_port_operations nv_generic_ops = {
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -444,6 +544,35 @@ static const struct ata_port_operations nv_adma_ops = {
        .host_stop              = nv_adma_host_stop,
 };
 
+static const struct ata_port_operations nv_swncq_ops = {
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .exec_command           = ata_exec_command,
+       .check_status           = ata_check_status,
+       .dev_select             = ata_std_dev_select,
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
+       .bmdma_stop             = ata_bmdma_stop,
+       .bmdma_status           = ata_bmdma_status,
+       .qc_defer               = ata_std_qc_defer,
+       .qc_prep                = nv_swncq_qc_prep,
+       .qc_issue               = nv_swncq_qc_issue,
+       .freeze                 = nv_mcp55_freeze,
+       .thaw                   = nv_mcp55_thaw,
+       .error_handler          = nv_swncq_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .data_xfer              = ata_data_xfer,
+       .irq_clear              = ata_bmdma_irq_clear,
+       .irq_on                 = ata_irq_on,
+       .scr_read               = nv_scr_read,
+       .scr_write              = nv_scr_write,
+#ifdef CONFIG_PM
+       .port_suspend           = nv_swncq_port_suspend,
+       .port_resume            = nv_swncq_port_resume,
+#endif
+       .port_start             = nv_swncq_port_start,
+};
+
 static const struct ata_port_info nv_port_info[] = {
        /* generic */
        {
@@ -490,6 +619,18 @@ static const struct ata_port_info nv_port_info[] = {
                .port_ops       = &nv_adma_ops,
                .irq_handler    = nv_adma_interrupt,
        },
+       /* SWNCQ */
+       {
+               .sht            = &nv_swncq_sht,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_NCQ,
+               .link_flags     = ATA_LFLAG_HRST_TO_RESUME,
+               .pio_mask       = NV_PIO_MASK,
+               .mwdma_mask     = NV_MWDMA_MASK,
+               .udma_mask      = NV_UDMA_MASK,
+               .port_ops       = &nv_swncq_ops,
+               .irq_handler    = nv_swncq_interrupt,
+       },
 };
 
 MODULE_AUTHOR("NVIDIA");
@@ -499,6 +640,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
 static int adma_enabled = 1;
+static int swncq_enabled;
 
 static void nv_adma_register_mode(struct ata_port *ap)
 {
@@ -1452,6 +1594,34 @@ static void nv_ck804_thaw(struct ata_port *ap)
        writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
 }
 
+static void nv_mcp55_freeze(struct ata_port *ap)
+{
+       void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+       int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+       u32 mask;
+
+       writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+       mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+       mask &= ~(NV_INT_ALL_MCP55 << shift);
+       writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+       ata_bmdma_freeze(ap);
+}
+
+static void nv_mcp55_thaw(struct ata_port *ap)
+{
+       void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+       int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+       u32 mask;
+
+       writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+       mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+       mask |= (NV_INT_MASK_MCP55 << shift);
+       writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+       ata_bmdma_thaw(ap);
+}
+
 static int nv_hardreset(struct ata_link *link, unsigned int *class,
                        unsigned long deadline)
 {
@@ -1525,6 +1695,663 @@ static void nv_adma_error_handler(struct ata_port *ap)
                           nv_hardreset, ata_std_postreset);
 }
 
+static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct defer_queue *dq = &pp->defer_queue;
+
+       /* queue is full */
+       WARN_ON(dq->tail - dq->head == ATA_MAX_QUEUE);
+       dq->defer_bits |= (1 << qc->tag);
+       dq->tag[dq->tail++ & (ATA_MAX_QUEUE - 1)] = qc->tag;
+}
+
+static struct ata_queued_cmd *nv_swncq_qc_from_dq(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct defer_queue *dq = &pp->defer_queue;
+       unsigned int tag;
+
+       if (dq->head == dq->tail)       /* null queue */
+               return NULL;
+
+       tag = dq->tag[dq->head & (ATA_MAX_QUEUE - 1)];
+       dq->tag[dq->head++ & (ATA_MAX_QUEUE - 1)] = ATA_TAG_POISON;
+       WARN_ON(!(dq->defer_bits & (1 << tag)));
+       dq->defer_bits &= ~(1 << tag);
+
+       return ata_qc_from_tag(ap, tag);
+}
+
+static void nv_swncq_fis_reinit(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       pp->dhfis_bits = 0;
+       pp->dmafis_bits = 0;
+       pp->sdbfis_bits = 0;
+       pp->ncq_flags = 0;
+}
+
+static void nv_swncq_pp_reinit(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct defer_queue *dq = &pp->defer_queue;
+
+       dq->head = 0;
+       dq->tail = 0;
+       dq->defer_bits = 0;
+       pp->qc_active = 0;
+       pp->last_issue_tag = ATA_TAG_POISON;
+       nv_swncq_fis_reinit(ap);
+}
+
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       writew(fis, pp->irq_block);
+}
+
+static void __ata_bmdma_stop(struct ata_port *ap)
+{
+       struct ata_queued_cmd qc;
+
+       qc.ap = ap;
+       ata_bmdma_stop(&qc);
+}
+
+static void nv_swncq_ncq_stop(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       unsigned int i;
+       u32 sactive;
+       u32 done_mask;
+
+       ata_port_printk(ap, KERN_ERR,
+                       "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n",
+                       ap->qc_active, ap->link.sactive);
+       ata_port_printk(ap, KERN_ERR,
+               "SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n  "
+               "dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n",
+               pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag,
+               pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits);
+
+       ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n",
+                       ap->ops->check_status(ap),
+                       ioread8(ap->ioaddr.error_addr));
+
+       sactive = readl(pp->sactive_block);
+       done_mask = pp->qc_active ^ sactive;
+
+       ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n");
+       for (i = 0; i < ATA_MAX_QUEUE; i++) {
+               u8 err = 0;
+               if (pp->qc_active & (1 << i))
+                       err = 0;
+               else if (done_mask & (1 << i))
+                       err = 1;
+               else
+                       continue;
+
+               ata_port_printk(ap, KERN_ERR,
+                               "tag 0x%x: %01x %01x %01x %01x %s\n", i,
+                               (pp->dhfis_bits >> i) & 0x1,
+                               (pp->dmafis_bits >> i) & 0x1,
+                               (pp->sdbfis_bits >> i) & 0x1,
+                               (sactive >> i) & 0x1,
+                               (err ? "error! tag doesn't exit" : " "));
+       }
+
+       nv_swncq_pp_reinit(ap);
+       ap->ops->irq_clear(ap);
+       __ata_bmdma_stop(ap);
+       nv_swncq_irq_clear(ap, 0xffff);
+}
+
+static void nv_swncq_error_handler(struct ata_port *ap)
+{
+       struct ata_eh_context *ehc = &ap->link.eh_context;
+
+       if (ap->link.sactive) {
+               nv_swncq_ncq_stop(ap);
+               ehc->i.action |= ATA_EH_HARDRESET;
+       }
+
+       ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+                          nv_hardreset, ata_std_postreset);
+}
+
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       u32 tmp;
+
+       /* clear irq */
+       writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+       /* disable irq */
+       writel(0, mmio + NV_INT_ENABLE_MCP55);
+
+       /* disable swncq */
+       tmp = readl(mmio + NV_CTL_MCP55);
+       tmp &= ~(NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ);
+       writel(tmp, mmio + NV_CTL_MCP55);
+
+       return 0;
+}
+
+static int nv_swncq_port_resume(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       u32 tmp;
+
+       /* clear irq */
+       writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+       /* enable irq */
+       writel(0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+       /* enable swncq */
+       tmp = readl(mmio + NV_CTL_MCP55);
+       writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+       return 0;
+}
+#endif
+
+static void nv_swncq_host_init(struct ata_host *host)
+{
+       u32 tmp;
+       void __iomem *mmio = host->iomap[NV_MMIO_BAR];
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       u8 regval;
+
+       /* disable  ECO 398 */
+       pci_read_config_byte(pdev, 0x7f, &regval);
+       regval &= ~(1 << 7);
+       pci_write_config_byte(pdev, 0x7f, regval);
+
+       /* enable swncq */
+       tmp = readl(mmio + NV_CTL_MCP55);
+       VPRINTK("HOST_CTL:0x%X\n", tmp);
+       writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+       /* enable irq intr */
+       tmp = readl(mmio + NV_INT_ENABLE_MCP55);
+       VPRINTK("HOST_ENABLE:0x%X\n", tmp);
+       writel(tmp | 0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+       /*  clear port irq */
+       writel(~0x0, mmio + NV_INT_STATUS_MCP55);
+}
+
+static int nv_swncq_slave_config(struct scsi_device *sdev)
+{
+       struct ata_port *ap = ata_shost_to_port(sdev->host);
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       struct ata_device *dev;
+       int rc;
+       u8 rev;
+       u8 check_maxtor = 0;
+       unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+       rc = ata_scsi_slave_config(sdev);
+       if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun)
+               /* Not a proper libata device, ignore */
+               return rc;
+
+       dev = &ap->link.device[sdev->id];
+       if (!(ap->flags & ATA_FLAG_NCQ) || dev->class == ATA_DEV_ATAPI)
+               return rc;
+
+       /* if MCP51 and Maxtor, then disable ncq */
+       if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA ||
+               pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2)
+               check_maxtor = 1;
+
+       /* if MCP55 and rev <= a2 and Maxtor, then disable ncq */
+       if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA ||
+               pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2) {
+               pci_read_config_byte(pdev, 0x8, &rev);
+               if (rev <= 0xa2)
+                       check_maxtor = 1;
+       }
+
+       if (!check_maxtor)
+               return rc;
+
+       ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+
+       if (strncmp(model_num, "Maxtor", 6) == 0) {
+               ata_scsi_change_queue_depth(sdev, 1);
+               ata_dev_printk(dev, KERN_NOTICE,
+                       "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth);
+       }
+
+       return rc;
+}
+
+static int nv_swncq_port_start(struct ata_port *ap)
+{
+       struct device *dev = ap->host->dev;
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       struct nv_swncq_port_priv *pp;
+       int rc;
+
+       rc = ata_port_start(ap);
+       if (rc)
+               return rc;
+
+       pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+       if (!pp)
+               return -ENOMEM;
+
+       pp->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE,
+                                     &pp->prd_dma, GFP_KERNEL);
+       if (!pp->prd)
+               return -ENOMEM;
+       memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE);
+
+       ap->private_data = pp;
+       pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE;
+       pp->irq_block = mmio + NV_INT_STATUS_MCP55 + ap->port_no * 2;
+       pp->tag_block = mmio + NV_NCQ_REG_MCP55 + ap->port_no * 2;
+
+       return 0;
+}
+
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc)
+{
+       if (qc->tf.protocol != ATA_PROT_NCQ) {
+               ata_qc_prep(qc);
+               return;
+       }
+
+       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+               return;
+
+       nv_swncq_fill_sg(qc);
+}
+
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct scatterlist *sg;
+       unsigned int idx;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct ata_prd *prd;
+
+       WARN_ON(qc->__sg == NULL);
+       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+
+       prd = pp->prd + ATA_MAX_PRD * qc->tag;
+
+       idx = 0;
+       ata_for_each_sg(sg, qc) {
+               u32 addr, offset;
+               u32 sg_len, len;
+
+               addr = (u32)sg_dma_address(sg);
+               sg_len = sg_dma_len(sg);
+
+               while (sg_len) {
+                       offset = addr & 0xffff;
+                       len = sg_len;
+                       if ((offset + sg_len) > 0x10000)
+                               len = 0x10000 - offset;
+
+                       prd[idx].addr = cpu_to_le32(addr);
+                       prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+
+                       idx++;
+                       sg_len -= len;
+                       addr += len;
+               }
+       }
+
+       if (idx)
+               prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,
+                                         struct ata_queued_cmd *qc)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       if (qc == NULL)
+               return 0;
+
+       DPRINTK("Enter\n");
+
+       writel((1 << qc->tag), pp->sactive_block);
+       pp->last_issue_tag = qc->tag;
+       pp->dhfis_bits &= ~(1 << qc->tag);
+       pp->dmafis_bits &= ~(1 << qc->tag);
+       pp->qc_active |= (0x1 << qc->tag);
+
+       ap->ops->tf_load(ap, &qc->tf);   /* load tf registers */
+       ap->ops->exec_command(ap, &qc->tf);
+
+       DPRINTK("Issued tag %u\n", qc->tag);
+
+       return 0;
+}
+
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       if (qc->tf.protocol != ATA_PROT_NCQ)
+               return ata_qc_issue_prot(qc);
+
+       DPRINTK("Enter\n");
+
+       if (!pp->qc_active)
+               nv_swncq_issue_atacmd(ap, qc);
+       else
+               nv_swncq_qc_to_dq(ap, qc);      /* add qc to defer queue */
+
+       return 0;
+}
+
+static void nv_swncq_hotplug(struct ata_port *ap, u32 fis)
+{
+       u32 serror;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+
+       ata_ehi_clear_desc(ehi);
+
+       /* AHCI needs SError cleared; otherwise, it might lock up */
+       sata_scr_read(&ap->link, SCR_ERROR, &serror);
+       sata_scr_write(&ap->link, SCR_ERROR, serror);
+
+       /* analyze @irq_stat */
+       if (fis & NV_SWNCQ_IRQ_ADDED)
+               ata_ehi_push_desc(ehi, "hot plug");
+       else if (fis & NV_SWNCQ_IRQ_REMOVED)
+               ata_ehi_push_desc(ehi, "hot unplug");
+
+       ata_ehi_hotplugged(ehi);
+
+       /* okay, let's hand over to EH */
+       ehi->serror |= serror;
+
+       ata_port_freeze(ap);
+}
+
+static int nv_swncq_sdbfis(struct ata_port *ap)
+{
+       struct ata_queued_cmd *qc;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       u32 sactive;
+       int nr_done = 0;
+       u32 done_mask;
+       int i;
+       u8 host_stat;
+       u8 lack_dhfis = 0;
+
+       host_stat = ap->ops->bmdma_status(ap);
+       if (unlikely(host_stat & ATA_DMA_ERR)) {
+               /* error when transfering data to/from memory */
+               ata_ehi_clear_desc(ehi);
+               ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+               ehi->err_mask |= AC_ERR_HOST_BUS;
+               ehi->action |= ATA_EH_SOFTRESET;
+               return -EINVAL;
+       }
+
+       ap->ops->irq_clear(ap);
+       __ata_bmdma_stop(ap);
+
+       sactive = readl(pp->sactive_block);
+       done_mask = pp->qc_active ^ sactive;
+
+       if (unlikely(done_mask & sactive)) {
+               ata_ehi_clear_desc(ehi);
+               ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition"
+                                 "(%08x->%08x)", pp->qc_active, sactive);
+               ehi->err_mask |= AC_ERR_HSM;
+               ehi->action |= ATA_EH_HARDRESET;
+               return -EINVAL;
+       }
+       for (i = 0; i < ATA_MAX_QUEUE; i++) {
+               if (!(done_mask & (1 << i)))
+                       continue;
+
+               qc = ata_qc_from_tag(ap, i);
+               if (qc) {
+                       ata_qc_complete(qc);
+                       pp->qc_active &= ~(1 << i);
+                       pp->dhfis_bits &= ~(1 << i);
+                       pp->dmafis_bits &= ~(1 << i);
+                       pp->sdbfis_bits |= (1 << i);
+                       nr_done++;
+               }
+       }
+
+       if (!ap->qc_active) {
+               DPRINTK("over\n");
+               nv_swncq_pp_reinit(ap);
+               return nr_done;
+       }
+
+       if (pp->qc_active & pp->dhfis_bits)
+               return nr_done;
+
+       if ((pp->ncq_flags & ncq_saw_backout) ||
+           (pp->qc_active ^ pp->dhfis_bits))
+               /* if the controller cann't get a device to host register FIS,
+                * The driver needs to reissue the new command.
+                */
+               lack_dhfis = 1;
+
+       DPRINTK("id 0x%x QC: qc_active 0x%x,"
+               "SWNCQ:qc_active 0x%X defer_bits %X "
+               "dhfis 0x%X dmafis 0x%X last_issue_tag %x\n",
+               ap->print_id, ap->qc_active, pp->qc_active,
+               pp->defer_queue.defer_bits, pp->dhfis_bits,
+               pp->dmafis_bits, pp->last_issue_tag);
+
+       nv_swncq_fis_reinit(ap);
+
+       if (lack_dhfis) {
+               qc = ata_qc_from_tag(ap, pp->last_issue_tag);
+               nv_swncq_issue_atacmd(ap, qc);
+               return nr_done;
+       }
+
+       if (pp->defer_queue.defer_bits) {
+               /* send deferral queue command */
+               qc = nv_swncq_qc_from_dq(ap);
+               WARN_ON(qc == NULL);
+               nv_swncq_issue_atacmd(ap, qc);
+       }
+
+       return nr_done;
+}
+
+static inline u32 nv_swncq_tag(struct ata_port *ap)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       u32 tag;
+
+       tag = readb(pp->tag_block) >> 2;
+       return (tag & 0x1f);
+}
+
+static int nv_swncq_dmafis(struct ata_port *ap)
+{
+       struct ata_queued_cmd *qc;
+       unsigned int rw;
+       u8 dmactl;
+       u32 tag;
+       struct nv_swncq_port_priv *pp = ap->private_data;
+
+       __ata_bmdma_stop(ap);
+       tag = nv_swncq_tag(ap);
+
+       DPRINTK("dma setup tag 0x%x\n", tag);
+       qc = ata_qc_from_tag(ap, tag);
+
+       if (unlikely(!qc))
+               return 0;
+
+       rw = qc->tf.flags & ATA_TFLAG_WRITE;
+
+       /* load PRD table addr. */
+       iowrite32(pp->prd_dma + ATA_PRD_TBL_SZ * qc->tag,
+                 ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+       /* specify data direction, triple-check start bit is clear */
+       dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+       dmactl &= ~ATA_DMA_WR;
+       if (!rw)
+               dmactl |= ATA_DMA_WR;
+
+       iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+       return 1;
+}
+
+static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
+{
+       struct nv_swncq_port_priv *pp = ap->private_data;
+       struct ata_queued_cmd *qc;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       u32 serror;
+       u8 ata_stat;
+       int rc = 0;
+
+       ata_stat = ap->ops->check_status(ap);
+       nv_swncq_irq_clear(ap, fis);
+       if (!fis)
+               return;
+
+       if (ap->pflags & ATA_PFLAG_FROZEN)
+               return;
+
+       if (fis & NV_SWNCQ_IRQ_HOTPLUG) {
+               nv_swncq_hotplug(ap, fis);
+               return;
+       }
+
+       if (!pp->qc_active)
+               return;
+
+       if (ap->ops->scr_read(ap, SCR_ERROR, &serror))
+               return;
+       ap->ops->scr_write(ap, SCR_ERROR, serror);
+
+       if (ata_stat & ATA_ERR) {
+               ata_ehi_clear_desc(ehi);
+               ata_ehi_push_desc(ehi, "Ata error. fis:0x%X", fis);
+               ehi->err_mask |= AC_ERR_DEV;
+               ehi->serror |= serror;
+               ehi->action |= ATA_EH_SOFTRESET;
+               ata_port_freeze(ap);
+               return;
+       }
+
+       if (fis & NV_SWNCQ_IRQ_BACKOUT) {
+               /* If the IRQ is backout, driver must issue
+                * the new command again some time later.
+                */
+               pp->ncq_flags |= ncq_saw_backout;
+       }
+
+       if (fis & NV_SWNCQ_IRQ_SDBFIS) {
+               pp->ncq_flags |= ncq_saw_sdb;
+               DPRINTK("id 0x%x SWNCQ: qc_active 0x%X "
+                       "dhfis 0x%X dmafis 0x%X sactive 0x%X\n",
+                       ap->print_id, pp->qc_active, pp->dhfis_bits,
+                       pp->dmafis_bits, readl(pp->sactive_block));
+               rc = nv_swncq_sdbfis(ap);
+               if (rc < 0)
+                       goto irq_error;
+       }
+
+       if (fis & NV_SWNCQ_IRQ_DHREGFIS) {
+               /* The interrupt indicates the new command
+                * was transmitted correctly to the drive.
+                */
+               pp->dhfis_bits |= (0x1 << pp->last_issue_tag);
+               pp->ncq_flags |= ncq_saw_d2h;
+               if (pp->ncq_flags & (ncq_saw_sdb | ncq_saw_backout)) {
+                       ata_ehi_push_desc(ehi, "illegal fis transaction");
+                       ehi->err_mask |= AC_ERR_HSM;
+                       ehi->action |= ATA_EH_HARDRESET;
+                       goto irq_error;
+               }
+
+               if (!(fis & NV_SWNCQ_IRQ_DMASETUP) &&
+                   !(pp->ncq_flags & ncq_saw_dmas)) {
+                       ata_stat = ap->ops->check_status(ap);
+                       if (ata_stat & ATA_BUSY)
+                               goto irq_exit;
+
+                       if (pp->defer_queue.defer_bits) {
+                               DPRINTK("send next command\n");
+                               qc = nv_swncq_qc_from_dq(ap);
+                               nv_swncq_issue_atacmd(ap, qc);
+                       }
+               }
+       }
+
+       if (fis & NV_SWNCQ_IRQ_DMASETUP) {
+               /* program the dma controller with appropriate PRD buffers
+                * and start the DMA transfer for requested command.
+                */
+               pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap));
+               pp->ncq_flags |= ncq_saw_dmas;
+               rc = nv_swncq_dmafis(ap);
+       }
+
+irq_exit:
+       return;
+irq_error:
+       ata_ehi_push_desc(ehi, "fis:0x%x", fis);
+       ata_port_freeze(ap);
+       return;
+}
+
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance)
+{
+       struct ata_host *host = dev_instance;
+       unsigned int i;
+       unsigned int handled = 0;
+       unsigned long flags;
+       u32 irq_stat;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       irq_stat = readl(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_MCP55);
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+                       if (ap->link.sactive) {
+                               nv_swncq_host_interrupt(ap, (u16)irq_stat);
+                               handled = 1;
+                       } else {
+                               if (irq_stat)   /* reserve Hotplug */
+                                       nv_swncq_irq_clear(ap, 0xfff0);
+
+                               handled += nv_host_intr(ap, (u8)irq_stat);
+                       }
+               }
+               irq_stat >>= NV_INT_PORT_SHIFT_MCP55;
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
+
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version = 0;
@@ -1551,7 +2378,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                return rc;
 
        /* determine type and allocate host */
-       if (type >= CK804 && adma_enabled) {
+       if (type == CK804 && adma_enabled) {
                dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
                type = ADMA;
        }
@@ -1597,6 +2424,9 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                rc = nv_adma_host_init(host);
                if (rc)
                        return rc;
+       } else if (type == SWNCQ && swncq_enabled) {
+               dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n");
+               nv_swncq_host_init(host);
        }
 
        pci_set_master(pdev);
@@ -1696,3 +2526,6 @@ module_init(nv_init);
 module_exit(nv_exit);
 module_param_named(adma, adma_enabled, bool, 0444);
 MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
+module_param_named(swncq, swncq_enabled, bool, 0444);
+MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: false)");
+
index 1dc9b4f2b2dcb56ff6b0949cafb127cda08b446e..cc6ee0890f56c1ddcb24581bbad7bbc27ae2640e 100644 (file)
@@ -505,7 +505,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        int rc;
        struct ata_host *host;
        int board_id = (int) ent->driver_data;
-       const int *bar_sizes;
+       const unsigned *bar_sizes;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
index 8296420ceaef3a59a422d240efb3e424f9fba8c1..ff2a303cbe000325c71079d2846ffc98ed26fdba 100644 (file)
@@ -626,7 +626,7 @@ typedef struct {
 
 struct amb_dev {
   u8               irq;
-  long            flags;
+  unsigned long           flags;
   u32              iobase;
   u32 *            membase;
 
index 737cea49f8721b57e766650365b4221d8efc2af8..94ebc9dc40fd64434f06e48f1923ad21e5db5112 100644 (file)
@@ -1295,7 +1295,7 @@ static const struct atmdev_ops ops = {
 
 static void __devinit undocumented_pci_fix (struct pci_dev *pdev)
 {
-       int tint;
+       u32 tint;
 
        /* The Windows driver says: */
        /* Switch off FireStream Retry Limit Threshold 
index 4461229f56a54cf8aaa6c3df5b91bfe3aa62f519..b48859d0d434bcfaf44ad0a94d848e6f12e9da1f 100644 (file)
@@ -423,7 +423,7 @@ struct hrz_dev {
   wait_queue_head_t   tx_queue;
 
   u8                  irq;
-  long               flags;
+  unsigned long              flags;
   u8                  tx_last;
   u8                  tx_idle;
 
index cb99daeae936777b45f128783c65fd5622258513..7a1390cd6aad67f407d750a050caa192a9ab8f21 100644 (file)
@@ -34,7 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
        return MEMORY_CLASS_NAME;
 }
 
-static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env)
+static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env)
 {
        int retval = 0;
 
index 28d145756f6cc5afbc43d4a2e41112fbb0c3db60..55c3237fb1bc8792df398d4f18531a48f9da3cb1 100644 (file)
@@ -3101,7 +3101,7 @@ static void cciss_getgeometry(int cntl_num)
        int i;
        int listlength = 0;
        __u32 lunid = 0;
-       int block_size;
+       unsigned block_size;
        sector_t total_size;
 
        ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
index 8955e7ff759a7c9b9269fee1e2398a81622cccdd..b83824c41329f3d4f4459de76b981c67ec946ba5 100644 (file)
@@ -58,6 +58,9 @@ struct gatt_mask {
         * devices this will probably be ignored */
 };
 
+#define AGP_PAGE_DESTROY_UNMAP 1
+#define AGP_PAGE_DESTROY_FREE 2
+
 struct aper_size_info_8 {
        int size;
        int num_entries;
@@ -113,7 +116,7 @@ struct agp_bridge_driver {
        struct agp_memory *(*alloc_by_type) (size_t, int);
        void (*free_by_type)(struct agp_memory *);
        void *(*agp_alloc_page)(struct agp_bridge_data *);
-       void (*agp_destroy_page)(void *);
+       void (*agp_destroy_page)(void *, int flags);
         int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
 };
 
@@ -267,7 +270,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type);
 struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
 void agp_generic_free_by_type(struct agp_memory *curr);
 void *agp_generic_alloc_page(struct agp_bridge_data *bridge);
-void agp_generic_destroy_page(void *addr);
+void agp_generic_destroy_page(void *addr, int flags);
 void agp_free_key(int key);
 int agp_num_entries(void);
 u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
index 4941ddb78939abf7db58ed11c17741feb8ddc8ce..aa5ddb716ffb4e613d6018b94db5651af9137ea8 100644 (file)
@@ -156,29 +156,34 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
        return addr;
 }
 
-static void ali_destroy_page(void * addr)
+static void ali_destroy_page(void * addr, int flags)
 {
        if (addr) {
-               global_cache_flush();   /* is this really needed?  --hch */
-               agp_generic_destroy_page(addr);
-               global_flush_tlb();
+               if (flags & AGP_PAGE_DESTROY_UNMAP) {
+                       global_cache_flush();   /* is this really needed?  --hch */
+                       agp_generic_destroy_page(addr, flags);
+                       global_flush_tlb();
+               } else
+                       agp_generic_destroy_page(addr, flags);
        }
 }
 
-static void m1541_destroy_page(void * addr)
+static void m1541_destroy_page(void * addr, int flags)
 {
        u32 temp;
 
        if (addr == NULL)
                return;
 
-       global_cache_flush();
+       if (flags & AGP_PAGE_DESTROY_UNMAP) {
+               global_cache_flush();
 
-       pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
-       pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
-                       (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-                         virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
-       agp_generic_destroy_page(addr);
+               pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
+               pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
+                                      (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+                                        virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
+       }
+       agp_generic_destroy_page(addr, flags);
 }
 
 
index f60bca70d1fba99f91cb6573b93d56bd3bea120c..1405a42585e13eb29dcb9ae3bce3d99836b9d5fb 100644 (file)
@@ -100,21 +100,16 @@ static int amd_create_gatt_pages(int nr_tables)
 
        for (i = 0; i < nr_tables; i++) {
                entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL);
+               tables[i] = entry;
                if (entry == NULL) {
-                       while (i > 0) {
-                               kfree(tables[i-1]);
-                               i--;
-                       }
-                       kfree(tables);
                        retval = -ENOMEM;
                        break;
                }
-               tables[i] = entry;
                retval = amd_create_page_map(entry);
                if (retval != 0)
                        break;
        }
-       amd_irongate_private.num_tables = nr_tables;
+       amd_irongate_private.num_tables = i;
        amd_irongate_private.gatt_pages = tables;
 
        if (retval != 0)
index 1b47c89a1b992c7946b3d9b6ae1fcf843a47eebb..832ded20fe70f60e2aa77ef3730beb94aac02cd8 100644 (file)
@@ -189,9 +189,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
 
 err_out:
        if (bridge->driver->needs_scratch_page) {
-               bridge->driver->agp_destroy_page(
-                               gart_to_virt(bridge->scratch_page_real));
+               bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+                                                AGP_PAGE_DESTROY_UNMAP);
                flush_agp_mappings();
+               bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+                                                AGP_PAGE_DESTROY_FREE);
        }
        if (got_gatt)
                bridge->driver->free_gatt_table(bridge);
@@ -215,9 +217,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
 
        if (bridge->driver->agp_destroy_page &&
            bridge->driver->needs_scratch_page) {
-               bridge->driver->agp_destroy_page(
-                               gart_to_virt(bridge->scratch_page_real));
+               bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+                                                AGP_PAGE_DESTROY_UNMAP);
                flush_agp_mappings();
+               bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+                                                AGP_PAGE_DESTROY_FREE);
        }
 }
 
index 3db4f4076ed4dae4292d8802b170efff796a036c..64b2f6d7059dc96f494e49ace44a2601937d5a85 100644 (file)
@@ -195,9 +195,12 @@ void agp_free_memory(struct agp_memory *curr)
        }
        if (curr->page_count != 0) {
                for (i = 0; i < curr->page_count; i++) {
-                       curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
+                       curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
                }
                flush_agp_mappings();
+               for (i = 0; i < curr->page_count; i++) {
+                       curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
+               }
        }
        agp_free_key(curr->key);
        agp_free_page_array(curr);
@@ -1176,7 +1179,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
 EXPORT_SYMBOL(agp_generic_alloc_page);
 
 
-void agp_generic_destroy_page(void *addr)
+void agp_generic_destroy_page(void *addr, int flags)
 {
        struct page *page;
 
@@ -1184,10 +1187,14 @@ void agp_generic_destroy_page(void *addr)
                return;
 
        page = virt_to_page(addr);
-       unmap_page_from_agp(page);
-       put_page(page);
-       free_page((unsigned long)addr);
-       atomic_dec(&agp_bridge->current_memory_agp);
+       if (flags & AGP_PAGE_DESTROY_UNMAP)
+               unmap_page_from_agp(page);
+
+       if (flags & AGP_PAGE_DESTROY_FREE) {
+               put_page(page);
+               free_page((unsigned long)addr);
+               atomic_dec(&agp_bridge->current_memory_agp);
+       }
 }
 EXPORT_SYMBOL(agp_generic_destroy_page);
 
index 75d2aca6353de9ce1bb1bd90acfca27eddc60688..70117df4d06779c490e88db53b1361a752a2d742 100644 (file)
@@ -536,10 +536,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
        return page;
 }
 
-static void i460_destroy_page (void *page)
+static void i460_destroy_page (void *page, int flags)
 {
        if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
-               agp_generic_destroy_page(page);
+               agp_generic_destroy_page(page, flags);
                global_flush_tlb();
        }
 }
index 141ca176c3974719fae122745aaee82ef2c4b276..d87961993ccf7f0ab5acf76155b12367bd6b37e0 100644 (file)
@@ -400,9 +400,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
                if (curr->page_count == 4)
                        i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
                else {
-                       agp_bridge->driver->agp_destroy_page(
-                                gart_to_virt(curr->memory[0]));
+                       agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+                                                            AGP_PAGE_DESTROY_UNMAP);
                        global_flush_tlb();
+                       agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+                                                            AGP_PAGE_DESTROY_FREE);
                }
                agp_free_page_array(curr);
        }
index 2d6f2d0bd02b8b963e19c9594aa96d1990a5a69f..82fb3d0d2785c5bf563b79fdcd39f782a8f48624 100644 (file)
 #define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
 #endif
 
-#define XFREE86_VERSION(major,minor,patch,snap) \
-               ((major << 16) | (minor << 8) | patch)
-
-#ifndef CONFIG_XFREE86_VERSION
-#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0)
-#endif
-
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
-#define DRM_PROC_DEVICES "/proc/devices"
-#define DRM_PROC_MISC   "/proc/misc"
-#define DRM_PROC_DRM    "/proc/drm"
-#define DRM_DEV_DRM     "/dev/drm"
-#define DRM_DEV_MODE    (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
-#define DRM_DEV_UID     0
-#define DRM_DEV_GID     0
-#endif
-
-#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
 #define DRM_MAJOR       226
 #define DRM_MAX_MINOR   15
-#endif
+
 #define DRM_NAME       "drm"     /**< Name in kernel, /dev, and /proc */
 #define DRM_MIN_ORDER  5         /**< At least 2^5 bytes = 32 bytes */
 #define DRM_MAX_ORDER  22        /**< Up to 2^22 bytes = 4MB */
index 0df87fc3dcb2ef224992bd3c001c01468db4a121..9dd0760dd87a7e89b405f2f83172cc26d803962c 100644 (file)
@@ -80,6 +80,9 @@
 #define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
 #define __OS_HAS_MTRR (defined(CONFIG_MTRR))
 
+struct drm_file;
+struct drm_device;
+
 #include "drm_os_linux.h"
 #include "drm_hashtab.h"
 
  * \param dev DRM device.
  * \param filp file pointer of the caller.
  */
-#define LOCK_TEST_WITH_RETURN( dev, filp )                             \
+#define LOCK_TEST_WITH_RETURN( dev, file_priv )                                \
 do {                                                                   \
        if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||           \
-            dev->lock.filp != filp ) {                         \
-               DRM_ERROR( "%s called without lock held\n",             \
-                          __FUNCTION__ );                              \
+            dev->lock.file_priv != file_priv ) {                       \
+               DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\
+                          __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
+                          dev->lock.file_priv, file_priv );            \
                return -EINVAL;                                         \
        }                                                               \
 } while (0)
@@ -257,12 +261,12 @@ do {                                                                      \
  * Ioctl function type.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private pointer.
  * \param cmd command.
  * \param arg argument.
  */
-typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
+typedef int drm_ioctl_t(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
 
 typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
                               unsigned long arg);
@@ -271,10 +275,18 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
 #define        DRM_MASTER      0x2
 #define DRM_ROOT_ONLY  0x4
 
-typedef struct drm_ioctl_desc {
+struct drm_ioctl_desc {
+       unsigned int cmd;
        drm_ioctl_t *func;
        int flags;
-} drm_ioctl_desc_t;
+};
+
+/**
+ * Creates a driver or general drm_ioctl_desc array entry for the given
+ * ioctl, for use by drm_ioctl().
+ */
+#define DRM_IOCTL_DEF(ioctl, func, flags) \
+       [DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags}
 
 struct drm_magic_entry {
        struct list_head head;
@@ -304,7 +316,7 @@ struct drm_buf {
        __volatile__ int waiting;      /**< On kernel DMA queue */
        __volatile__ int pending;      /**< On hardware DMA queue */
        wait_queue_head_t dma_wait;    /**< Processes waiting */
-       struct file *filp;             /**< Pointer to holding file descr */
+       struct drm_file *file_priv;    /**< Private of holding file descr */
        int context;                   /**< Kernel queue for this buffer */
        int while_locked;              /**< Dispatch this buffer while locked */
        enum {
@@ -377,6 +389,7 @@ struct drm_file {
        int remove_auth_on_close;
        unsigned long lock_count;
        void *driver_priv;
+       struct file *filp;
 };
 
 /** Wait queue */
@@ -403,7 +416,7 @@ struct drm_queue {
  */
 struct drm_lock_data {
        struct drm_hw_lock *hw_lock;    /**< Hardware lock */
-       struct file *filp;              /**< File descr of lock holder (0=kernel) */
+       struct drm_file *file_priv;     /**< File descr of lock holder (0=kernel) */
        wait_queue_head_t lock_queue;   /**< Queue of blocked processes */
        unsigned long lock_time;        /**< Time of last lock in jiffies */
        spinlock_t spinlock;
@@ -552,11 +565,11 @@ struct drm_driver {
        int (*load) (struct drm_device *, unsigned long flags);
        int (*firstopen) (struct drm_device *);
        int (*open) (struct drm_device *, struct drm_file *);
-       void (*preclose) (struct drm_device *, struct file * filp);
+       void (*preclose) (struct drm_device *, struct drm_file *file_priv);
        void (*postclose) (struct drm_device *, struct drm_file *);
        void (*lastclose) (struct drm_device *);
        int (*unload) (struct drm_device *);
-       int (*dma_ioctl) (DRM_IOCTL_ARGS);
+       int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
        void (*dma_ready) (struct drm_device *);
        int (*dma_quiescent) (struct drm_device *);
        int (*context_ctor) (struct drm_device *dev, int context);
@@ -587,11 +600,12 @@ struct drm_driver {
        void (*irq_preinstall) (struct drm_device *dev);
        void (*irq_postinstall) (struct drm_device *dev);
        void (*irq_uninstall) (struct drm_device *dev);
-       void (*reclaim_buffers) (struct drm_device *dev, struct file * filp);
+       void (*reclaim_buffers) (struct drm_device *dev,
+                                struct drm_file * file_priv);
        void (*reclaim_buffers_locked) (struct drm_device *dev,
-                                       struct file *filp);
+                                       struct drm_file *file_priv);
        void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
-                                       struct file * filp);
+                                           struct drm_file *file_priv);
        unsigned long (*get_map_ofs) (struct drm_map * map);
        unsigned long (*get_reg_ofs) (struct drm_device *dev);
        void (*set_version) (struct drm_device *dev,
@@ -606,7 +620,7 @@ struct drm_driver {
 
        u32 driver_features;
        int dev_priv_size;
-       drm_ioctl_desc_t *ioctls;
+       struct drm_ioctl_desc *ioctls;
        int num_ioctls;
        struct file_operations fops;
        struct pci_driver pci_driver;
@@ -850,70 +864,70 @@ extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
 extern int drm_unbind_agp(DRM_AGP_MEM * handle);
 
                                /* Misc. IOCTL support (drm_ioctl.h) */
-extern int drm_irq_by_busid(struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg);
-extern int drm_getunique(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
-extern int drm_setunique(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
-extern int drm_getmap(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int drm_getclient(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
-extern int drm_getstats(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
-extern int drm_setversion(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg);
-extern int drm_noop(struct inode *inode, struct file *filp,
-                   unsigned int cmd, unsigned long arg);
+extern int drm_irq_by_busid(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv);
+extern int drm_getunique(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int drm_setunique(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int drm_getmap(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+extern int drm_getclient(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int drm_getstats(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern int drm_setversion(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv);
+extern int drm_noop(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
 
                                /* Context IOCTL support (drm_context.h) */
-extern int drm_resctx(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int drm_addctx(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int drm_modctx(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int drm_getctx(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int drm_switchctx(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
-extern int drm_newctx(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int drm_rmctx(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg);
+extern int drm_resctx(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+extern int drm_addctx(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+extern int drm_modctx(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+extern int drm_getctx(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+extern int drm_switchctx(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int drm_newctx(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+extern int drm_rmctx(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
 
 extern int drm_ctxbitmap_init(struct drm_device *dev);
 extern void drm_ctxbitmap_cleanup(struct drm_device *dev);
 extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
 
-extern int drm_setsareactx(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg);
-extern int drm_getsareactx(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg);
+extern int drm_setsareactx(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+extern int drm_getsareactx(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
 
                                /* Drawable IOCTL support (drm_drawable.h) */
-extern int drm_adddraw(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg);
-extern int drm_rmdraw(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
-extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg);
+extern int drm_adddraw(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+extern int drm_rmdraw(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+extern int drm_update_drawable_info(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
 extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
                                                  drm_drawable_t id);
 extern void drm_drawable_free_all(struct drm_device *dev);
 
                                /* Authentication IOCTL support (drm_auth.h) */
-extern int drm_getmagic(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
-extern int drm_authmagic(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
+extern int drm_getmagic(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern int drm_authmagic(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
 
                                /* Locking IOCTL support (drm_lock.h) */
-extern int drm_lock(struct inode *inode, struct file *filp,
-                   unsigned int cmd, unsigned long arg);
-extern int drm_unlock(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg);
+extern int drm_lock(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+extern int drm_unlock(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
 extern int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
 extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context);
 extern void drm_idlelock_take(struct drm_lock_data *lock_data);
@@ -924,8 +938,7 @@ extern void drm_idlelock_release(struct drm_lock_data *lock_data);
  * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
  */
 
-extern int drm_i_have_hw_lock(struct file *filp);
-extern int drm_kernel_take_hw_lock(struct file *filp);
+extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv);
 
                                /* Buffer management support (drm_bufs.h) */
 extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
@@ -933,24 +946,23 @@ extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request
 extern int drm_addmap(struct drm_device *dev, unsigned int offset,
                      unsigned int size, enum drm_map_type type,
                      enum drm_map_flags flags, drm_local_map_t ** map_ptr);
-extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg);
-extern int drm_rmmap(struct drm_device *dev, drm_local_map_t * map);
-extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t * map);
-extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg);
-
+extern int drm_addmap_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv);
+extern int drm_rmmap(struct drm_device *dev, drm_local_map_t *map);
+extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map);
+extern int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+extern int drm_addbufs(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+extern int drm_infobufs(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern int drm_markbufs(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern int drm_freebufs(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern int drm_mapbufs(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
 extern int drm_order(unsigned long size);
-extern int drm_addbufs(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg);
-extern int drm_infobufs(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
-extern int drm_markbufs(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
-extern int drm_freebufs(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
-extern int drm_mapbufs(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg);
 extern unsigned long drm_get_resource_start(struct drm_device *dev,
                                            unsigned int resource);
 extern unsigned long drm_get_resource_len(struct drm_device *dev,
@@ -960,19 +972,20 @@ extern unsigned long drm_get_resource_len(struct drm_device *dev,
 extern int drm_dma_setup(struct drm_device *dev);
 extern void drm_dma_takedown(struct drm_device *dev);
 extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf);
-extern void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp);
+extern void drm_core_reclaim_buffers(struct drm_device *dev,
+                                    struct drm_file *filp);
 
                                /* IRQ support (drm_irq.h) */
-extern int drm_control(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg);
+extern int drm_control(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
 extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
 extern int drm_irq_uninstall(struct drm_device *dev);
 extern void drm_driver_irq_preinstall(struct drm_device *dev);
 extern void drm_driver_irq_postinstall(struct drm_device *dev);
 extern void drm_driver_irq_uninstall(struct drm_device *dev);
 
-extern int drm_wait_vblank(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg);
+extern int drm_wait_vblank(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
 extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
 extern void drm_vbl_send_signals(struct drm_device *dev);
 extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
@@ -980,31 +993,30 @@ extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_de
                                /* AGP/GART support (drm_agpsupport.h) */
 extern struct drm_agp_head *drm_agp_init(struct drm_device *dev);
 extern int drm_agp_acquire(struct drm_device *dev);
-extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
-                                unsigned int cmd, unsigned long arg);
+extern int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+                                struct drm_file *file_priv);
 extern int drm_agp_release(struct drm_device *dev);
-extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
-                                unsigned int cmd, unsigned long arg);
+extern int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+                                struct drm_file *file_priv);
 extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode);
-extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
-                               unsigned int cmd, unsigned long arg);
-extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info * info);
-extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
-                             unsigned int cmd, unsigned long arg);
+extern int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info);
+extern int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
 extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request);
-extern int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
+extern int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
 extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request);
-extern int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
+extern int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
 extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request);
-extern int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg);
+extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv);
 extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
-extern int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
-extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge,
-                                           size_t pages, u32 type);
+extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type);
 extern int drm_agp_free_memory(DRM_AGP_MEM * handle);
 extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start);
 extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
@@ -1033,10 +1045,11 @@ extern int drm_proc_cleanup(int minor,
 
                                /* Scatter Gather Support (drm_scatter.h) */
 extern void drm_sg_cleanup(struct drm_sg_mem * entry);
-extern int drm_sg_alloc(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg);
-extern int drm_sg_free(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg);
+extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request);
+extern int drm_sg_free(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
 
                               /* ATI PCIGART support (ati_pcigart.h) */
 extern int drm_ati_pcigart_init(struct drm_device *dev,
index 354f0e3674bfff3c5b586c7b5599bcf965c6922c..214f4fbcba73e5746f63cde6dd3605416126e7b2 100644 (file)
@@ -40,7 +40,7 @@
  * Get AGP information.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a (output) drm_agp_info structure.
  * \return zero on success or a negative number on failure.
@@ -71,20 +71,16 @@ int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
 
 EXPORT_SYMBOL(drm_agp_info);
 
-int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg)
+int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_agp_info info;
+       struct drm_agp_info *info = data;
        int err;
 
-       err = drm_agp_info(dev, &info);
+       err = drm_agp_info(dev, info);
        if (err)
                return err;
 
-       if (copy_to_user((struct drm_agp_info __user *) arg, &info, sizeof(info)))
-               return -EFAULT;
        return 0;
 }
 
@@ -115,7 +111,7 @@ EXPORT_SYMBOL(drm_agp_acquire);
  * Acquire the AGP device (ioctl).
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument.
  * \return zero on success or a negative number on failure.
@@ -123,12 +119,10 @@ EXPORT_SYMBOL(drm_agp_acquire);
  * Verifies the AGP device hasn't been acquired before and calls
  * \c agp_backend_acquire.
  */
-int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg)
+int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-
-       return drm_agp_acquire((struct drm_device *) priv->head->dev);
+       return drm_agp_acquire((struct drm_device *) file_priv->head->dev);
 }
 
 /**
@@ -149,12 +143,9 @@ int drm_agp_release(struct drm_device * dev)
 }
 EXPORT_SYMBOL(drm_agp_release);
 
-int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg)
+int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-
        return drm_agp_release(dev);
 }
 
@@ -182,24 +173,19 @@ int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode)
 
 EXPORT_SYMBOL(drm_agp_enable);
 
-int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
+int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_agp_mode mode;
-
-       if (copy_from_user(&mode, (struct drm_agp_mode __user *) arg, sizeof(mode)))
-               return -EFAULT;
+       struct drm_agp_mode *mode = data;
 
-       return drm_agp_enable(dev, mode);
+       return drm_agp_enable(dev, *mode);
 }
 
 /**
  * Allocate AGP memory.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv file private pointer.
  * \param cmd command.
  * \param arg pointer to a drm_agp_buffer structure.
  * \return zero on success or a negative number on failure.
@@ -241,35 +227,13 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
 }
 EXPORT_SYMBOL(drm_agp_alloc);
 
-int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_agp_buffer request;
-       struct drm_agp_buffer __user *argp = (void __user *)arg;
-       int err;
-
-       if (copy_from_user(&request, argp, sizeof(request)))
-               return -EFAULT;
 
-       err = drm_agp_alloc(dev, &request);
-       if (err)
-               return err;
-
-       if (copy_to_user(argp, &request, sizeof(request))) {
-               struct drm_agp_mem *entry;
-               list_for_each_entry(entry, &dev->agp->memory, head) {
-                       if (entry->handle == request.handle)
-                               break;
-               }
-               list_del(&entry->head);
-               drm_free_agp(entry->memory, entry->pages);
-               drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
-               return -EFAULT;
-       }
+int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_agp_buffer *request = data;
 
-       return 0;
+       return drm_agp_alloc(dev, request);
 }
 
 /**
@@ -297,7 +261,7 @@ static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
  * Unbind AGP memory from the GATT (ioctl).
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_agp_binding structure.
  * \return zero on success or a negative number on failure.
@@ -323,25 +287,20 @@ int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
 }
 EXPORT_SYMBOL(drm_agp_unbind);
 
-int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_agp_binding request;
 
-       if (copy_from_user
-           (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
-               return -EFAULT;
+int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct drm_agp_binding *request = data;
 
-       return drm_agp_unbind(dev, &request);
+       return drm_agp_unbind(dev, request);
 }
 
 /**
  * Bind AGP memory into the GATT (ioctl)
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_agp_binding structure.
  * \return zero on success or a negative number on failure.
@@ -372,25 +331,20 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
 }
 EXPORT_SYMBOL(drm_agp_bind);
 
-int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg)
-{
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_agp_binding request;
 
-       if (copy_from_user
-           (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
-               return -EFAULT;
+int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
+{
+       struct drm_agp_binding *request = data;
 
-       return drm_agp_bind(dev, &request);
+       return drm_agp_bind(dev, request);
 }
 
 /**
  * Free AGP memory (ioctl).
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_agp_buffer structure.
  * \return zero on success or a negative number on failure.
@@ -419,18 +373,14 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
 }
 EXPORT_SYMBOL(drm_agp_free);
 
-int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg)
-{
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_agp_buffer request;
 
-       if (copy_from_user
-           (&request, (struct drm_agp_buffer __user *) arg, sizeof(request)))
-               return -EFAULT;
 
-       return drm_agp_free(dev, &request);
+int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
+{
+       struct drm_agp_buffer *request = data;
+
+       return drm_agp_free(dev, request);
 }
 
 /**
index 7f777da872cd61832db65e102e3557cc4b497c77..a73462723d2d517d2c7af88cb46880b9024ee354 100644 (file)
@@ -128,42 +128,38 @@ static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic)
  * Get a unique magic number (ioctl).
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a resulting drm_auth structure.
  * \return zero on success, or a negative number on failure.
  *
  * If there is a magic number in drm_file::magic then use it, otherwise
  * searches an unique non-zero magic number and add it associating it with \p
- * filp.
+ * file_priv.
  */
-int drm_getmagic(struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg)
+int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        static drm_magic_t sequence = 0;
        static DEFINE_SPINLOCK(lock);
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_auth auth;
+       struct drm_auth *auth = data;
 
        /* Find unique magic */
-       if (priv->magic) {
-               auth.magic = priv->magic;
+       if (file_priv->magic) {
+               auth->magic = file_priv->magic;
        } else {
                do {
                        spin_lock(&lock);
                        if (!sequence)
                                ++sequence;     /* reserve 0 */
-                       auth.magic = sequence++;
+                       auth->magic = sequence++;
                        spin_unlock(&lock);
-               } while (drm_find_file(dev, auth.magic));
-               priv->magic = auth.magic;
-               drm_add_magic(dev, priv, auth.magic);
+               } while (drm_find_file(dev, auth->magic));
+               file_priv->magic = auth->magic;
+               drm_add_magic(dev, file_priv, auth->magic);
        }
 
-       DRM_DEBUG("%u\n", auth.magic);
-       if (copy_to_user((struct drm_auth __user *) arg, &auth, sizeof(auth)))
-               return -EFAULT;
+       DRM_DEBUG("%u\n", auth->magic);
+
        return 0;
 }
 
@@ -171,27 +167,23 @@ int drm_getmagic(struct inode *inode, struct file *filp,
  * Authenticate with a magic.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_auth structure.
  * \return zero if authentication successed, or a negative number otherwise.
  *
- * Checks if \p filp is associated with the magic number passed in \arg.
+ * Checks if \p file_priv is associated with the magic number passed in \arg.
  */
-int drm_authmagic(struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg)
+int drm_authmagic(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_auth auth;
+       struct drm_auth *auth = data;
        struct drm_file *file;
 
-       if (copy_from_user(&auth, (struct drm_auth __user *) arg, sizeof(auth)))
-               return -EFAULT;
-       DRM_DEBUG("%u\n", auth.magic);
-       if ((file = drm_find_file(dev, auth.magic))) {
+       DRM_DEBUG("%u\n", auth->magic);
+       if ((file = drm_find_file(dev, auth->magic))) {
                file->authenticated = 1;
-               drm_remove_magic(dev, auth.magic);
+               drm_remove_magic(dev, auth->magic);
                return 0;
        }
        return -EINVAL;
index c115b39b85178cc4d84fd9d9b55f5521ccb6d7c5..856774fbe025f17e6f7ed4b3014d2d37e8b08c22 100644 (file)
@@ -92,7 +92,7 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
  * Ioctl to specify a range of memory that is available for mapping by a non-root process.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_map structure.
  * \return zero on success or a negative value on error.
@@ -332,38 +332,24 @@ int drm_addmap(struct drm_device * dev, unsigned int offset,
 
 EXPORT_SYMBOL(drm_addmap);
 
-int drm_addmap_ioctl(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
+int drm_addmap_ioctl(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_map map;
+       struct drm_map *map = data;
        struct drm_map_list *maplist;
-       struct drm_map __user *argp = (void __user *)arg;
        int err;
 
-       if (!(filp->f_mode & 3))
-               return -EACCES; /* Require read/write */
-
-       if (copy_from_user(&map, argp, sizeof(map))) {
-               return -EFAULT;
-       }
-
-       if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP))
+       if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP))
                return -EPERM;
 
-       err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags,
-                             &maplist);
+       err = drm_addmap_core(dev, map->offset, map->size, map->type,
+                             map->flags, &maplist);
 
        if (err)
                return err;
 
-       if (copy_to_user(argp, maplist->map, sizeof(struct drm_map)))
-               return -EFAULT;
-
        /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */
-       if (put_user((void *)(unsigned long)maplist->user_token, &argp->handle))
-               return -EFAULT;
+       map->handle = (void *)(unsigned long)maplist->user_token;
        return 0;
 }
 
@@ -372,7 +358,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
  * isn't in use.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a struct drm_map structure.
  * \return zero on success or a negative value on error.
@@ -453,24 +439,18 @@ int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
  * gets used by drivers that the server doesn't need to care about.  This seems
  * unlikely.
  */
-int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
-                   unsigned int cmd, unsigned long arg)
+int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_map request;
+       struct drm_map *request = data;
        drm_local_map_t *map = NULL;
        struct drm_map_list *r_list;
        int ret;
 
-       if (copy_from_user(&request, (struct drm_map __user *) arg, sizeof(request))) {
-               return -EFAULT;
-       }
-
        mutex_lock(&dev->struct_mutex);
        list_for_each_entry(r_list, &dev->maplist, head) {
                if (r_list->map &&
-                   r_list->user_token == (unsigned long)request.handle &&
+                   r_list->user_token == (unsigned long)request->handle &&
                    r_list->map->flags & _DRM_REMOVABLE) {
                        map = r_list->map;
                        break;
@@ -661,7 +641,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                buf->waiting = 0;
                buf->pending = 0;
                init_waitqueue_head(&buf->dma_wait);
-               buf->filp = NULL;
+               buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
                buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -872,7 +852,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                        buf->waiting = 0;
                        buf->pending = 0;
                        init_waitqueue_head(&buf->dma_wait);
-                       buf->filp = NULL;
+                       buf->file_priv = NULL;
 
                        buf->dev_priv_size = dev->driver->dev_priv_size;
                        buf->dev_private = drm_alloc(buf->dev_priv_size,
@@ -1050,7 +1030,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
                buf->waiting = 0;
                buf->pending = 0;
                init_waitqueue_head(&buf->dma_wait);
-               buf->filp = NULL;
+               buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
                buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -1211,7 +1191,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
                buf->waiting = 0;
                buf->pending = 0;
                init_waitqueue_head(&buf->dma_wait);
-               buf->filp = NULL;
+               buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
                buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -1275,7 +1255,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
  * Add buffers for DMA transfers (ioctl).
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a struct drm_buf_desc request.
  * \return zero on success or a negative number on failure.
@@ -1285,38 +1265,27 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
  * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent
  * PCI memory respectively.
  */
-int drm_addbufs(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+int drm_addbufs(struct drm_device *dev, void *data,
+               struct drm_file *file_priv)
 {
-       struct drm_buf_desc request;
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
+       struct drm_buf_desc *request = data;
        int ret;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
                return -EINVAL;
 
-       if (copy_from_user(&request, (struct drm_buf_desc __user *) arg,
-                          sizeof(request)))
-               return -EFAULT;
-
 #if __OS_HAS_AGP
-       if (request.flags & _DRM_AGP_BUFFER)
-               ret = drm_addbufs_agp(dev, &request);
+       if (request->flags & _DRM_AGP_BUFFER)
+               ret = drm_addbufs_agp(dev, request);
        else
 #endif
-       if (request.flags & _DRM_SG_BUFFER)
-               ret = drm_addbufs_sg(dev, &request);
-       else if (request.flags & _DRM_FB_BUFFER)
-               ret = drm_addbufs_fb(dev, &request);
+       if (request->flags & _DRM_SG_BUFFER)
+               ret = drm_addbufs_sg(dev, request);
+       else if (request->flags & _DRM_FB_BUFFER)
+               ret = drm_addbufs_fb(dev, request);
        else
-               ret = drm_addbufs_pci(dev, &request);
+               ret = drm_addbufs_pci(dev, request);
 
-       if (ret == 0) {
-               if (copy_to_user((void __user *)arg, &request, sizeof(request))) {
-                       ret = -EFAULT;
-               }
-       }
        return ret;
 }
 
@@ -1328,7 +1297,7 @@ int drm_addbufs(struct inode *inode, struct file *filp,
  * large buffers can be used for image transfer).
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_buf_info structure.
  * \return zero on success or a negative number on failure.
@@ -1337,14 +1306,11 @@ int drm_addbufs(struct inode *inode, struct file *filp,
  * lock, preventing of allocating more buffers after this call. Information
  * about each requested buffer is then copied into user space.
  */
-int drm_infobufs(struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg)
+int drm_infobufs(struct drm_device *dev, void *data,
+                struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_device_dma *dma = dev->dma;
-       struct drm_buf_info request;
-       struct drm_buf_info __user *argp = (void __user *)arg;
+       struct drm_buf_info *request = data;
        int i;
        int count;
 
@@ -1362,9 +1328,6 @@ int drm_infobufs(struct inode *inode, struct file *filp,
        ++dev->buf_use;         /* Can't allocate more after this call */
        spin_unlock(&dev->count_lock);
 
-       if (copy_from_user(&request, argp, sizeof(request)))
-               return -EFAULT;
-
        for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
                if (dma->bufs[i].buf_count)
                        ++count;
@@ -1372,11 +1335,11 @@ int drm_infobufs(struct inode *inode, struct file *filp,
 
        DRM_DEBUG("count = %d\n", count);
 
-       if (request.count >= count) {
+       if (request->count >= count) {
                for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
                        if (dma->bufs[i].buf_count) {
                                struct drm_buf_desc __user *to =
-                                   &request.list[count];
+                                   &request->list[count];
                                struct drm_buf_entry *from = &dma->bufs[i];
                                struct drm_freelist *list = &dma->bufs[i].freelist;
                                if (copy_to_user(&to->count,
@@ -1403,10 +1366,7 @@ int drm_infobufs(struct inode *inode, struct file *filp,
                        }
                }
        }
-       request.count = count;
-
-       if (copy_to_user(argp, &request, sizeof(request)))
-               return -EFAULT;
+       request->count = count;
 
        return 0;
 }
@@ -1415,7 +1375,7 @@ int drm_infobufs(struct inode *inode, struct file *filp,
  * Specifies a low and high water mark for buffer allocation
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg a pointer to a drm_buf_desc structure.
  * \return zero on success or a negative number on failure.
@@ -1425,13 +1385,11 @@ int drm_infobufs(struct inode *inode, struct file *filp,
  *
  * \note This ioctl is deprecated and mostly never used.
  */
-int drm_markbufs(struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg)
+int drm_markbufs(struct drm_device *dev, void *data,
+                struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_device_dma *dma = dev->dma;
-       struct drm_buf_desc request;
+       struct drm_buf_desc *request = data;
        int order;
        struct drm_buf_entry *entry;
 
@@ -1441,24 +1399,20 @@ int drm_markbufs(struct inode *inode, struct file *filp,
        if (!dma)
                return -EINVAL;
 
-       if (copy_from_user(&request,
-                          (struct drm_buf_desc __user *) arg, sizeof(request)))
-               return -EFAULT;
-
        DRM_DEBUG("%d, %d, %d\n",
-                 request.size, request.low_mark, request.high_mark);
-       order = drm_order(request.size);
+                 request->size, request->low_mark, request->high_mark);
+       order = drm_order(request->size);
        if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
                return -EINVAL;
        entry = &dma->bufs[order];
 
-       if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+       if (request->low_mark < 0 || request->low_mark > entry->buf_count)
                return -EINVAL;
-       if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+       if (request->high_mark < 0 || request->high_mark > entry->buf_count)
                return -EINVAL;
 
-       entry->freelist.low_mark = request.low_mark;
-       entry->freelist.high_mark = request.high_mark;
+       entry->freelist.low_mark = request->low_mark;
+       entry->freelist.high_mark = request->high_mark;
 
        return 0;
 }
@@ -1467,7 +1421,7 @@ int drm_markbufs(struct inode *inode, struct file *filp,
  * Unreserve the buffers in list, previously reserved using drmDMA.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_buf_free structure.
  * \return zero on success or a negative number on failure.
@@ -1475,13 +1429,11 @@ int drm_markbufs(struct inode *inode, struct file *filp,
  * Calls free_buffer() for each used buffer.
  * This function is primarily used for debugging.
  */
-int drm_freebufs(struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg)
+int drm_freebufs(struct drm_device *dev, void *data,
+                struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_device_dma *dma = dev->dma;
-       struct drm_buf_free request;
+       struct drm_buf_free *request = data;
        int i;
        int idx;
        struct drm_buf *buf;
@@ -1492,13 +1444,9 @@ int drm_freebufs(struct inode *inode, struct file *filp,
        if (!dma)
                return -EINVAL;
 
-       if (copy_from_user(&request,
-                          (struct drm_buf_free __user *) arg, sizeof(request)))
-               return -EFAULT;
-
-       DRM_DEBUG("%d\n", request.count);
-       for (i = 0; i < request.count; i++) {
-               if (copy_from_user(&idx, &request.list[i], sizeof(idx)))
+       DRM_DEBUG("%d\n", request->count);
+       for (i = 0; i < request->count; i++) {
+               if (copy_from_user(&idx, &request->list[i], sizeof(idx)))
                        return -EFAULT;
                if (idx < 0 || idx >= dma->buf_count) {
                        DRM_ERROR("Index %d (of %d max)\n",
@@ -1506,7 +1454,7 @@ int drm_freebufs(struct inode *inode, struct file *filp,
                        return -EINVAL;
                }
                buf = dma->buflist[idx];
-               if (buf->filp != filp) {
+               if (buf->file_priv != file_priv) {
                        DRM_ERROR("Process %d freeing buffer not owned\n",
                                  current->pid);
                        return -EINVAL;
@@ -1521,7 +1469,7 @@ int drm_freebufs(struct inode *inode, struct file *filp,
  * Maps all of the DMA buffers into client-virtual space (ioctl).
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg pointer to a drm_buf_map structure.
  * \return zero on success or a negative number on failure.
@@ -1531,18 +1479,15 @@ int drm_freebufs(struct inode *inode, struct file *filp,
  * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
  * drm_mmap_dma().
  */
-int drm_mapbufs(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+int drm_mapbufs(struct drm_device *dev, void *data,
+               struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_device_dma *dma = dev->dma;
-       struct drm_buf_map __user *argp = (void __user *)arg;
        int retcode = 0;
        const int zero = 0;
        unsigned long virtual;
        unsigned long address;
-       struct drm_buf_map request;
+       struct drm_buf_map *request = data;
        int i;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1559,10 +1504,7 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
        dev->buf_use++;         /* Can't allocate more after this call */
        spin_unlock(&dev->count_lock);
 
-       if (copy_from_user(&request, argp, sizeof(request)))
-               return -EFAULT;
-
-       if (request.count >= dma->buf_count) {
+       if (request->count >= dma->buf_count) {
                if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP))
                    || (drm_core_check_feature(dev, DRIVER_SG)
                        && (dma->flags & _DRM_DMA_USE_SG))
@@ -1575,15 +1517,15 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
                                retcode = -EINVAL;
                                goto done;
                        }
-
                        down_write(&current->mm->mmap_sem);
-                       virtual = do_mmap(filp, 0, map->size,
+                       virtual = do_mmap(file_priv->filp, 0, map->size,
                                          PROT_READ | PROT_WRITE,
-                                         MAP_SHARED, token);
+                                         MAP_SHARED,
+                                         token);
                        up_write(&current->mm->mmap_sem);
                } else {
                        down_write(&current->mm->mmap_sem);
-                       virtual = do_mmap(filp, 0, dma->byte_count,
+                       virtual = do_mmap(file_priv->filp, 0, dma->byte_count,
                                          PROT_READ | PROT_WRITE,
                                          MAP_SHARED, 0);
                        up_write(&current->mm->mmap_sem);
@@ -1593,28 +1535,28 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
                        retcode = (signed long)virtual;
                        goto done;
                }
-               request.virtual = (void __user *)virtual;
+               request->virtual = (void __user *)virtual;
 
                for (i = 0; i < dma->buf_count; i++) {
-                       if (copy_to_user(&request.list[i].idx,
+                       if (copy_to_user(&request->list[i].idx,
                                         &dma->buflist[i]->idx,
-                                        sizeof(request.list[0].idx))) {
+                                        sizeof(request->list[0].idx))) {
                                retcode = -EFAULT;
                                goto done;
                        }
-                       if (copy_to_user(&request.list[i].total,
+                       if (copy_to_user(&request->list[i].total,
                                         &dma->buflist[i]->total,
-                                        sizeof(request.list[0].total))) {
+                                        sizeof(request->list[0].total))) {
                                retcode = -EFAULT;
                                goto done;
                        }
-                       if (copy_to_user(&request.list[i].used,
+                       if (copy_to_user(&request->list[i].used,
                                         &zero, sizeof(zero))) {
                                retcode = -EFAULT;
                                goto done;
                        }
                        address = virtual + dma->buflist[i]->offset;    /* *** */
-                       if (copy_to_user(&request.list[i].address,
+                       if (copy_to_user(&request->list[i].address,
                                         &address, sizeof(address))) {
                                retcode = -EFAULT;
                                goto done;
@@ -1622,11 +1564,8 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
                }
        }
       done:
-       request.count = dma->buf_count;
-       DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
-
-       if (copy_to_user(argp, &request, sizeof(request)))
-               return -EFAULT;
+       request->count = dma->buf_count;
+       DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
 
        return retcode;
 }
index 61ad986baa8d7a7cadf3e99d25f9070db02b63ec..17fe69e7bfc19a4b69b2577402e781c93784e4db 100644 (file)
@@ -131,7 +131,7 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev)
  * Get per-context SAREA.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx_priv_map structure.
  * \return zero on success or a negative number on failure.
@@ -139,22 +139,16 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev)
  * Gets the map from drm_device::ctx_idr with the handle specified and
  * returns its handle.
  */
-int drm_getsareactx(struct inode *inode, struct file *filp,
-                   unsigned int cmd, unsigned long arg)
+int drm_getsareactx(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_ctx_priv_map __user *argp = (void __user *)arg;
-       struct drm_ctx_priv_map request;
+       struct drm_ctx_priv_map *request = data;
        struct drm_map *map;
        struct drm_map_list *_entry;
 
-       if (copy_from_user(&request, argp, sizeof(request)))
-               return -EFAULT;
-
        mutex_lock(&dev->struct_mutex);
 
-       map = idr_find(&dev->ctx_idr, request.ctx_id);
+       map = idr_find(&dev->ctx_idr, request->ctx_id);
        if (!map) {
                mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
@@ -162,19 +156,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
 
        mutex_unlock(&dev->struct_mutex);
 
-       request.handle = NULL;
+       request->handle = NULL;
        list_for_each_entry(_entry, &dev->maplist, head) {
                if (_entry->map == map) {
-                       request.handle =
+                       request->handle = 
                            (void *)(unsigned long)_entry->user_token;
                        break;
                }
        }
-       if (request.handle == NULL)
+       if (request->handle == NULL)
                return -EINVAL;
 
-       if (copy_to_user(argp, &request, sizeof(request)))
-               return -EFAULT;
        return 0;
 }
 
@@ -182,7 +174,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
  * Set per-context SAREA.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx_priv_map structure.
  * \return zero on success or a negative number on failure.
@@ -190,24 +182,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
  * Searches the mapping specified in \p arg and update the entry in
  * drm_device::ctx_idr with it.
  */
-int drm_setsareactx(struct inode *inode, struct file *filp,
-                   unsigned int cmd, unsigned long arg)
+int drm_setsareactx(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_ctx_priv_map request;
+       struct drm_ctx_priv_map *request = data;
        struct drm_map *map = NULL;
        struct drm_map_list *r_list = NULL;
 
-       if (copy_from_user(&request,
-                          (struct drm_ctx_priv_map __user *) arg,
-                          sizeof(request)))
-               return -EFAULT;
-
        mutex_lock(&dev->struct_mutex);
        list_for_each_entry(r_list, &dev->maplist, head) {
                if (r_list->map
-                   && r_list->user_token == (unsigned long)request.handle)
+                   && r_list->user_token == (unsigned long) request->handle)
                        goto found;
        }
       bad:
@@ -219,10 +204,11 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
        if (!map)
                goto bad;
 
-       if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id)))
+       if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id)))
                goto bad;
 
        mutex_unlock(&dev->struct_mutex);
+
        return 0;
 }
 
@@ -292,34 +278,28 @@ static int drm_context_switch_complete(struct drm_device * dev, int new)
  * Reserve contexts.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx_res structure.
  * \return zero on success or a negative number on failure.
  */
-int drm_resctx(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_resctx(struct drm_device *dev, void *data,
+              struct drm_file *file_priv)
 {
-       struct drm_ctx_res res;
-       struct drm_ctx_res __user *argp = (void __user *)arg;
+       struct drm_ctx_res *res = data;
        struct drm_ctx ctx;
        int i;
 
-       if (copy_from_user(&res, argp, sizeof(res)))
-               return -EFAULT;
-
-       if (res.count >= DRM_RESERVED_CONTEXTS) {
+       if (res->count >= DRM_RESERVED_CONTEXTS) {
                memset(&ctx, 0, sizeof(ctx));
                for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
                        ctx.handle = i;
-                       if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx)))
+                       if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx)))
                                return -EFAULT;
                }
        }
-       res.count = DRM_RESERVED_CONTEXTS;
+       res->count = DRM_RESERVED_CONTEXTS;
 
-       if (copy_to_user(argp, &res, sizeof(res)))
-               return -EFAULT;
        return 0;
 }
 
@@ -327,40 +307,34 @@ int drm_resctx(struct inode *inode, struct file *filp,
  * Add context.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx structure.
  * \return zero on success or a negative number on failure.
  *
  * Get a new handle for the context and copy to userspace.
  */
-int drm_addctx(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_addctx(struct drm_device *dev, void *data,
+              struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_ctx_list *ctx_entry;
-       struct drm_ctx __user *argp = (void __user *)arg;
-       struct drm_ctx ctx;
-
-       if (copy_from_user(&ctx, argp, sizeof(ctx)))
-               return -EFAULT;
+       struct drm_ctx *ctx = data;
 
-       ctx.handle = drm_ctxbitmap_next(dev);
-       if (ctx.handle == DRM_KERNEL_CONTEXT) {
+       ctx->handle = drm_ctxbitmap_next(dev);
+       if (ctx->handle == DRM_KERNEL_CONTEXT) {
                /* Skip kernel's context and get a new one. */
-               ctx.handle = drm_ctxbitmap_next(dev);
+               ctx->handle = drm_ctxbitmap_next(dev);
        }
-       DRM_DEBUG("%d\n", ctx.handle);
-       if (ctx.handle == -1) {
+       DRM_DEBUG("%d\n", ctx->handle);
+       if (ctx->handle == -1) {
                DRM_DEBUG("Not enough free contexts.\n");
                /* Should this return -EBUSY instead? */
                return -ENOMEM;
        }
 
-       if (ctx.handle != DRM_KERNEL_CONTEXT) {
+       if (ctx->handle != DRM_KERNEL_CONTEXT) {
                if (dev->driver->context_ctor)
-                       if (!dev->driver->context_ctor(dev, ctx.handle)) {
+                       if (!dev->driver->context_ctor(dev, ctx->handle)) {
                                DRM_DEBUG("Running out of ctxs or memory.\n");
                                return -ENOMEM;
                        }
@@ -373,21 +347,18 @@ int drm_addctx(struct inode *inode, struct file *filp,
        }
 
        INIT_LIST_HEAD(&ctx_entry->head);
-       ctx_entry->handle = ctx.handle;
-       ctx_entry->tag = priv;
+       ctx_entry->handle = ctx->handle;
+       ctx_entry->tag = file_priv;
 
        mutex_lock(&dev->ctxlist_mutex);
        list_add(&ctx_entry->head, &dev->ctxlist);
        ++dev->ctx_count;
        mutex_unlock(&dev->ctxlist_mutex);
 
-       if (copy_to_user(argp, &ctx, sizeof(ctx)))
-               return -EFAULT;
        return 0;
 }
 
-int drm_modctx(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        /* This does nothing */
        return 0;
@@ -397,25 +368,18 @@ int drm_modctx(struct inode *inode, struct file *filp,
  * Get context.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx structure.
  * \return zero on success or a negative number on failure.
  */
-int drm_getctx(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       struct drm_ctx __user *argp = (void __user *)arg;
-       struct drm_ctx ctx;
-
-       if (copy_from_user(&ctx, argp, sizeof(ctx)))
-               return -EFAULT;
+       struct drm_ctx *ctx = data;
 
        /* This is 0, because we don't handle any context flags */
-       ctx.flags = 0;
+       ctx->flags = 0;
 
-       if (copy_to_user(argp, &ctx, sizeof(ctx)))
-               return -EFAULT;
        return 0;
 }
 
@@ -423,50 +387,40 @@ int drm_getctx(struct inode *inode, struct file *filp,
  * Switch context.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx structure.
  * \return zero on success or a negative number on failure.
  *
  * Calls context_switch().
  */
-int drm_switchctx(struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg)
+int drm_switchctx(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_ctx ctx;
+       struct drm_ctx *ctx = data;
 
-       if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
-               return -EFAULT;
-
-       DRM_DEBUG("%d\n", ctx.handle);
-       return drm_context_switch(dev, dev->last_context, ctx.handle);
+       DRM_DEBUG("%d\n", ctx->handle);
+       return drm_context_switch(dev, dev->last_context, ctx->handle);
 }
 
 /**
  * New context.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx structure.
  * \return zero on success or a negative number on failure.
  *
  * Calls context_switch_complete().
  */
-int drm_newctx(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_newctx(struct drm_device *dev, void *data,
+              struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_ctx ctx;
+       struct drm_ctx *ctx = data;
 
-       if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
-               return -EFAULT;
-
-       DRM_DEBUG("%d\n", ctx.handle);
-       drm_context_switch_complete(dev, ctx.handle);
+       DRM_DEBUG("%d\n", ctx->handle);
+       drm_context_switch_complete(dev, ctx->handle);
 
        return 0;
 }
@@ -475,31 +429,26 @@ int drm_newctx(struct inode *inode, struct file *filp,
  * Remove context.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument pointing to a drm_ctx structure.
  * \return zero on success or a negative number on failure.
  *
  * If not the special kernel context, calls ctxbitmap_free() to free the specified context.
  */
-int drm_rmctx(struct inode *inode, struct file *filp,
-             unsigned int cmd, unsigned long arg)
+int drm_rmctx(struct drm_device *dev, void *data,
+             struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_ctx ctx;
-
-       if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
-               return -EFAULT;
+       struct drm_ctx *ctx = data;
 
-       DRM_DEBUG("%d\n", ctx.handle);
-       if (ctx.handle == DRM_KERNEL_CONTEXT + 1) {
-               priv->remove_auth_on_close = 1;
+       DRM_DEBUG("%d\n", ctx->handle);
+       if (ctx->handle == DRM_KERNEL_CONTEXT + 1) {
+               file_priv->remove_auth_on_close = 1;
        }
-       if (ctx.handle != DRM_KERNEL_CONTEXT) {
+       if (ctx->handle != DRM_KERNEL_CONTEXT) {
                if (dev->driver->context_dtor)
-                       dev->driver->context_dtor(dev, ctx.handle);
-               drm_ctxbitmap_free(dev, ctx.handle);
+                       dev->driver->context_dtor(dev, ctx->handle);
+               drm_ctxbitmap_free(dev, ctx->handle);
        }
 
        mutex_lock(&dev->ctxlist_mutex);
@@ -507,7 +456,7 @@ int drm_rmctx(struct inode *inode, struct file *filp,
                struct drm_ctx_list *pos, *n;
 
                list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
-                       if (pos->handle == ctx.handle) {
+                       if (pos->handle == ctx->handle) {
                                list_del(&pos->head);
                                drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
                                --dev->ctx_count;
index 802fbdbfe1b342b3456800c05a8fcc1286891915..7a8e2fba46781f70ebaac9e1ad3f0c9c2d2bc4da 100644 (file)
@@ -136,7 +136,7 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
 
        buf->waiting = 0;
        buf->pending = 0;
-       buf->filp = NULL;
+       buf->file_priv = NULL;
        buf->used = 0;
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)
@@ -148,11 +148,12 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
 /**
  * Reclaim the buffers.
  *
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  *
- * Frees each buffer associated with \p filp not already on the hardware.
+ * Frees each buffer associated with \p file_priv not already on the hardware.
  */
-void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp)
+void drm_core_reclaim_buffers(struct drm_device *dev,
+                             struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        int i;
@@ -160,7 +161,7 @@ void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp)
        if (!dma)
                return;
        for (i = 0; i < dma->buf_count; i++) {
-               if (dma->buflist[i]->filp == filp) {
+               if (dma->buflist[i]->file_priv == file_priv) {
                        switch (dma->buflist[i]->list) {
                        case DRM_LIST_NONE:
                                drm_free_buffer(dev, dma->buflist[i]);
index d6cdba5644e2df9345588dcc3df831e1e816e170..1839c57663c550e5a487df49b4d040c40e582074 100644 (file)
 /**
  * Allocate drawable ID and memory to store information about it.
  */
-int drm_adddraw(DRM_IOCTL_ARGS)
+int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        unsigned long irqflags;
-       struct drm_draw draw;
+       struct drm_draw *draw = data;
        int new_id = 0;
        int ret;
 
@@ -63,11 +62,9 @@ again:
 
        spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
-       draw.handle = new_id;
+       draw->handle = new_id;
 
-       DRM_DEBUG("%d\n", draw.handle);
-
-       DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw));
+       DRM_DEBUG("%d\n", draw->handle);
 
        return 0;
 }
@@ -75,72 +72,64 @@ again:
 /**
  * Free drawable ID and memory to store information about it.
  */
-int drm_rmdraw(DRM_IOCTL_ARGS)
+int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       struct drm_draw draw;
+       struct drm_draw *draw = data;
        unsigned long irqflags;
 
-       DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data,
-                                sizeof(draw));
-
        spin_lock_irqsave(&dev->drw_lock, irqflags);
 
-       drm_free(drm_get_drawable_info(dev, draw.handle),
+       drm_free(drm_get_drawable_info(dev, draw->handle),
                 sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
 
-       idr_remove(&dev->drw_idr, draw.handle);
+       idr_remove(&dev->drw_idr, draw->handle);
 
        spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-       DRM_DEBUG("%d\n", draw.handle);
+       DRM_DEBUG("%d\n", draw->handle);
        return 0;
 }
 
-int drm_update_drawable_info(DRM_IOCTL_ARGS)
+int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       struct drm_update_draw update;
+       struct drm_update_draw *update = data;
        unsigned long irqflags;
        struct drm_clip_rect *rects;
        struct drm_drawable_info *info;
        int err;
 
-       DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data,
-                                sizeof(update));
-
-       info = idr_find(&dev->drw_idr, update.handle);
+       info = idr_find(&dev->drw_idr, update->handle);
        if (!info) {
                info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS);
                if (!info)
                        return -ENOMEM;
-               if (IS_ERR(idr_replace(&dev->drw_idr, info, update.handle))) {
-                       DRM_ERROR("No such drawable %d\n", update.handle);
+               if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
+                       DRM_ERROR("No such drawable %d\n", update->handle);
                        drm_free(info, sizeof(*info), DRM_MEM_BUFS);
                        return -EINVAL;
                }
        }
 
-       switch (update.type) {
+       switch (update->type) {
        case DRM_DRAWABLE_CLIPRECTS:
-               if (update.num != info->num_rects) {
-                       rects = drm_alloc(update.num * sizeof(struct drm_clip_rect),
+               if (update->num != info->num_rects) {
+                       rects = drm_alloc(update->num * sizeof(struct drm_clip_rect),
                                         DRM_MEM_BUFS);
                } else
                        rects = info->rects;
 
-               if (update.num && !rects) {
+               if (update->num && !rects) {
                        DRM_ERROR("Failed to allocate cliprect memory\n");
-                       err = DRM_ERR(ENOMEM);
+                       err = -ENOMEM;
                        goto error;
                }
 
-               if (update.num && DRM_COPY_FROM_USER(rects,
+               if (update->num && DRM_COPY_FROM_USER(rects,
                                                     (struct drm_clip_rect __user *)
-                                                    (unsigned long)update.data,
-                                                    update.num *
+                                                    (unsigned long)update->data,
+                                                    update->num *
                                                     sizeof(*rects))) {
                        DRM_ERROR("Failed to copy cliprects from userspace\n");
-                       err = DRM_ERR(EFAULT);
+                       err = -EFAULT;
                        goto error;
                }
 
@@ -152,23 +141,23 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS)
                }
 
                info->rects = rects;
-               info->num_rects = update.num;
+               info->num_rects = update->num;
 
                spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
                DRM_DEBUG("Updated %d cliprects for drawable %d\n",
-                         info->num_rects, update.handle);
+                         info->num_rects, update->handle);
                break;
        default:
-               DRM_ERROR("Invalid update type %d\n", update.type);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("Invalid update type %d\n", update->type);
+               return -EINVAL;
        }
 
        return 0;
 
 error:
        if (rects != info->rects)
-               drm_free(rects, update.num * sizeof(struct drm_clip_rect),
+               drm_free(rects, update->num * sizeof(struct drm_clip_rect),
                         DRM_MEM_BUFS);
 
        return err;
index 19994cd865def31db2ef6f487e6513276336179d..72668b15e5ce2a5a8db7aedce9b73691762a8f05 100644 (file)
 #include "drmP.h"
 #include "drm_core.h"
 
-static int drm_version(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg);
+static int drm_version(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
 
 /** Ioctl table */
-static drm_ioctl_desc_t drm_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0},
-       [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0},
-       [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0},
-       [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0},
-       [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0},
-       [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0},
-       [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-
-       [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, DRM_AUTH},
-
-       [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH},
-
-       [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, DRM_AUTH},
-
-       [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-
-       [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, DRM_AUTH},
-
-       [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, DRM_AUTH},
-
-       [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, DRM_AUTH},
+static struct drm_ioctl_desc drm_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
        /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
-       [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = {NULL, DRM_AUTH},
+       DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH),
 
-       [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+       DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
 #if __OS_HAS_AGP
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 #endif
 
-       [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+       DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
-       [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+       DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
 
-       [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+       DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 };
 
 #define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )
@@ -224,7 +225,7 @@ int drm_lastclose(struct drm_device * dev)
 
        if (dev->lock.hw_lock) {
                dev->sigdata.lock = dev->lock.hw_lock = NULL;   /* SHM removed */
-               dev->lock.filp = NULL;
+               dev->lock.file_priv = NULL;
                wake_up_interruptible(&dev->lock.lock_queue);
        }
        mutex_unlock(&dev->struct_mutex);
@@ -418,27 +419,19 @@ module_exit(drm_core_exit);
  *
  * Fills in the version information in \p arg.
  */
-static int drm_version(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg)
+static int drm_version(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_version __user *argp = (void __user *)arg;
-       struct drm_version version;
+       struct drm_version *version = data;
        int len;
 
-       if (copy_from_user(&version, argp, sizeof(version)))
-               return -EFAULT;
+       version->version_major = dev->driver->major;
+       version->version_minor = dev->driver->minor;
+       version->version_patchlevel = dev->driver->patchlevel;
+       DRM_COPY(version->name, dev->driver->name);
+       DRM_COPY(version->date, dev->driver->date);
+       DRM_COPY(version->desc, dev->driver->desc);
 
-       version.version_major = dev->driver->major;
-       version.version_minor = dev->driver->minor;
-       version.version_patchlevel = dev->driver->patchlevel;
-       DRM_COPY(version.name, dev->driver->name);
-       DRM_COPY(version.date, dev->driver->date);
-       DRM_COPY(version.desc, dev->driver->desc);
-
-       if (copy_to_user(argp, &version, sizeof(version)))
-               return -EFAULT;
        return 0;
 }
 
@@ -446,7 +439,7 @@ static int drm_version(struct inode *inode, struct file *filp,
  * Called whenever a process performs an ioctl on /dev/drm.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument.
  * \return zero on success or negative number on failure.
@@ -457,21 +450,22 @@ static int drm_version(struct inode *inode, struct file *filp,
 int drm_ioctl(struct inode *inode, struct file *filp,
              unsigned int cmd, unsigned long arg)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       drm_ioctl_desc_t *ioctl;
+       struct drm_file *file_priv = filp->private_data;
+       struct drm_device *dev = file_priv->head->dev;
+       struct drm_ioctl_desc *ioctl;
        drm_ioctl_t *func;
        unsigned int nr = DRM_IOCTL_NR(cmd);
        int retcode = -EINVAL;
+       char *kdata = NULL;
 
        atomic_inc(&dev->ioctl_count);
        atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
-       ++priv->ioctl_count;
+       ++file_priv->ioctl_count;
 
        DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
                  current->pid, cmd, nr,
-                 (long)old_encode_dev(priv->head->device),
-                 priv->authenticated);
+                 (long)old_encode_dev(file_priv->head->device),
+                 file_priv->authenticated);
 
        if ((nr >= DRM_CORE_IOCTL_COUNT) &&
            ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
@@ -489,18 +483,40 @@ int drm_ioctl(struct inode *inode, struct file *filp,
        if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
                func = dev->driver->dma_ioctl;
 
+
        if (!func) {
                DRM_DEBUG("no function\n");
                retcode = -EINVAL;
        } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
-                  ((ioctl->flags & DRM_AUTH) && !priv->authenticated) ||
-                  ((ioctl->flags & DRM_MASTER) && !priv->master)) {
+                  ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
+                  ((ioctl->flags & DRM_MASTER) && !file_priv->master)) {
                retcode = -EACCES;
        } else {
-               retcode = func(inode, filp, cmd, arg);
+               if (cmd & (IOC_IN | IOC_OUT)) {
+                       kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+                       if (!kdata)
+                               return -ENOMEM;
+               }
+
+               if (cmd & IOC_IN) {
+                       if (copy_from_user(kdata, (void __user *)arg,
+                                          _IOC_SIZE(cmd)) != 0) {
+                               retcode = -EACCES;
+                               goto err_i1;
+                       }
+               }
+               retcode = func(dev, kdata, file_priv);
+
+               if (cmd & IOC_OUT) {
+                       if (copy_to_user((void __user *)arg, kdata,
+                                        _IOC_SIZE(cmd)) != 0)
+                               retcode = -EACCES;
+               }
        }
 
       err_i1:
+       if (kdata)
+               kfree(kdata);
        atomic_dec(&dev->ioctl_count);
        if (retcode)
                DRM_DEBUG("ret = %x\n", retcode);
index 7bc51bac450d70210fee213275536148ebc8654b..f383fc37190c1a1d2a3a18396adda4d130a6b3f4 100644 (file)
@@ -242,6 +242,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
        memset(priv, 0, sizeof(*priv));
        filp->private_data = priv;
+       priv->filp = filp;
        priv->uid = current->euid;
        priv->pid = current->pid;
        priv->minor = minor;
@@ -312,7 +313,7 @@ EXPORT_SYMBOL(drm_fasync);
  * Release file.
  *
  * \param inode device inode
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \return zero on success or a negative number on failure.
  *
  * If the hardware lock is held then free it, and take it again for the kernel
@@ -322,29 +323,28 @@ EXPORT_SYMBOL(drm_fasync);
  */
 int drm_release(struct inode *inode, struct file *filp)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev;
+       struct drm_file *file_priv = filp->private_data;
+       struct drm_device *dev = file_priv->head->dev;
        int retcode = 0;
 
        lock_kernel();
-       dev = priv->head->dev;
 
        DRM_DEBUG("open_count = %d\n", dev->open_count);
 
        if (dev->driver->preclose)
-               dev->driver->preclose(dev, filp);
+               dev->driver->preclose(dev, file_priv);
 
        /* ========================================================
         * Begin inline drm_release
         */
 
        DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
-                 current->pid, (long)old_encode_dev(priv->head->device),
+                 current->pid, (long)old_encode_dev(file_priv->head->device),
                  dev->open_count);
 
        if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
-               if (drm_i_have_hw_lock(filp)) {
-                       dev->driver->reclaim_buffers_locked(dev, filp);
+               if (drm_i_have_hw_lock(dev, file_priv)) {
+                       dev->driver->reclaim_buffers_locked(dev, file_priv);
                } else {
                        unsigned long _end=jiffies + 3*DRM_HZ;
                        int locked = 0;
@@ -370,7 +370,7 @@ int drm_release(struct inode *inode, struct file *filp)
                                          "\tI will go on reclaiming the buffers anyway.\n");
                        }
 
-                       dev->driver->reclaim_buffers_locked(dev, filp);
+                       dev->driver->reclaim_buffers_locked(dev, file_priv);
                        drm_idlelock_release(&dev->lock);
                }
        }
@@ -378,12 +378,12 @@ int drm_release(struct inode *inode, struct file *filp)
        if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
 
                drm_idlelock_take(&dev->lock);
-               dev->driver->reclaim_buffers_idlelocked(dev, filp);
+               dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
                drm_idlelock_release(&dev->lock);
 
        }
 
-       if (drm_i_have_hw_lock(filp)) {
+       if (drm_i_have_hw_lock(dev, file_priv)) {
                DRM_DEBUG("File %p released, freeing lock for context %d\n",
                          filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
 
@@ -394,7 +394,7 @@ int drm_release(struct inode *inode, struct file *filp)
 
        if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
            !dev->driver->reclaim_buffers_locked) {
-               dev->driver->reclaim_buffers(dev, filp);
+               dev->driver->reclaim_buffers(dev, file_priv);
        }
 
        drm_fasync(-1, filp, 0);
@@ -404,7 +404,7 @@ int drm_release(struct inode *inode, struct file *filp)
                struct drm_ctx_list *pos, *n;
 
                list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
-                       if (pos->tag == priv &&
+                       if (pos->tag == file_priv &&
                            pos->handle != DRM_KERNEL_CONTEXT) {
                                if (dev->driver->context_dtor)
                                        dev->driver->context_dtor(dev,
@@ -421,18 +421,18 @@ int drm_release(struct inode *inode, struct file *filp)
        mutex_unlock(&dev->ctxlist_mutex);
 
        mutex_lock(&dev->struct_mutex);
-       if (priv->remove_auth_on_close == 1) {
+       if (file_priv->remove_auth_on_close == 1) {
                struct drm_file *temp;
 
                list_for_each_entry(temp, &dev->filelist, lhead)
                        temp->authenticated = 0;
        }
-       list_del(&priv->lhead);
+       list_del(&file_priv->lhead);
        mutex_unlock(&dev->struct_mutex);
 
        if (dev->driver->postclose)
-               dev->driver->postclose(dev, priv);
-       drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+               dev->driver->postclose(dev, file_priv);
+       drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES);
 
        /* ========================================================
         * End inline drm_release
index 462f46f2049a4e7f15437fec760af2b885be5762..2286f3312c5c0cbe27d1b4daa3803c1b1279b339 100644 (file)
@@ -1040,7 +1040,7 @@ drm_ioctl_compat_t *drm_compat_ioctls[] = {
  * Called whenever a 32-bit process running under a 64-bit kernel
  * performs an ioctl on /dev/drm.
  *
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument.
  * \return zero on success or negative number on failure.
index b195e102e73797b2c6a316bdbe583091ced3dabe..d9be14624526e9553279f61f9c788526c6562894 100644 (file)
  * Get the bus id.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_unique structure.
  * \return zero on success or a negative number on failure.
  *
  * Copies the bus id from drm_device::unique into user space.
  */
-int drm_getunique(struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg)
+int drm_getunique(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_unique __user *argp = (void __user *)arg;
-       struct drm_unique u;
+       struct drm_unique *u = data;
 
-       if (copy_from_user(&u, argp, sizeof(u)))
-               return -EFAULT;
-       if (u.unique_len >= dev->unique_len) {
-               if (copy_to_user(u.unique, dev->unique, dev->unique_len))
+       if (u->unique_len >= dev->unique_len) {
+               if (copy_to_user(u->unique, dev->unique, dev->unique_len))
                        return -EFAULT;
        }
-       u.unique_len = dev->unique_len;
-       if (copy_to_user(argp, &u, sizeof(u)))
-               return -EFAULT;
+       u->unique_len = dev->unique_len;
+
        return 0;
 }
 
@@ -73,7 +67,7 @@ int drm_getunique(struct inode *inode, struct file *filp,
  * Set the bus id.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_unique structure.
  * \return zero on success or a negative number on failure.
@@ -83,28 +77,23 @@ int drm_getunique(struct inode *inode, struct file *filp,
  * in interface version 1.1 and will return EBUSY when setversion has requested
  * version 1.1 or greater.
  */
-int drm_setunique(struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg)
+int drm_setunique(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_unique u;
+       struct drm_unique *u = data;
        int domain, bus, slot, func, ret;
 
        if (dev->unique_len || dev->unique)
                return -EBUSY;
 
-       if (copy_from_user(&u, (struct drm_unique __user *) arg, sizeof(u)))
-               return -EFAULT;
-
-       if (!u.unique_len || u.unique_len > 1024)
+       if (!u->unique_len || u->unique_len > 1024)
                return -EINVAL;
 
-       dev->unique_len = u.unique_len;
-       dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+       dev->unique_len = u->unique_len;
+       dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
        if (!dev->unique)
                return -ENOMEM;
-       if (copy_from_user(dev->unique, u.unique, dev->unique_len))
+       if (copy_from_user(dev->unique, u->unique, dev->unique_len))
                return -EFAULT;
 
        dev->unique[dev->unique_len] = '\0';
@@ -123,7 +112,7 @@ int drm_setunique(struct inode *inode, struct file *filp,
         */
        ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
        if (ret != 3)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        domain = bus >> 8;
        bus &= 0xff;
 
@@ -172,7 +161,7 @@ static int drm_set_busid(struct drm_device * dev)
  * Get a mapping information.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_map structure.
  *
@@ -181,21 +170,16 @@ static int drm_set_busid(struct drm_device * dev)
  * Searches for the mapping with the specified offset and copies its information
  * into userspace
  */
-int drm_getmap(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_getmap(struct drm_device *dev, void *data,
+              struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_map __user *argp = (void __user *)arg;
-       struct drm_map map;
+       struct drm_map *map = data;
        struct drm_map_list *r_list = NULL;
        struct list_head *list;
        int idx;
        int i;
 
-       if (copy_from_user(&map, argp, sizeof(map)))
-               return -EFAULT;
-       idx = map.offset;
+       idx = map->offset;
 
        mutex_lock(&dev->struct_mutex);
        if (idx < 0) {
@@ -216,16 +200,14 @@ int drm_getmap(struct inode *inode, struct file *filp,
                return -EINVAL;
        }
 
-       map.offset = r_list->map->offset;
-       map.size = r_list->map->size;
-       map.type = r_list->map->type;
-       map.flags = r_list->map->flags;
-       map.handle = (void *)(unsigned long)r_list->user_token;
-       map.mtrr = r_list->map->mtrr;
+       map->offset = r_list->map->offset;
+       map->size = r_list->map->size;
+       map->type = r_list->map->type;
+       map->flags = r_list->map->flags;
+       map->handle = (void *)(unsigned long) r_list->user_token;
+       map->mtrr = r_list->map->mtrr;
        mutex_unlock(&dev->struct_mutex);
 
-       if (copy_to_user(argp, &map, sizeof(map)))
-               return -EFAULT;
        return 0;
 }
 
@@ -233,7 +215,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
  * Get client information.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_client structure.
  *
@@ -242,20 +224,15 @@ int drm_getmap(struct inode *inode, struct file *filp,
  * Searches for the client with the specified index and copies its information
  * into userspace
  */
-int drm_getclient(struct inode *inode, struct file *filp,
-                 unsigned int cmd, unsigned long arg)
+int drm_getclient(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_client __user *argp = (struct drm_client __user *)arg;
-       struct drm_client client;
+       struct drm_client *client = data;
        struct drm_file *pt;
        int idx;
        int i;
 
-       if (copy_from_user(&client, argp, sizeof(client)))
-               return -EFAULT;
-       idx = client.idx;
+       idx = client->idx;
        mutex_lock(&dev->struct_mutex);
        
        if (list_empty(&dev->filelist)) {
@@ -269,15 +246,13 @@ int drm_getclient(struct inode *inode, struct file *filp,
                        break;
        }
 
-       client.auth = pt->authenticated;
-       client.pid = pt->pid;
-       client.uid = pt->uid;
-       client.magic = pt->magic;
-       client.iocs = pt->ioctl_count;
+       client->auth = pt->authenticated;
+       client->pid = pt->pid;
+       client->uid = pt->uid;
+       client->magic = pt->magic;
+       client->iocs = pt->ioctl_count;
        mutex_unlock(&dev->struct_mutex);
 
-       if (copy_to_user(argp, &client, sizeof(client)))
-               return -EFAULT;
        return 0;
 }
 
@@ -285,39 +260,35 @@ int drm_getclient(struct inode *inode, struct file *filp,
  * Get statistics information.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_stats structure.
  *
  * \return zero on success or a negative number on failure.
  */
-int drm_getstats(struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg)
+int drm_getstats(struct drm_device *dev, void *data,
+                struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_stats stats;
+       struct drm_stats *stats = data;
        int i;
 
-       memset(&stats, 0, sizeof(stats));
+       memset(stats, 0, sizeof(stats));
 
        mutex_lock(&dev->struct_mutex);
 
        for (i = 0; i < dev->counters; i++) {
                if (dev->types[i] == _DRM_STAT_LOCK)
-                       stats.data[i].value
-                           (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
+                       stats->data[i].value =
+                           (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
                else
-                       stats.data[i].value = atomic_read(&dev->counts[i]);
-               stats.data[i].type = dev->types[i];
+                       stats->data[i].value = atomic_read(&dev->counts[i]);
+               stats->data[i].type = dev->types[i];
        }
 
-       stats.count = dev->counters;
+       stats->count = dev->counters;
 
        mutex_unlock(&dev->struct_mutex);
 
-       if (copy_to_user((struct drm_stats __user *) arg, &stats, sizeof(stats)))
-               return -EFAULT;
        return 0;
 }
 
@@ -325,64 +296,59 @@ int drm_getstats(struct inode *inode, struct file *filp,
  * Setversion ioctl.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_lock structure.
  * \return zero on success or negative number on failure.
  *
  * Sets the requested interface version
  */
-int drm_setversion(DRM_IOCTL_ARGS)
+int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       struct drm_set_version sv;
-       struct drm_set_version retv;
-       int if_version;
-       struct drm_set_version __user *argp = (void __user *)data;
-       int ret;
-
-       if (copy_from_user(&sv, argp, sizeof(sv)))
-               return -EFAULT;
-
-       retv.drm_di_major = DRM_IF_MAJOR;
-       retv.drm_di_minor = DRM_IF_MINOR;
-       retv.drm_dd_major = dev->driver->major;
-       retv.drm_dd_minor = dev->driver->minor;
-
-       if (copy_to_user(argp, &retv, sizeof(retv)))
-               return -EFAULT;
-
-       if (sv.drm_di_major != -1) {
-               if (sv.drm_di_major != DRM_IF_MAJOR ||
-                   sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
-                       return -EINVAL;
-               if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
+       struct drm_set_version *sv = data;
+       int if_version, retcode = 0;
+
+       if (sv->drm_di_major != -1) {
+               if (sv->drm_di_major != DRM_IF_MAJOR ||
+                   sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) {
+                       retcode = -EINVAL;
+                       goto done;
+               }
+               if_version = DRM_IF_VERSION(sv->drm_di_major,
+                                           sv->drm_di_minor);
                dev->if_version = max(if_version, dev->if_version);
-               if (sv.drm_di_minor >= 1) {
+               if (sv->drm_di_minor >= 1) {
                        /*
                         * Version 1.1 includes tying of DRM to specific device
                         */
-                       ret = drm_set_busid(dev);
-                       if (ret)
-                               return ret;
+                       drm_set_busid(dev);
                }
        }
 
-       if (sv.drm_dd_major != -1) {
-               if (sv.drm_dd_major != dev->driver->major ||
-                   sv.drm_dd_minor < 0
-                   || sv.drm_dd_minor > dev->driver->minor)
-                       return -EINVAL;
+       if (sv->drm_dd_major != -1) {
+               if (sv->drm_dd_major != dev->driver->major ||
+                   sv->drm_dd_minor < 0 || sv->drm_dd_minor >
+                   dev->driver->minor) {
+                       retcode = -EINVAL;
+                       goto done;
+               }
 
                if (dev->driver->set_version)
-                       dev->driver->set_version(dev, &sv);
+                       dev->driver->set_version(dev, sv);
        }
-       return 0;
+
+done:
+       sv->drm_di_major = DRM_IF_MAJOR;
+       sv->drm_di_minor = DRM_IF_MINOR;
+       sv->drm_dd_major = dev->driver->major;
+       sv->drm_dd_minor = dev->driver->minor;
+
+       return retcode;
 }
 
 /** No-op ioctl. */
-int drm_noop(struct inode *inode, struct file *filp, unsigned int cmd,
-            unsigned long arg)
+int drm_noop(struct drm_device *dev, void *data,
+            struct drm_file *file_priv)
 {
        DRM_DEBUG("\n");
        return 0;
index 871d2fde09b33ee3d1c8b48b5b6f5d74af0cdffa..05eae63f85baf173efe6473caccf12f8fde75139 100644 (file)
@@ -41,7 +41,7 @@
  * Get interrupt from bus id.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_irq_busid structure.
  * \return zero on success or a negative number on failure.
  * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
  * to that of the device that this DRM instance attached to.
  */
-int drm_irq_by_busid(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg)
+int drm_irq_by_busid(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_irq_busid __user *argp = (void __user *)arg;
-       struct drm_irq_busid p;
+       struct drm_irq_busid *p = data;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
-       if (copy_from_user(&p, argp, sizeof(p)))
-               return -EFAULT;
-
-       if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
-           (p.busnum & 0xff) != dev->pdev->bus->number ||
-           p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
+       if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
+           (p->busnum & 0xff) != dev->pdev->bus->number ||
+           p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
                return -EINVAL;
 
-       p.irq = dev->irq;
+       p->irq = dev->irq;
+
+       DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
+                 p->irq);
 
-       DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq);
-       if (copy_to_user(argp, &p, sizeof(p)))
-               return -EFAULT;
        return 0;
 }
 
@@ -187,31 +181,27 @@ EXPORT_SYMBOL(drm_irq_uninstall);
  * IRQ control ioctl.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_control structure.
  * \return zero on success or a negative number on failure.
  *
  * Calls irq_install() or irq_uninstall() according to \p arg.
  */
-int drm_control(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+int drm_control(struct drm_device *dev, void *data,
+               struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_control ctl;
+       struct drm_control *ctl = data;
 
        /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
 
-       if (copy_from_user(&ctl, (struct drm_control __user *) arg, sizeof(ctl)))
-               return -EFAULT;
 
-       switch (ctl.func) {
+       switch (ctl->func) {
        case DRM_INST_HANDLER:
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
-                   ctl.irq != dev->irq)
+                   ctl->irq != dev->irq)
                        return -EINVAL;
                return drm_irq_install(dev);
        case DRM_UNINST_HANDLER:
@@ -227,7 +217,7 @@ int drm_control(struct inode *inode, struct file *filp,
  * Wait for VBLANK.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param data user argument, pointing to a drm_wait_vblank structure.
  * \return zero on success or a negative number on failure.
@@ -242,31 +232,25 @@ int drm_control(struct inode *inode, struct file *filp,
  *
  * If a signal is not requested, then calls vblank_wait().
  */
-int drm_wait_vblank(DRM_IOCTL_ARGS)
+int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       union drm_wait_vblank __user *argp = (void __user *)data;
-       union drm_wait_vblank vblwait;
+       union drm_wait_vblank *vblwait = data;
        struct timeval now;
        int ret = 0;
        unsigned int flags, seq;
 
-       if (!dev->irq)
+       if ((!dev->irq) || (!dev->irq_enabled))
                return -EINVAL;
 
-       if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
-               return -EFAULT;
-
-       if (vblwait.request.type &
+       if (vblwait->request.type &
            ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
                DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
-                         vblwait.request.type,
+                         vblwait->request.type,
                          (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
                return -EINVAL;
        }
 
-       flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+       flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
 
        if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
                                    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
@@ -275,10 +259,10 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
        seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
                          : &dev->vbl_received);
 
-       switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
+       switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
        case _DRM_VBLANK_RELATIVE:
-               vblwait.request.sequence += seq;
-               vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+               vblwait->request.sequence += seq;
+               vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
        case _DRM_VBLANK_ABSOLUTE:
                break;
        default:
@@ -286,8 +270,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
        }
 
        if ((flags & _DRM_VBLANK_NEXTONMISS) &&
-           (seq - vblwait.request.sequence) <= (1<<23)) {
-               vblwait.request.sequence = seq + 1;
+           (seq - vblwait->request.sequence) <= (1<<23)) {
+               vblwait->request.sequence = seq + 1;
        }
 
        if (flags & _DRM_VBLANK_SIGNAL) {
@@ -303,12 +287,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
                 * that case
                 */
                list_for_each_entry(vbl_sig, vbl_sigs, head) {
-                       if (vbl_sig->sequence == vblwait.request.sequence
-                           && vbl_sig->info.si_signo == vblwait.request.signal
+                       if (vbl_sig->sequence == vblwait->request.sequence
+                           && vbl_sig->info.si_signo ==
+                           vblwait->request.signal
                            && vbl_sig->task == current) {
                                spin_unlock_irqrestore(&dev->vbl_lock,
                                                       irqflags);
-                               vblwait.reply.sequence = seq;
+                               vblwait->reply.sequence = seq;
                                goto done;
                        }
                }
@@ -330,8 +315,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
                memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
 
-               vbl_sig->sequence = vblwait.request.sequence;
-               vbl_sig->info.si_signo = vblwait.request.signal;
+               vbl_sig->sequence = vblwait->request.sequence;
+               vbl_sig->info.si_signo = vblwait->request.signal;
                vbl_sig->task = current;
 
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -340,25 +325,22 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
-               vblwait.reply.sequence = seq;
+               vblwait->reply.sequence = seq;
        } else {
                if (flags & _DRM_VBLANK_SECONDARY) {
                        if (dev->driver->vblank_wait2)
-                               ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
+                               ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
                } else if (dev->driver->vblank_wait)
                        ret =
                            dev->driver->vblank_wait(dev,
-                                                    &vblwait.request.sequence);
+                                                    &vblwait->request.sequence);
 
                do_gettimeofday(&now);
-               vblwait.reply.tval_sec = now.tv_sec;
-               vblwait.reply.tval_usec = now.tv_usec;
+               vblwait->reply.tval_sec = now.tv_sec;
+               vblwait->reply.tval_usec = now.tv_usec;
        }
 
       done:
-       if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
-               return -EFAULT;
-
        return ret;
 }
 
index c0534b5a8b7885d59ffe738f210cc719c4c004cd..c6b73e744d67baba2fcd96094e3e3748f8738df2 100644 (file)
@@ -41,39 +41,33 @@ static int drm_notifier(void *priv);
  * Lock ioctl.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_lock structure.
  * \return zero on success or negative number on failure.
  *
  * Add the current task to the lock wait queue, and attempt to take to lock.
  */
-int drm_lock(struct inode *inode, struct file *filp,
-            unsigned int cmd, unsigned long arg)
+int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        DECLARE_WAITQUEUE(entry, current);
-       struct drm_lock lock;
+       struct drm_lock *lock = data;
        int ret = 0;
 
-       ++priv->lock_count;
+       ++file_priv->lock_count;
 
-       if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
-               return -EFAULT;
-
-       if (lock.context == DRM_KERNEL_CONTEXT) {
+       if (lock->context == DRM_KERNEL_CONTEXT) {
                DRM_ERROR("Process %d using kernel context %d\n",
-                         current->pid, lock.context);
+                         current->pid, lock->context);
                return -EINVAL;
        }
 
        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
-                 lock.context, current->pid,
-                 dev->lock.hw_lock->lock, lock.flags);
+                 lock->context, current->pid,
+                 dev->lock.hw_lock->lock, lock->flags);
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
-               if (lock.context < 0)
+               if (lock->context < 0)
                        return -EINVAL;
 
        add_wait_queue(&dev->lock.lock_queue, &entry);
@@ -87,8 +81,8 @@ int drm_lock(struct inode *inode, struct file *filp,
                        ret = -EINTR;
                        break;
                }
-               if (drm_lock_take(&dev->lock, lock.context)) {
-                       dev->lock.filp = filp;
+               if (drm_lock_take(&dev->lock, lock->context)) {
+                       dev->lock.file_priv = file_priv;
                        dev->lock.lock_time = jiffies;
                        atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
                        break;  /* Got lock */
@@ -107,7 +101,8 @@ int drm_lock(struct inode *inode, struct file *filp,
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(&dev->lock.lock_queue, &entry);
 
-       DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
+       DRM_DEBUG("%d %s\n", lock->context,
+                 ret ? "interrupted" : "has lock");
        if (ret) return ret;
 
        sigemptyset(&dev->sigmask);
@@ -115,24 +110,26 @@ int drm_lock(struct inode *inode, struct file *filp,
        sigaddset(&dev->sigmask, SIGTSTP);
        sigaddset(&dev->sigmask, SIGTTIN);
        sigaddset(&dev->sigmask, SIGTTOU);
-       dev->sigdata.context = lock.context;
+       dev->sigdata.context = lock->context;
        dev->sigdata.lock = dev->lock.hw_lock;
        block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
 
-       if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
+       if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
                dev->driver->dma_ready(dev);
 
-       if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) {
+       if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
+       {
                if (dev->driver->dma_quiescent(dev)) {
-                       DRM_DEBUG("%d waiting for DMA quiescent\n", lock.context);
-                       return DRM_ERR(EBUSY);
+                       DRM_DEBUG("%d waiting for DMA quiescent\n",
+                                 lock->context);
+                       return -EBUSY;
                }
        }
 
        if (dev->driver->kernel_context_switch &&
-           dev->last_context != lock.context) {
+           dev->last_context != lock->context) {
                dev->driver->kernel_context_switch(dev, dev->last_context,
-                                                  lock.context);
+                                                  lock->context);
        }
 
        return 0;
@@ -142,27 +139,21 @@ int drm_lock(struct inode *inode, struct file *filp,
  * Unlock ioctl.
  *
  * \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param cmd command.
  * \param arg user argument, pointing to a drm_lock structure.
  * \return zero on success or negative number on failure.
  *
  * Transfer and free the lock.
  */
-int drm_unlock(struct inode *inode, struct file *filp,
-              unsigned int cmd, unsigned long arg)
+int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_lock lock;
+       struct drm_lock *lock = data;
        unsigned long irqflags;
 
-       if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
-               return -EFAULT;
-
-       if (lock.context == DRM_KERNEL_CONTEXT) {
+       if (lock->context == DRM_KERNEL_CONTEXT) {
                DRM_ERROR("Process %d using kernel context %d\n",
-                         current->pid, lock.context);
+                         current->pid, lock->context);
                return -EINVAL;
        }
 
@@ -184,7 +175,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
        if (dev->driver->kernel_context_switch_unlock)
                dev->driver->kernel_context_switch_unlock(dev);
        else {
-               if (drm_lock_free(&dev->lock,lock.context)) {
+               if (drm_lock_free(&dev->lock,lock->context)) {
                        /* FIXME: Should really bail out here. */
                }
        }
@@ -257,7 +248,7 @@ static int drm_lock_transfer(struct drm_lock_data *lock_data,
        unsigned int old, new, prev;
        volatile unsigned int *lock = &lock_data->hw_lock->lock;
 
-       lock_data->filp = NULL;
+       lock_data->file_priv = NULL;
        do {
                old = *lock;
                new = context | _DRM_LOCK_HELD;
@@ -390,13 +381,11 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
 EXPORT_SYMBOL(drm_idlelock_release);
 
 
-int drm_i_have_hw_lock(struct file *filp)
+int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-
-       return (priv->lock_count && dev->lock.hw_lock &&
+       return (file_priv->lock_count && dev->lock.hw_lock &&
                _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
-               dev->lock.filp == filp);
+               dev->lock.file_priv == file_priv);
 }
 
 EXPORT_SYMBOL(drm_i_have_hw_lock);
index 0b8d3433386dec992ec031aeb88058f51c4a1e78..114e54e0f61bc8d5f0cc1c7d85d2c72cfa1f9750 100644 (file)
@@ -6,11 +6,6 @@
 #include <linux/interrupt.h>   /* For task queue support */
 #include <linux/delay.h>
 
-/** File pointer type */
-#define DRMFILE                         struct file *
-/** Ioctl arguments */
-#define DRM_IOCTL_ARGS                 struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data
-#define DRM_ERR(d)                     -(d)
 /** Current process ID */
 #define DRM_CURRENTPID                 current->pid
 #define DRM_SUSER(p)                   capable(CAP_SYS_ADMIN)
@@ -33,9 +28,6 @@
 #define DRM_WRITEMEMORYBARRIER()       wmb()
 /** Read/write memory barrier */
 #define DRM_MEMORYBARRIER()            mb()
-/** DRM device local declaration */
-#define DRM_DEVICE     struct drm_file *priv   = filp->private_data; \
-                       struct drm_device *dev  = priv->head->dev
 
 /** IRQ handler arguments and return type and values */
 #define DRM_IRQ_ARGS           int irq, void *arg
@@ -94,8 +86,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
 #define DRM_GET_USER_UNCHECKED(val, uaddr)             \
        __get_user(val, uaddr)
 
-#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
-
 #define DRM_HZ HZ
 
 #define DRM_WAIT_ON( ret, queue, timeout, condition )          \
index 30b200b01314d24291dfa4530548789fb96ebad2..f3593974496c443a76152b849724333f74ce7a2e 100644 (file)
        {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
        {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
index 067d25daaf176d19e29904e33d50ba7e5b202700..eb7fa437355e4068a52d48d2f7e7afbdad9e2f00 100644 (file)
@@ -62,13 +62,8 @@ void drm_sg_cleanup(struct drm_sg_mem * entry)
 # define ScatterHandle(x) (unsigned int)(x)
 #endif
 
-int drm_sg_alloc(struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg)
+int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_scatter_gather __user *argp = (void __user *)arg;
-       struct drm_scatter_gather request;
        struct drm_sg_mem *entry;
        unsigned long pages, i, j;
 
@@ -80,17 +75,13 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
        if (dev->sg)
                return -EINVAL;
 
-       if (copy_from_user(&request, argp, sizeof(request)))
-               return -EFAULT;
-
        entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS);
        if (!entry)
                return -ENOMEM;
 
        memset(entry, 0, sizeof(*entry));
-
-       pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
-       DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages);
+       pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
+       DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
 
        entry->pages = pages;
        entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist),
@@ -142,12 +133,7 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
                SetPageReserved(entry->pagelist[j]);
        }
 
-       request.handle = entry->handle;
-
-       if (copy_to_user(argp, &request, sizeof(request))) {
-               drm_sg_cleanup(entry);
-               return -EFAULT;
-       }
+       request->handle = entry->handle;
 
        dev->sg = entry;
 
@@ -197,27 +183,31 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
        drm_sg_cleanup(entry);
        return -ENOMEM;
 }
+EXPORT_SYMBOL(drm_sg_alloc);
+
 
-int drm_sg_free(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       struct drm_scatter_gather request;
+       struct drm_scatter_gather *request = data;
+
+       return drm_sg_alloc(dev, request);
+
+}
+
+int drm_sg_free(struct drm_device *dev, void *data,
+               struct drm_file *file_priv)
+{
+       struct drm_scatter_gather *request = data;
        struct drm_sg_mem *entry;
 
        if (!drm_core_check_feature(dev, DRIVER_SG))
                return -EINVAL;
 
-       if (copy_from_user(&request,
-                          (struct drm_scatter_gather __user *) arg,
-                          sizeof(request)))
-               return -EFAULT;
-
        entry = dev->sg;
        dev->sg = NULL;
 
-       if (!entry || entry->handle != request.handle)
+       if (!entry || entry->handle != request->handle)
                return -EINVAL;
 
        DRM_DEBUG("sg free virtual  = %p\n", entry->virtual);
index 68e36e51ba0c8cdafa9344bff9063ec018f95963..e8d50af58201825effe532d775362187a90b46fc 100644 (file)
@@ -463,7 +463,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
 /**
  * mmap DMA memory.
  *
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param vma virtual memory area.
  * \return zero on success or a negative number on failure.
  *
@@ -533,7 +533,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
 /**
  * mmap DMA memory.
  *
- * \param filp file pointer.
+ * \param file_priv DRM file private.
  * \param vma virtual memory area.
  * \return zero on success or a negative number on failure.
  *
index cb449999d0efe7438d23b24529ca6df8b7be2c2d..8e841bdee6dc219c067032c7add3b74152f5fa63 100644 (file)
@@ -120,10 +120,9 @@ static const struct file_operations i810_buffer_fops = {
        .fasync = drm_fasync,
 };
 
-static int i810_map_buffer(struct drm_buf * buf, struct file *filp)
+static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
+       struct drm_device *dev = file_priv->head->dev;
        drm_i810_buf_priv_t *buf_priv = buf->dev_private;
        drm_i810_private_t *dev_priv = dev->dev_private;
        const struct file_operations *old_fops;
@@ -133,14 +132,14 @@ static int i810_map_buffer(struct drm_buf * buf, struct file *filp)
                return -EINVAL;
 
        down_write(&current->mm->mmap_sem);
-       old_fops = filp->f_op;
-       filp->f_op = &i810_buffer_fops;
+       old_fops = file_priv->filp->f_op;
+       file_priv->filp->f_op = &i810_buffer_fops;
        dev_priv->mmap_buffer = buf;
-       buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
+       buf_priv->virtual = (void *)do_mmap(file_priv->filp, 0, buf->total,
                                            PROT_READ | PROT_WRITE,
                                            MAP_SHARED, buf->bus_address);
        dev_priv->mmap_buffer = NULL;
-       filp->f_op = old_fops;
+       file_priv->filp->f_op = old_fops;
        if (IS_ERR(buf_priv->virtual)) {
                /* Real error */
                DRM_ERROR("mmap error\n");
@@ -173,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf)
 }
 
 static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
-                              struct file *filp)
+                              struct drm_file *file_priv)
 {
        struct drm_buf *buf;
        drm_i810_buf_priv_t *buf_priv;
@@ -186,13 +185,13 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
                return retcode;
        }
 
-       retcode = i810_map_buffer(buf, filp);
+       retcode = i810_map_buffer(buf, file_priv);
        if (retcode) {
                i810_freelist_put(dev, buf);
                DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
                return retcode;
        }
-       buf->filp = filp;
+       buf->file_priv = file_priv;
        buf_priv = buf->dev_private;
        d->granted = 1;
        d->request_idx = buf->idx;
@@ -380,7 +379,7 @@ static int i810_dma_initialize(struct drm_device * dev,
                i810_dma_cleanup(dev);
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -430,99 +429,29 @@ static int i810_dma_initialize(struct drm_device * dev,
        return 0;
 }
 
-/* i810 DRM version 1.1 used a smaller init structure with different
- * ordering of values than is currently used (drm >= 1.2). There is
- * no defined way to detect the XFree version to correct this problem,
- * however by checking using this procedure we can detect the correct
- * thing to do.
- *
- * #1 Read the Smaller init structure from user-space
- * #2 Verify the overlay_physical is a valid physical address, or NULL
- *    If it isn't then we have a v1.1 client. Fix up params.
- *    If it is, then we have a 1.2 client... get the rest of the data.
- */
-static int i810_dma_init_compat(drm_i810_init_t * init, unsigned long arg)
+static int i810_dma_init(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-
-       /* Get v1.1 init data */
-       if (copy_from_user(init, (drm_i810_pre12_init_t __user *) arg,
-                          sizeof(drm_i810_pre12_init_t))) {
-               return -EFAULT;
-       }
-
-       if ((!init->overlay_physical) || (init->overlay_physical > 4096)) {
-
-               /* This is a v1.2 client, just get the v1.2 init data */
-               DRM_INFO("Using POST v1.2 init.\n");
-               if (copy_from_user(init, (drm_i810_init_t __user *) arg,
-                                  sizeof(drm_i810_init_t))) {
-                       return -EFAULT;
-               }
-       } else {
-
-               /* This is a v1.1 client, fix the params */
-               DRM_INFO("Using PRE v1.2 init.\n");
-               init->pitch_bits = init->h;
-               init->pitch = init->w;
-               init->h = init->overlay_physical;
-               init->w = init->overlay_offset;
-               init->overlay_physical = 0;
-               init->overlay_offset = 0;
-       }
-
-       return 0;
-}
-
-static int i810_dma_init(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i810_private_t *dev_priv;
-       drm_i810_init_t init;
+       drm_i810_init_t *init = data;
        int retcode = 0;
 
-       /* Get only the init func */
-       if (copy_from_user
-           (&init, (void __user *)arg, sizeof(drm_i810_init_func_t)))
-               return -EFAULT;
-
-       switch (init.func) {
-       case I810_INIT_DMA:
-               /* This case is for backward compatibility. It
-                * handles XFree 4.1.0 and 4.2.0, and has to
-                * do some parameter checking as described below.
-                * It will someday go away.
-                */
-               retcode = i810_dma_init_compat(&init, arg);
-               if (retcode)
-                       return retcode;
-
-               dev_priv = drm_alloc(sizeof(drm_i810_private_t),
-                                    DRM_MEM_DRIVER);
-               if (dev_priv == NULL)
-                       return -ENOMEM;
-               retcode = i810_dma_initialize(dev, dev_priv, &init);
-               break;
-
-       default:
+       switch (init->func) {
        case I810_INIT_DMA_1_4:
                DRM_INFO("Using v1.4 init.\n");
-               if (copy_from_user(&init, (drm_i810_init_t __user *) arg,
-                                  sizeof(drm_i810_init_t))) {
-                       return -EFAULT;
-               }
                dev_priv = drm_alloc(sizeof(drm_i810_private_t),
                                     DRM_MEM_DRIVER);
                if (dev_priv == NULL)
                        return -ENOMEM;
-               retcode = i810_dma_initialize(dev, dev_priv, &init);
+               retcode = i810_dma_initialize(dev, dev_priv, init);
                break;
 
        case I810_CLEANUP_DMA:
                DRM_INFO("DMA Cleanup\n");
                retcode = i810_dma_cleanup(dev);
                break;
+       default:
+               return -EINVAL;
        }
 
        return retcode;
@@ -968,7 +897,8 @@ static int i810_flush_queue(struct drm_device * dev)
 }
 
 /* Must be called with the lock held */
-static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
+static void i810_reclaim_buffers(struct drm_device * dev,
+                                struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        int i;
@@ -986,7 +916,7 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
                struct drm_buf *buf = dma->buflist[i];
                drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
-               if (buf->filp == filp && buf_priv) {
+               if (buf->file_priv == file_priv && buf_priv) {
                        int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
                                           I810_BUF_FREE);
 
@@ -998,47 +928,38 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
        }
 }
 
-static int i810_flush_ioctl(struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg)
+static int i810_flush_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        i810_flush_queue(dev);
        return 0;
 }
 
-static int i810_dma_vertex(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg)
+static int i810_dma_vertex(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_device_dma *dma = dev->dma;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
            dev_priv->sarea_priv;
-       drm_i810_vertex_t vertex;
-
-       if (copy_from_user
-           (&vertex, (drm_i810_vertex_t __user *) arg, sizeof(vertex)))
-               return -EFAULT;
+       drm_i810_vertex_t *vertex = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
-                 vertex.idx, vertex.used, vertex.discard);
+                 vertex->idx, vertex->used, vertex->discard);
 
-       if (vertex.idx < 0 || vertex.idx > dma->buf_count)
+       if (vertex->idx < 0 || vertex->idx > dma->buf_count)
                return -EINVAL;
 
        i810_dma_dispatch_vertex(dev,
-                                dma->buflist[vertex.idx],
-                                vertex.discard, vertex.used);
+                                dma->buflist[vertex->idx],
+                                vertex->discard, vertex->used);
 
-       atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
+       atomic_add(vertex->used, &dev->counts[_DRM_STAT_SECONDARY]);
        atomic_inc(&dev->counts[_DRM_STAT_DMA]);
        sarea_priv->last_enqueue = dev_priv->counter - 1;
        sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1046,48 +967,37 @@ static int i810_dma_vertex(struct inode *inode, struct file *filp,
        return 0;
 }
 
-static int i810_clear_bufs(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg)
+static int i810_clear_bufs(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       drm_i810_clear_t clear;
+       drm_i810_clear_t *clear = data;
 
-       if (copy_from_user
-           (&clear, (drm_i810_clear_t __user *) arg, sizeof(clear)))
-               return -EFAULT;
-
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        /* GH: Someone's doing nasty things... */
        if (!dev->dev_private) {
                return -EINVAL;
        }
 
-       i810_dma_dispatch_clear(dev, clear.flags,
-                               clear.clear_color, clear.clear_depth);
+       i810_dma_dispatch_clear(dev, clear->flags,
+                               clear->clear_color, clear->clear_depth);
        return 0;
 }
 
-static int i810_swap_bufs(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg)
+static int i810_swap_bufs(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-
        DRM_DEBUG("i810_swap_bufs\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        i810_dma_dispatch_swap(dev);
        return 0;
 }
 
-static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
-                      unsigned long arg)
+static int i810_getage(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
@@ -1097,46 +1007,39 @@ static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
        return 0;
 }
 
-static int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
-                      unsigned long arg)
+static int i810_getbuf(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        int retcode = 0;
-       drm_i810_dma_t d;
+       drm_i810_dma_t *d = data;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
            dev_priv->sarea_priv;
 
-       if (copy_from_user(&d, (drm_i810_dma_t __user *) arg, sizeof(d)))
-               return -EFAULT;
-
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       d.granted = 0;
+       d->granted = 0;
 
-       retcode = i810_dma_get_buffer(dev, &d, filp);
+       retcode = i810_dma_get_buffer(dev, d, file_priv);
 
        DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
-                 current->pid, retcode, d.granted);
+                 current->pid, retcode, d->granted);
 
-       if (copy_to_user((void __user *) arg, &d, sizeof(d)))
-               return -EFAULT;
        sarea_priv->last_dispatch = (int)hw_status[5];
 
        return retcode;
 }
 
-static int i810_copybuf(struct inode *inode,
-                       struct file *filp, unsigned int cmd, unsigned long arg)
+static int i810_copybuf(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        /* Never copy - 2.4.x doesn't need it */
        return 0;
 }
 
-static int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
-                      unsigned long arg)
+static int i810_docopy(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        /* Never copy - 2.4.x doesn't need it */
        return 0;
@@ -1202,30 +1105,25 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf,
        ADVANCE_LP_RING();
 }
 
-static int i810_dma_mc(struct inode *inode, struct file *filp,
-                      unsigned int cmd, unsigned long arg)
+static int i810_dma_mc(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_device_dma *dma = dev->dma;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
            dev_priv->sarea_priv;
-       drm_i810_mc_t mc;
-
-       if (copy_from_user(&mc, (drm_i810_mc_t __user *) arg, sizeof(mc)))
-               return -EFAULT;
+       drm_i810_mc_t *mc = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (mc.idx >= dma->buf_count || mc.idx < 0)
+       if (mc->idx >= dma->buf_count || mc->idx < 0)
                return -EINVAL;
 
-       i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used,
-                            mc.last_render);
+       i810_dma_dispatch_mc(dev, dma->buflist[mc->idx], mc->used,
+                            mc->last_render);
 
-       atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]);
+       atomic_add(mc->used, &dev->counts[_DRM_STAT_SECONDARY]);
        atomic_inc(&dev->counts[_DRM_STAT_DMA]);
        sarea_priv->last_enqueue = dev_priv->counter - 1;
        sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1233,52 +1131,41 @@ static int i810_dma_mc(struct inode *inode, struct file *filp,
        return 0;
 }
 
-static int i810_rstatus(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg)
+static int i810_rstatus(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
 
        return (int)(((u32 *) (dev_priv->hw_status_page))[4]);
 }
 
-static int i810_ov0_info(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
+static int i810_ov0_info(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
-       drm_i810_overlay_t data;
+       drm_i810_overlay_t *ov = data;
+
+       ov->offset = dev_priv->overlay_offset;
+       ov->physical = dev_priv->overlay_physical;
 
-       data.offset = dev_priv->overlay_offset;
-       data.physical = dev_priv->overlay_physical;
-       if (copy_to_user
-           ((drm_i810_overlay_t __user *) arg, &data, sizeof(data)))
-               return -EFAULT;
        return 0;
 }
 
-static int i810_fstatus(struct inode *inode, struct file *filp,
-                       unsigned int cmd, unsigned long arg)
+static int i810_fstatus(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
        return I810_READ(0x30008);
 }
 
-static int i810_ov0_flip(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
+static int i810_ov0_flip(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        //Tell the overlay to update
        I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000);
@@ -1310,16 +1197,14 @@ static int i810_do_cleanup_pageflip(struct drm_device * dev)
        return 0;
 }
 
-static int i810_flip_bufs(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg)
+static int i810_flip_bufs(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i810_private_t *dev_priv = dev->dev_private;
 
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv->page_flipping)
                i810_do_init_pageflip(dev);
@@ -1345,7 +1230,7 @@ void i810_driver_lastclose(struct drm_device * dev)
        i810_dma_cleanup(dev);
 }
 
-void i810_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i810_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
        if (dev->dev_private) {
                drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1355,9 +1240,10 @@ void i810_driver_preclose(struct drm_device * dev, DRMFILE filp)
        }
 }
 
-void i810_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
+                                       struct drm_file *file_priv)
 {
-       i810_reclaim_buffers(dev, filp);
+       i810_reclaim_buffers(dev, file_priv);
 }
 
 int i810_driver_dma_quiescent(struct drm_device * dev)
@@ -1366,22 +1252,22 @@ int i810_driver_dma_quiescent(struct drm_device * dev)
        return 0;
 }
 
-drm_ioctl_desc_t i810_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_I810_INIT)] = {i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_I810_VERTEX)] = {i810_dma_vertex, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_CLEAR)] = {i810_clear_bufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_FLUSH)] = {i810_flush_ioctl, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_GETAGE)] = {i810_getage, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_GETBUF)] = {i810_getbuf, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_SWAP)] = {i810_swap_bufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_COPY)] = {i810_copybuf, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_DOCOPY)] = {i810_docopy, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_OV0INFO)] = {i810_ov0_info, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_FSTATUS)] = {i810_fstatus, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = {i810_ov0_flip, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_MC)] = {i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_I810_RSTATUS)] = {i810_rstatus, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I810_FLIP)] = {i810_flip_bufs, DRM_AUTH}
+struct drm_ioctl_desc i810_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH)
 };
 
 int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
index 614977dbce455d19a02ae6a586349a87ca38afcc..7a10bb6f2c0f2f6d54160e06316b506506f9c592 100644 (file)
@@ -102,13 +102,8 @@ typedef enum _drm_i810_init_func {
 /* This is the init structure after v1.2 */
 typedef struct _drm_i810_init {
        drm_i810_init_func_t func;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
-       int ring_map_idx;
-       int buffer_map_idx;
-#else
        unsigned int mmio_offset;
        unsigned int buffers_offset;
-#endif
        int sarea_priv_offset;
        unsigned int ring_start;
        unsigned int ring_end;
index 648833844c7fde92c92875e2938c3366d3d45b13..0af45872f67eef3756110faec83b467dd79ad790 100644 (file)
@@ -117,15 +117,16 @@ typedef struct drm_i810_private {
                                /* i810_dma.c */
 extern int i810_driver_dma_quiescent(struct drm_device * dev);
 extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
-                                              struct file *filp);
+                                              struct drm_file *file_priv);
 extern int i810_driver_load(struct drm_device *, unsigned long flags);
 extern void i810_driver_lastclose(struct drm_device * dev);
-extern void i810_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i810_driver_preclose(struct drm_device * dev,
+                                struct drm_file *file_priv);
 extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
-                                              struct file *filp);
+                                              struct drm_file *file_priv);
 extern int i810_driver_device_is_agp(struct drm_device * dev);
 
-extern drm_ioctl_desc_t i810_ioctls[];
+extern struct drm_ioctl_desc i810_ioctls[];
 extern int i810_max_ioctl;
 
 #define I810_BASE(reg)         ((unsigned long) \
index dc20c1a7834eac3ae54d8aad4865e74fbfb59e15..43a1f78712d6cc784f24048d10b9ca71cbc060a9 100644 (file)
@@ -122,10 +122,9 @@ static const struct file_operations i830_buffer_fops = {
        .fasync = drm_fasync,
 };
 
-static int i830_map_buffer(struct drm_buf * buf, struct file *filp)
+static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
+       struct drm_device *dev = file_priv->head->dev;
        drm_i830_buf_priv_t *buf_priv = buf->dev_private;
        drm_i830_private_t *dev_priv = dev->dev_private;
        const struct file_operations *old_fops;
@@ -136,13 +135,13 @@ static int i830_map_buffer(struct drm_buf * buf, struct file *filp)
                return -EINVAL;
 
        down_write(&current->mm->mmap_sem);
-       old_fops = filp->f_op;
-       filp->f_op = &i830_buffer_fops;
+       old_fops = file_priv->filp->f_op;
+       file_priv->filp->f_op = &i830_buffer_fops;
        dev_priv->mmap_buffer = buf;
-       virtual = do_mmap(filp, 0, buf->total, PROT_READ | PROT_WRITE,
+       virtual = do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE,
                          MAP_SHARED, buf->bus_address);
        dev_priv->mmap_buffer = NULL;
-       filp->f_op = old_fops;
+       file_priv->filp->f_op = old_fops;
        if (IS_ERR((void *)virtual)) {  /* ugh */
                /* Real error */
                DRM_ERROR("mmap error\n");
@@ -177,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf)
 }
 
 static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
-                              struct file *filp)
+                              struct drm_file *file_priv)
 {
        struct drm_buf *buf;
        drm_i830_buf_priv_t *buf_priv;
@@ -190,13 +189,13 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
                return retcode;
        }
 
-       retcode = i830_map_buffer(buf, filp);
+       retcode = i830_map_buffer(buf, file_priv);
        if (retcode) {
                i830_freelist_put(dev, buf);
                DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
                return retcode;
        }
-       buf->filp = filp;
+       buf->file_priv = file_priv;
        buf_priv = buf->dev_private;
        d->granted = 1;
        d->request_idx = buf->idx;
@@ -389,7 +388,7 @@ static int i830_dma_initialize(struct drm_device * dev,
                i830_dma_cleanup(dev);
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -451,25 +450,20 @@ static int i830_dma_initialize(struct drm_device * dev,
        return 0;
 }
 
-static int i830_dma_init(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
+static int i830_dma_init(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i830_private_t *dev_priv;
-       drm_i830_init_t init;
+       drm_i830_init_t *init = data;
        int retcode = 0;
 
-       if (copy_from_user(&init, (void *__user)arg, sizeof(init)))
-               return -EFAULT;
-
-       switch (init.func) {
+       switch (init->func) {
        case I830_INIT_DMA:
                dev_priv = drm_alloc(sizeof(drm_i830_private_t),
                                     DRM_MEM_DRIVER);
                if (dev_priv == NULL)
                        return -ENOMEM;
-               retcode = i830_dma_initialize(dev, dev_priv, &init);
+               retcode = i830_dma_initialize(dev, dev_priv, init);
                break;
        case I830_CLEANUP_DMA:
                retcode = i830_dma_cleanup(dev);
@@ -1248,7 +1242,7 @@ static int i830_flush_queue(struct drm_device * dev)
 }
 
 /* Must be called with the lock held */
-static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
+static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        int i;
@@ -1266,7 +1260,7 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
                struct drm_buf *buf = dma->buflist[i];
                drm_i830_buf_priv_t *buf_priv = buf->dev_private;
 
-               if (buf->filp == filp && buf_priv) {
+               if (buf->file_priv == file_priv && buf_priv) {
                        int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
                                           I830_BUF_FREE);
 
@@ -1278,45 +1272,36 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
        }
 }
 
-static int i830_flush_ioctl(struct inode *inode, struct file *filp,
-                           unsigned int cmd, unsigned long arg)
+static int i830_flush_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        i830_flush_queue(dev);
        return 0;
 }
 
-static int i830_dma_vertex(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg)
+static int i830_dma_vertex(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        struct drm_device_dma *dma = dev->dma;
        drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
            dev_priv->sarea_priv;
-       drm_i830_vertex_t vertex;
-
-       if (copy_from_user
-           (&vertex, (drm_i830_vertex_t __user *) arg, sizeof(vertex)))
-               return -EFAULT;
+       drm_i830_vertex_t *vertex = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
-                 vertex.idx, vertex.used, vertex.discard);
+                 vertex->idx, vertex->used, vertex->discard);
 
-       if (vertex.idx < 0 || vertex.idx > dma->buf_count)
+       if (vertex->idx < 0 || vertex->idx > dma->buf_count)
                return -EINVAL;
 
        i830_dma_dispatch_vertex(dev,
-                                dma->buflist[vertex.idx],
-                                vertex.discard, vertex.used);
+                                dma->buflist[vertex->idx],
+                                vertex->discard, vertex->used);
 
        sarea_priv->last_enqueue = dev_priv->counter - 1;
        sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1324,39 +1309,30 @@ static int i830_dma_vertex(struct inode *inode, struct file *filp,
        return 0;
 }
 
-static int i830_clear_bufs(struct inode *inode, struct file *filp,
-                          unsigned int cmd, unsigned long arg)
+static int i830_clear_bufs(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-       drm_i830_clear_t clear;
-
-       if (copy_from_user
-           (&clear, (drm_i830_clear_t __user *) arg, sizeof(clear)))
-               return -EFAULT;
+       drm_i830_clear_t *clear = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        /* GH: Someone's doing nasty things... */
        if (!dev->dev_private) {
                return -EINVAL;
        }
 
-       i830_dma_dispatch_clear(dev, clear.flags,
-                               clear.clear_color,
-                               clear.clear_depth, clear.clear_depthmask);
+       i830_dma_dispatch_clear(dev, clear->flags,
+                               clear->clear_color,
+                               clear->clear_depth, clear->clear_depthmask);
        return 0;
 }
 
-static int i830_swap_bufs(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg)
+static int i830_swap_bufs(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
-
        DRM_DEBUG("i830_swap_bufs\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        i830_dma_dispatch_swap(dev);
        return 0;
@@ -1386,16 +1362,14 @@ static int i830_do_cleanup_pageflip(struct drm_device * dev)
        return 0;
 }
 
-static int i830_flip_bufs(struct inode *inode, struct file *filp,
-                         unsigned int cmd, unsigned long arg)
+static int i830_flip_bufs(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i830_private_t *dev_priv = dev->dev_private;
 
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv->page_flipping)
                i830_do_init_pageflip(dev);
@@ -1404,11 +1378,9 @@ static int i830_flip_bufs(struct inode *inode, struct file *filp,
        return 0;
 }
 
-static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
-                      unsigned long arg)
+static int i830_getage(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
@@ -1418,58 +1390,50 @@ static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
        return 0;
 }
 
-static int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
-                      unsigned long arg)
+static int i830_getbuf(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        int retcode = 0;
-       drm_i830_dma_t d;
+       drm_i830_dma_t *d = data;
        drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
            dev_priv->sarea_priv;
 
        DRM_DEBUG("getbuf\n");
-       if (copy_from_user(&d, (drm_i830_dma_t __user *) arg, sizeof(d)))
-               return -EFAULT;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       d.granted = 0;
+       d->granted = 0;
 
-       retcode = i830_dma_get_buffer(dev, &d, filp);
+       retcode = i830_dma_get_buffer(dev, d, file_priv);
 
        DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
-                 current->pid, retcode, d.granted);
+                 current->pid, retcode, d->granted);
 
-       if (copy_to_user((void __user *) arg, &d, sizeof(d)))
-               return -EFAULT;
        sarea_priv->last_dispatch = (int)hw_status[5];
 
        return retcode;
 }
 
-static int i830_copybuf(struct inode *inode,
-                       struct file *filp, unsigned int cmd, unsigned long arg)
+static int i830_copybuf(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        /* Never copy - 2.4.x doesn't need it */
        return 0;
 }
 
-static int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
-                      unsigned long arg)
+static int i830_docopy(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
        return 0;
 }
 
-static int i830_getparam(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
+static int i830_getparam(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i830_private_t *dev_priv = dev->dev_private;
-       drm_i830_getparam_t param;
+       drm_i830_getparam_t *param = data;
        int value;
 
        if (!dev_priv) {
@@ -1477,11 +1441,7 @@ static int i830_getparam(struct inode *inode, struct file *filp,
                return -EINVAL;
        }
 
-       if (copy_from_user
-           (&param, (drm_i830_getparam_t __user *) arg, sizeof(param)))
-               return -EFAULT;
-
-       switch (param.param) {
+       switch (param->param) {
        case I830_PARAM_IRQ_ACTIVE:
                value = dev->irq_enabled;
                break;
@@ -1489,7 +1449,7 @@ static int i830_getparam(struct inode *inode, struct file *filp,
                return -EINVAL;
        }
 
-       if (copy_to_user(param.value, &value, sizeof(int))) {
+       if (copy_to_user(param->value, &value, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
        }
@@ -1497,26 +1457,20 @@ static int i830_getparam(struct inode *inode, struct file *filp,
        return 0;
 }
 
-static int i830_setparam(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg)
+static int i830_setparam(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i830_private_t *dev_priv = dev->dev_private;
-       drm_i830_setparam_t param;
+       drm_i830_setparam_t *param = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
                return -EINVAL;
        }
 
-       if (copy_from_user
-           (&param, (drm_i830_setparam_t __user *) arg, sizeof(param)))
-               return -EFAULT;
-
-       switch (param.param) {
+       switch (param->param) {
        case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
-               dev_priv->use_mi_batchbuffer_start = param.value;
+               dev_priv->use_mi_batchbuffer_start = param->value;
                break;
        default:
                return -EINVAL;
@@ -1542,7 +1496,7 @@ void i830_driver_lastclose(struct drm_device * dev)
        i830_dma_cleanup(dev);
 }
 
-void i830_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
        if (dev->dev_private) {
                drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1552,9 +1506,9 @@ void i830_driver_preclose(struct drm_device * dev, DRMFILE filp)
        }
 }
 
-void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv)
 {
-       i830_reclaim_buffers(dev, filp);
+       i830_reclaim_buffers(dev, file_priv);
 }
 
 int i830_driver_dma_quiescent(struct drm_device * dev)
@@ -1563,21 +1517,21 @@ int i830_driver_dma_quiescent(struct drm_device * dev)
        return 0;
 }
 
-drm_ioctl_desc_t i830_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_I830_INIT)] = {i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_I830_VERTEX)] = {i830_dma_vertex, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_CLEAR)] = {i830_clear_bufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_FLUSH)] = {i830_flush_ioctl, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_GETAGE)] = {i830_getage, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_GETBUF)] = {i830_getbuf, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_SWAP)] = {i830_swap_bufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_COPY)] = {i830_copybuf, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_DOCOPY)] = {i830_docopy, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_FLIP)] = {i830_flip_bufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = {i830_irq_emit, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = {i830_irq_wait, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_GETPARAM)] = {i830_getparam, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I830_SETPARAM)] = {i830_setparam, DRM_AUTH}
+struct drm_ioctl_desc i830_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH)
 };
 
 int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
index ddda67956dea3be11c3b52ae0a6defe8b9a59931..db3a9fa83960ec22ebc3f288606e02cdddbcf1b6 100644 (file)
@@ -122,24 +122,25 @@ typedef struct drm_i830_private {
 
 } drm_i830_private_t;
 
-extern drm_ioctl_desc_t i830_ioctls[];
+extern struct drm_ioctl_desc i830_ioctls[];
 extern int i830_max_ioctl;
 
 /* i830_irq.c */
-extern int i830_irq_emit(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
-extern int i830_irq_wait(struct inode *inode, struct file *filp,
-                        unsigned int cmd, unsigned long arg);
+extern int i830_irq_emit(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int i830_irq_wait(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
 
 extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i830_driver_irq_preinstall(struct drm_device * dev);
 extern void i830_driver_irq_postinstall(struct drm_device * dev);
 extern void i830_driver_irq_uninstall(struct drm_device * dev);
 extern int i830_driver_load(struct drm_device *, unsigned long flags);
-extern void i830_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i830_driver_preclose(struct drm_device * dev,
+                                struct drm_file *file_priv);
 extern void i830_driver_lastclose(struct drm_device * dev);
 extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev,
-                                              struct file *filp);
+                                              struct drm_file *file_priv);
 extern int i830_driver_dma_quiescent(struct drm_device * dev);
 extern int i830_driver_device_is_agp(struct drm_device * dev);
 
index a1b5c63c3c3e1c359377123dd4b4c3dd69b46280..76403f4b62000a111d06913fabf6ea5d62ada826 100644 (file)
@@ -114,29 +114,23 @@ static int i830_wait_irq(struct drm_device * dev, int irq_nr)
 
 /* Needs the lock as it touches the ring.
  */
-int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
-                 unsigned long arg)
+int i830_irq_emit(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i830_private_t *dev_priv = dev->dev_private;
-       drm_i830_irq_emit_t emit;
+       drm_i830_irq_emit_t *emit = data;
        int result;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
                return -EINVAL;
        }
 
-       if (copy_from_user
-           (&emit, (drm_i830_irq_emit_t __user *) arg, sizeof(emit)))
-               return -EFAULT;
-
        result = i830_emit_irq(dev);
 
-       if (copy_to_user(emit.irq_seq, &result, sizeof(int))) {
+       if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
        }
@@ -146,24 +140,18 @@ int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
 
 /* Doesn't need the hardware lock.
  */
-int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd,
-                 unsigned long arg)
+int i830_irq_wait(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->head->dev;
        drm_i830_private_t *dev_priv = dev->dev_private;
-       drm_i830_irq_wait_t irqwait;
+       drm_i830_irq_wait_t *irqwait = data; 
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
                return -EINVAL;
        }
 
-       if (copy_from_user(&irqwait, (drm_i830_irq_wait_t __user *) arg,
-                          sizeof(irqwait)))
-               return -EFAULT;
-
-       return i830_wait_irq(dev, irqwait.irq_seq);
+       return i830_wait_irq(dev, irqwait->irq_seq);
 }
 
 /* drm_dma.h hooks
index 8e7d713a5a1588053d7093acbcb583d57a30ac40..e61a43e5b3ac1018ed93873576013578af49270d 100644 (file)
@@ -70,7 +70,7 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
                last_head = ring->head;
        }
 
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 void i915_kernel_lost_context(struct drm_device * dev)
@@ -137,7 +137,7 @@ static int i915_initialize(struct drm_device * dev,
                DRM_ERROR("can not find sarea!\n");
                dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
@@ -145,7 +145,7 @@ static int i915_initialize(struct drm_device * dev,
                dev->dev_private = (void *)dev_priv;
                i915_dma_cleanup(dev);
                DRM_ERROR("can not find mmio map!\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->sarea_priv = (drm_i915_sarea_t *)
@@ -169,7 +169,7 @@ static int i915_initialize(struct drm_device * dev,
                i915_dma_cleanup(dev);
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -200,7 +200,7 @@ static int i915_initialize(struct drm_device * dev,
                        dev->dev_private = (void *)dev_priv;
                        i915_dma_cleanup(dev);
                        DRM_ERROR("Can not allocate hardware status page\n");
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
                dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
                dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
@@ -221,24 +221,24 @@ static int i915_dma_resume(struct drm_device * dev)
 
        if (!dev_priv->sarea) {
                DRM_ERROR("can not find sarea!\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (!dev_priv->mmio_map) {
                DRM_ERROR("can not find mmio map!\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (dev_priv->ring.map.handle == NULL) {
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        /* Program Hardware Status Page */
        if (!dev_priv->hw_status_page) {
                DRM_ERROR("Can not find hardware status page\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
 
@@ -251,23 +251,20 @@ static int i915_dma_resume(struct drm_device * dev)
        return 0;
 }
 
-static int i915_dma_init(DRM_IOCTL_ARGS)
+static int i915_dma_init(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv;
-       drm_i915_init_t init;
+       drm_i915_init_t *init = data;
        int retcode = 0;
 
-       DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data,
-                                sizeof(init));
-
-       switch (init.func) {
+       switch (init->func) {
        case I915_INIT_DMA:
                dev_priv = drm_alloc(sizeof(drm_i915_private_t),
                                     DRM_MEM_DRIVER);
                if (dev_priv == NULL)
-                       return DRM_ERR(ENOMEM);
-               retcode = i915_initialize(dev, dev_priv, &init);
+                       return -ENOMEM;
+               retcode = i915_initialize(dev, dev_priv, init);
                break;
        case I915_CLEANUP_DMA:
                retcode = i915_dma_cleanup(dev);
@@ -276,7 +273,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
                retcode = i915_dma_resume(dev);
                break;
        default:
-               retcode = DRM_ERR(EINVAL);
+               retcode = -EINVAL;
                break;
        }
 
@@ -366,7 +363,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
        RING_LOCALS;
 
        if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        BEGIN_LP_RING((dwords+1)&~1);
 
@@ -374,17 +371,17 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
                int cmd, sz;
 
                if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
 
                if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
 
                OUT_RING(cmd);
 
                while (++i, --sz) {
                        if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
                                                         sizeof(cmd))) {
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        OUT_RING(cmd);
                }
@@ -407,13 +404,13 @@ static int i915_emit_box(struct drm_device * dev,
        RING_LOCALS;
 
        if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
                DRM_ERROR("Bad box %d,%d..%d,%d\n",
                          box.x1, box.y1, box.x2, box.y2);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (IS_I965G(dev)) {
@@ -467,7 +464,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
 
        if (cmd->sz & 0x3) {
                DRM_ERROR("alignment");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        i915_kernel_lost_context(dev);
@@ -502,7 +499,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
 
        if ((batch->start | batch->used) & 0x7) {
                DRM_ERROR("alignment");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        i915_kernel_lost_context(dev);
@@ -598,76 +595,69 @@ static int i915_quiescent(struct drm_device * dev)
        return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
 }
 
-static int i915_flush_ioctl(DRM_IOCTL_ARGS)
+static int i915_flush_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        return i915_quiescent(dev);
 }
 
-static int i915_batchbuffer(DRM_IOCTL_ARGS)
+static int i915_batchbuffer(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
            dev_priv->sarea_priv;
-       drm_i915_batchbuffer_t batch;
+       drm_i915_batchbuffer_t *batch = data;
        int ret;
 
        if (!dev_priv->allow_batchbuffer) {
                DRM_ERROR("Batchbuffer ioctl disabled\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data,
-                                sizeof(batch));
-
        DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
-                 batch.start, batch.used, batch.num_cliprects);
+                 batch->start, batch->used, batch->num_cliprects);
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
-                                                      batch.num_cliprects *
+       if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
+                                                      batch->num_cliprects *
                                                       sizeof(struct drm_clip_rect)))
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
-       ret = i915_dispatch_batchbuffer(dev, &batch);
+       ret = i915_dispatch_batchbuffer(dev, batch);
 
        sarea_priv->last_dispatch = (int)hw_status[5];
        return ret;
 }
 
-static int i915_cmdbuffer(DRM_IOCTL_ARGS)
+static int i915_cmdbuffer(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 *hw_status = dev_priv->hw_status_page;
        drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
            dev_priv->sarea_priv;
-       drm_i915_cmdbuffer_t cmdbuf;
+       drm_i915_cmdbuffer_t *cmdbuf = data;
        int ret;
 
-       DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data,
-                                sizeof(cmdbuf));
-
        DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
-                 cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
+                 cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (cmdbuf.num_cliprects &&
-           DRM_VERIFYAREA_READ(cmdbuf.cliprects,
-                               cmdbuf.num_cliprects *
+       if (cmdbuf->num_cliprects &&
+           DRM_VERIFYAREA_READ(cmdbuf->cliprects,
+                               cmdbuf->num_cliprects *
                                sizeof(struct drm_clip_rect))) {
                DRM_ERROR("Fault accessing cliprects\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
-       ret = i915_dispatch_cmdbuffer(dev, &cmdbuf);
+       ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
        if (ret) {
                DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
                return ret;
@@ -677,33 +667,29 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int i915_flip_bufs(DRM_IOCTL_ARGS)
+static int i915_flip_bufs(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        return i915_dispatch_flip(dev);
 }
 
-static int i915_getparam(DRM_IOCTL_ARGS)
+static int i915_getparam(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_getparam_t param;
+       drm_i915_getparam_t *param = data;
        int value;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data,
-                                sizeof(param));
-
-       switch (param.param) {
+       switch (param->param) {
        case I915_PARAM_IRQ_ACTIVE:
                value = dev->irq ? 1 : 0;
                break;
@@ -714,68 +700,64 @@ static int i915_getparam(DRM_IOCTL_ARGS)
                value = READ_BREADCRUMB(dev_priv);
                break;
        default:
-               DRM_ERROR("Unknown parameter %d\n", param.param);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("Unknown parameter %d\n", param->param);
+               return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
                DRM_ERROR("DRM_COPY_TO_USER failed\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
 }
 
-static int i915_setparam(DRM_IOCTL_ARGS)
+static int i915_setparam(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_setparam_t param;
+       drm_i915_setparam_t *param = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data,
-                                sizeof(param));
-
-       switch (param.param) {
+       switch (param->param) {
        case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
                if (!IS_I965G(dev))
-                       dev_priv->use_mi_batchbuffer_start = param.value;
+                       dev_priv->use_mi_batchbuffer_start = param->value;
                break;
        case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
-               dev_priv->tex_lru_log_granularity = param.value;
+               dev_priv->tex_lru_log_granularity = param->value;
                break;
        case I915_SETPARAM_ALLOW_BATCHBUFFER:
-               dev_priv->allow_batchbuffer = param.value;
+               dev_priv->allow_batchbuffer = param->value;
                break;
        default:
-               DRM_ERROR("unknown parameter %d\n", param.param);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("unknown parameter %d\n", param->param);
+               return -EINVAL;
        }
 
        return 0;
 }
 
-static int i915_set_status_page(DRM_IOCTL_ARGS)
+static int i915_set_status_page(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_hws_addr_t hws;
+       drm_i915_hws_addr_t *hws = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
-       DRM_COPY_FROM_USER_IOCTL(hws, (drm_i915_hws_addr_t __user *) data,
-                       sizeof(hws));
-       printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws.addr);
 
-       dev_priv->status_gfx_addr = hws.addr & (0x1ffff<<12);
+       printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);
+
+       dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
 
-       dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws.addr;
+       dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws->addr;
        dev_priv->hws_map.size = 4*1024;
        dev_priv->hws_map.type = 0;
        dev_priv->hws_map.flags = 0;
@@ -788,7 +770,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
                dev_priv->status_gfx_addr = 0;
                DRM_ERROR("can not ioremap virtual address for"
                                " G33 hw status page\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        dev_priv->hw_status_page = dev_priv->hws_map.handle;
 
@@ -821,32 +803,32 @@ void i915_driver_lastclose(struct drm_device * dev)
        i915_dma_cleanup(dev);
 }
 
-void i915_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
        if (dev->dev_private) {
                drm_i915_private_t *dev_priv = dev->dev_private;
-               i915_mem_release(dev, filp, dev_priv->agp_heap);
+               i915_mem_release(dev, file_priv, dev_priv->agp_heap);
        }
 }
 
-drm_ioctl_desc_t i915_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
-       [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
-       [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
-       [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] = {i915_set_status_page, DRM_AUTH},
+struct drm_ioctl_desc i915_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP,  i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
+       DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE,  i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
+       DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE,  i915_vblank_pipe_get, DRM_AUTH ),
+       DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
index 28b98733beb8ffc7b6522e64fcbf1f2282fa36ce..e064292e703ac7a348f12421a3551e860b866497 100644 (file)
@@ -70,7 +70,7 @@ struct mem_block {
        struct mem_block *prev;
        int start;
        int size;
-       DRMFILE filp;           /* 0: free, -1: heap, other: real files */
+       struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
 };
 
 typedef struct _drm_i915_vbl_swap {
@@ -116,21 +116,24 @@ typedef struct drm_i915_private {
        unsigned int swaps_pending;
 } drm_i915_private_t;
 
-extern drm_ioctl_desc_t i915_ioctls[];
+extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 
                                /* i915_dma.c */
 extern void i915_kernel_lost_context(struct drm_device * dev);
 extern int i915_driver_load(struct drm_device *, unsigned long flags);
 extern void i915_driver_lastclose(struct drm_device * dev);
-extern void i915_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i915_driver_preclose(struct drm_device *dev,
+                                struct drm_file *file_priv);
 extern int i915_driver_device_is_agp(struct drm_device * dev);
 extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
                              unsigned long arg);
 
 /* i915_irq.c */
-extern int i915_irq_emit(DRM_IOCTL_ARGS);
-extern int i915_irq_wait(DRM_IOCTL_ARGS);
+extern int i915_irq_emit(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int i915_irq_wait(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
 
 extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
 extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
@@ -138,18 +141,25 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(struct drm_device * dev);
 extern void i915_driver_irq_postinstall(struct drm_device * dev);
 extern void i915_driver_irq_uninstall(struct drm_device * dev);
-extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
-extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
-extern int i915_vblank_swap(DRM_IOCTL_ARGS);
+extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+extern int i915_vblank_swap(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv);
 
 /* i915_mem.c */
-extern int i915_mem_alloc(DRM_IOCTL_ARGS);
-extern int i915_mem_free(DRM_IOCTL_ARGS);
-extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
-extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
+extern int i915_mem_alloc(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv);
+extern int i915_mem_free(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int i915_mem_init_heap(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv);
+extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
+                                struct drm_file *file_priv);
 extern void i915_mem_takedown(struct mem_block **heap);
 extern void i915_mem_release(struct drm_device * dev,
-                            DRMFILE filp, struct mem_block *heap);
+                            struct drm_file *file_priv, struct mem_block *heap);
 
 #define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, (reg))
 #define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
index bb8e9e9c820156e849cbd6ece7485de88767baff..a443f4a202e3889c1a52adc43ac1d3020a9351e9 100644 (file)
@@ -311,7 +311,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
        DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
                    READ_BREADCRUMB(dev_priv) >= irq_nr);
 
-       if (ret == DRM_ERR(EBUSY)) {
+       if (ret == -EBUSY) {
                DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
                          __FUNCTION__,
                          READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
@@ -330,7 +330,7 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequ
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
@@ -355,28 +355,25 @@ int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
 
 /* Needs the lock as it touches the ring.
  */
-int i915_irq_emit(DRM_IOCTL_ARGS)
+int i915_irq_emit(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_irq_emit_t emit;
+       drm_i915_irq_emit_t *emit = data;
        int result;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
-                                sizeof(emit));
-
        result = i915_emit_irq(dev);
 
-       if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
+       if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
@@ -384,21 +381,18 @@ int i915_irq_emit(DRM_IOCTL_ARGS)
 
 /* Doesn't need the hardware lock.
  */
-int i915_irq_wait(DRM_IOCTL_ARGS)
+int i915_irq_wait(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_irq_wait_t irqwait;
+       drm_i915_irq_wait_t *irqwait = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
-                                sizeof(irqwait));
-
-       return i915_wait_irq(dev, irqwait.irq_seq);
+       return i915_wait_irq(dev, irqwait->irq_seq);
 }
 
 static void i915_enable_interrupt (struct drm_device *dev)
@@ -417,64 +411,60 @@ static void i915_enable_interrupt (struct drm_device *dev)
 
 /* Set the vblank monitor pipe
  */
-int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
+int i915_vblank_pipe_set(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_vblank_pipe_t pipe;
+       drm_i915_vblank_pipe_t *pipe = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
-                                sizeof(pipe));
-
-       if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+       if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
                DRM_ERROR("%s called with invalid pipe 0x%x\n", 
-                         __FUNCTION__, pipe.pipe);
-               return DRM_ERR(EINVAL);
+                         __FUNCTION__, pipe->pipe);
+               return -EINVAL;
        }
 
-       dev_priv->vblank_pipe = pipe.pipe;
+       dev_priv->vblank_pipe = pipe->pipe;
 
        i915_enable_interrupt (dev);
 
        return 0;
 }
 
-int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
+int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_vblank_pipe_t pipe;
+       drm_i915_vblank_pipe_t *pipe = data;
        u16 flag;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        flag = I915_READ(I915REG_INT_ENABLE_R);
-       pipe.pipe = 0;
+       pipe->pipe = 0;
        if (flag & VSYNC_PIPEA_FLAG)
-               pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
+               pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
        if (flag & VSYNC_PIPEB_FLAG)
-               pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
-       DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
-                                sizeof(pipe));
+               pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
+
        return 0;
 }
 
 /**
  * Schedule buffer swap at given vertical blank.
  */
-int i915_vblank_swap(DRM_IOCTL_ARGS)
+int i915_vblank_swap(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_vblank_swap_t swap;
+       drm_i915_vblank_swap_t *swap = data;
        drm_i915_vbl_swap_t *vbl_swap;
        unsigned int pipe, seqtype, curseq;
        unsigned long irqflags;
@@ -482,38 +472,35 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __func__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (dev_priv->sarea_priv->rotation) {
                DRM_DEBUG("Rotation not supported\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
-                                sizeof(swap));
-
-       if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+       if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
                             _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
-               DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
+               return -EINVAL;
        }
 
-       pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+       pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
 
-       seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+       seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
 
        if (!(dev_priv->vblank_pipe & (1 << pipe))) {
                DRM_ERROR("Invalid pipe %d\n", pipe);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        spin_lock_irqsave(&dev->drw_lock, irqflags);
 
-       if (!drm_get_drawable_info(dev, swap.drawable)) {
+       if (!drm_get_drawable_info(dev, swap->drawable)) {
                spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-               DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
-               return DRM_ERR(EINVAL);
+               DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
+               return -EINVAL;
        }
 
        spin_unlock_irqrestore(&dev->drw_lock, irqflags);
@@ -521,14 +508,14 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
        curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
 
        if (seqtype == _DRM_VBLANK_RELATIVE)
-               swap.sequence += curseq;
+               swap->sequence += curseq;
 
-       if ((curseq - swap.sequence) <= (1<<23)) {
-               if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
-                       swap.sequence = curseq + 1;
+       if ((curseq - swap->sequence) <= (1<<23)) {
+               if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
+                       swap->sequence = curseq + 1;
                } else {
                        DRM_DEBUG("Missed target sequence\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
 
@@ -537,9 +524,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
        list_for_each(list, &dev_priv->vbl_swaps.head) {
                vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
 
-               if (vbl_swap->drw_id == swap.drawable &&
+               if (vbl_swap->drw_id == swap->drawable &&
                    vbl_swap->pipe == pipe &&
-                   vbl_swap->sequence == swap.sequence) {
+                   vbl_swap->sequence == swap->sequence) {
                        spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
                        DRM_DEBUG("Already scheduled\n");
                        return 0;
@@ -550,21 +537,21 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
        if (dev_priv->swaps_pending >= 100) {
                DRM_DEBUG("Too many swaps queued\n");
-               return DRM_ERR(EBUSY);
+               return -EBUSY;
        }
 
-       vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
+       vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
 
        if (!vbl_swap) {
                DRM_ERROR("Failed to allocate memory to queue swap\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        DRM_DEBUG("\n");
 
-       vbl_swap->drw_id = swap.drawable;
+       vbl_swap->drw_id = swap->drawable;
        vbl_swap->pipe = pipe;
-       vbl_swap->sequence = swap.sequence;
+       vbl_swap->sequence = swap->sequence;
 
        spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
 
@@ -573,9 +560,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
        spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
 
-       DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
-                              sizeof(swap));
-
        return 0;
 }
 
index 50b4bacef0e01654d4097ac91aaca88209395464..56fb9b30a5d7453aa824a31b1e6ec93c988d5c6d 100644 (file)
@@ -89,7 +89,7 @@ static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
  */
 
 static struct mem_block *split_block(struct mem_block *p, int start, int size,
-                                    DRMFILE filp)
+                                    struct drm_file *file_priv)
 {
        /* Maybe cut off the start of an existing block */
        if (start > p->start) {
@@ -99,7 +99,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
                        goto out;
                newblock->start = start;
                newblock->size = p->size - (start - p->start);
-               newblock->filp = NULL;
+               newblock->file_priv = NULL;
                newblock->next = p->next;
                newblock->prev = p;
                p->next->prev = newblock;
@@ -116,7 +116,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
                        goto out;
                newblock->start = start + size;
                newblock->size = p->size - size;
-               newblock->filp = NULL;
+               newblock->file_priv = NULL;
                newblock->next = p->next;
                newblock->prev = p;
                p->next->prev = newblock;
@@ -126,20 +126,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
 
       out:
        /* Our block is in the middle */
-       p->filp = filp;
+       p->file_priv = file_priv;
        return p;
 }
 
 static struct mem_block *alloc_block(struct mem_block *heap, int size,
-                                    int align2, DRMFILE filp)
+                                    int align2, struct drm_file *file_priv)
 {
        struct mem_block *p;
        int mask = (1 << align2) - 1;
 
        for (p = heap->next; p != heap; p = p->next) {
                int start = (p->start + mask) & ~mask;
-               if (p->filp == NULL && start + size <= p->start + p->size)
-                       return split_block(p, start, size, filp);
+               if (p->file_priv == NULL && start + size <= p->start + p->size)
+                       return split_block(p, start, size, file_priv);
        }
 
        return NULL;
@@ -158,12 +158,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start)
 
 static void free_block(struct mem_block *p)
 {
-       p->filp = NULL;
+       p->file_priv = NULL;
 
-       /* Assumes a single contiguous range.  Needs a special filp in
+       /* Assumes a single contiguous range.  Needs a special file_priv in
         * 'heap' to stop it being subsumed.
         */
-       if (p->next->filp == NULL) {
+       if (p->next->file_priv == NULL) {
                struct mem_block *q = p->next;
                p->size += q->size;
                p->next = q->next;
@@ -171,7 +171,7 @@ static void free_block(struct mem_block *p)
                drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
        }
 
-       if (p->prev->filp == NULL) {
+       if (p->prev->file_priv == NULL) {
                struct mem_block *q = p->prev;
                q->size += p->size;
                q->next = p->next;
@@ -197,18 +197,19 @@ static int init_heap(struct mem_block **heap, int start, int size)
 
        blocks->start = start;
        blocks->size = size;
-       blocks->filp = NULL;
+       blocks->file_priv = NULL;
        blocks->next = blocks->prev = *heap;
 
        memset(*heap, 0, sizeof(**heap));
-       (*heap)->filp = (DRMFILE) - 1;
+       (*heap)->file_priv = (struct drm_file *) - 1;
        (*heap)->next = (*heap)->prev = blocks;
        return 0;
 }
 
 /* Free all blocks associated with the releasing file.
  */
-void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *heap)
+void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv,
+                     struct mem_block *heap)
 {
        struct mem_block *p;
 
@@ -216,17 +217,17 @@ void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *h
                return;
 
        for (p = heap->next; p != heap; p = p->next) {
-               if (p->filp == filp) {
-                       p->filp = NULL;
+               if (p->file_priv == file_priv) {
+                       p->file_priv = NULL;
                        mark_block(dev, p, 0);
                }
        }
 
-       /* Assumes a single contiguous range.  Needs a special filp in
+       /* Assumes a single contiguous range.  Needs a special file_priv in
         * 'heap' to stop it being subsumed.
         */
        for (p = heap->next; p != heap; p = p->next) {
-               while (p->filp == NULL && p->next->filp == NULL) {
+               while (p->file_priv == NULL && p->next->file_priv == NULL) {
                        struct mem_block *q = p->next;
                        p->size += q->size;
                        p->next = q->next;
@@ -267,129 +268,117 @@ static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
 
 /* IOCTL HANDLERS */
 
-int i915_mem_alloc(DRM_IOCTL_ARGS)
+int i915_mem_alloc(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_alloc_t alloc;
+       drm_i915_mem_alloc_t *alloc = data;
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data,
-                                sizeof(alloc));
-
-       heap = get_heap(dev_priv, alloc.region);
+       heap = get_heap(dev_priv, alloc->region);
        if (!heap || !*heap)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
        /* Make things easier on ourselves: all allocations at least
         * 4k aligned.
         */
-       if (alloc.alignment < 12)
-               alloc.alignment = 12;
+       if (alloc->alignment < 12)
+               alloc->alignment = 12;
 
-       block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
+       block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
 
        if (!block)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        mark_block(dev, block, 1);
 
-       if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
+       if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
+                            sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
 }
 
-int i915_mem_free(DRM_IOCTL_ARGS)
+int i915_mem_free(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_free_t memfree;
+       drm_i915_mem_free_t *memfree = data;
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data,
-                                sizeof(memfree));
-
-       heap = get_heap(dev_priv, memfree.region);
+       heap = get_heap(dev_priv, memfree->region);
        if (!heap || !*heap)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
-       block = find_block(*heap, memfree.region_offset);
+       block = find_block(*heap, memfree->region_offset);
        if (!block)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
-       if (block->filp != filp)
-               return DRM_ERR(EPERM);
+       if (block->file_priv != file_priv)
+               return -EPERM;
 
        mark_block(dev, block, 0);
        free_block(block);
        return 0;
 }
 
-int i915_mem_init_heap(DRM_IOCTL_ARGS)
+int i915_mem_init_heap(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_init_heap_t initheap;
+       drm_i915_mem_init_heap_t *initheap = data;
        struct mem_block **heap;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(initheap,
-                                (drm_i915_mem_init_heap_t __user *) data,
-                                sizeof(initheap));
-
-       heap = get_heap(dev_priv, initheap.region);
+       heap = get_heap(dev_priv, initheap->region);
        if (!heap)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
        if (*heap) {
                DRM_ERROR("heap already initialized?");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
-       return init_heap(heap, initheap.start, initheap.size);
+       return init_heap(heap, initheap->start, initheap->size);
 }
 
-int i915_mem_destroy_heap( DRM_IOCTL_ARGS )
+int i915_mem_destroy_heap( struct drm_device *dev, void *data,
+                          struct drm_file *file_priv )
 {
-       DRM_DEVICE;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_destroy_heap_t destroyheap;
+       drm_i915_mem_destroy_heap_t *destroyheap = data;
        struct mem_block **heap;
 
        if ( !dev_priv ) {
                DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data,
-                                 sizeof(destroyheap) );
-
-       heap = get_heap( dev_priv, destroyheap.region );
+       heap = get_heap( dev_priv, destroyheap->region );
        if (!heap) {
                DRM_ERROR("get_heap failed");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
        
        if (!*heap) {
                DRM_ERROR("heap not initialized?");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        i915_mem_takedown( heap );
index 9c73a6e3861b0d18ffb0077ad453519a6369a302..c567c34cda78e27582bcff4a2e562178e62e23a3 100644 (file)
@@ -71,7 +71,7 @@ int mga_do_wait_for_idle(drm_mga_private_t * dev_priv)
        DRM_ERROR("failed!\n");
        DRM_INFO("   status=0x%08x\n", status);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int mga_do_dma_reset(drm_mga_private_t * dev_priv)
@@ -256,7 +256,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr
 
        dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
        if (dev_priv->head == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t));
        SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0);
@@ -267,7 +267,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr
 
                entry = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
                if (entry == NULL)
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
 
                memset(entry, 0, sizeof(drm_mga_freelist_t));
 
@@ -399,7 +399,7 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags)
 
        dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
        if (!dev_priv)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        dev->dev_private = (void *)dev_priv;
        memset(dev_priv, 0, sizeof(drm_mga_private_t));
@@ -578,7 +578,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
                DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n",
                          dev_priv->warp->handle, dev_priv->primary->handle,
                          dev->agp_buffer_map->handle);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        dev_priv->dma_access = MGA_PAGPXFER;
@@ -622,7 +622,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
 
        if (dev->dma == NULL) {
                DRM_ERROR("dev->dma is NULL\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        /* Make drm_addbufs happy by not trying to create a mapping for less
@@ -656,7 +656,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
 
        if (err != 0) {
                DRM_ERROR("Unable to allocate primary DMA region: %d\n", err);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        if (dev_priv->primary->size != dma_bs->primary_size) {
@@ -759,36 +759,30 @@ static int mga_do_dma_bootstrap(struct drm_device * dev,
        return err;
 }
 
-int mga_dma_bootstrap(DRM_IOCTL_ARGS)
+int mga_dma_bootstrap(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_mga_dma_bootstrap_t bootstrap;
+       drm_mga_dma_bootstrap_t *bootstrap = data;
        int err;
        static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 };
        const drm_mga_private_t *const dev_priv =
                (drm_mga_private_t *) dev->dev_private;
 
-       DRM_COPY_FROM_USER_IOCTL(bootstrap,
-                                (drm_mga_dma_bootstrap_t __user *) data,
-                                sizeof(bootstrap));
-
-       err = mga_do_dma_bootstrap(dev, &bootstrap);
+       err = mga_do_dma_bootstrap(dev, bootstrap);
        if (err) {
                mga_do_cleanup_dma(dev, FULL_CLEANUP);
                return err;
        }
 
        if (dev_priv->agp_textures != NULL) {
-               bootstrap.texture_handle = dev_priv->agp_textures->offset;
-               bootstrap.texture_size = dev_priv->agp_textures->size;
+               bootstrap->texture_handle = dev_priv->agp_textures->offset;
+               bootstrap->texture_size = dev_priv->agp_textures->size;
        } else {
-               bootstrap.texture_handle = 0;
-               bootstrap.texture_size = 0;
+               bootstrap->texture_handle = 0;
+               bootstrap->texture_size = 0;
        }
 
-       bootstrap.agp_mode = modes[bootstrap.agp_mode & 0x07];
-       DRM_COPY_TO_USER_IOCTL((drm_mga_dma_bootstrap_t __user *)data,
-                              bootstrap, sizeof(bootstrap));
+       bootstrap->agp_mode = modes[bootstrap->agp_mode & 0x07];
 
        return err;
 }
@@ -826,7 +820,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
        dev_priv->sarea = drm_getsarea(dev);
        if (!dev_priv->sarea) {
                DRM_ERROR("failed to find sarea!\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (!dev_priv->used_new_dma_init) {
@@ -837,29 +831,29 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
                dev_priv->status = drm_core_findmap(dev, init->status_offset);
                if (!dev_priv->status) {
                        DRM_ERROR("failed to find status page!\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
                if (!dev_priv->mmio) {
                        DRM_ERROR("failed to find mmio region!\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
                if (!dev_priv->warp) {
                        DRM_ERROR("failed to find warp microcode region!\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
                if (!dev_priv->primary) {
                        DRM_ERROR("failed to find primary dma region!\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                dev->agp_buffer_token = init->buffers_offset;
                dev->agp_buffer_map =
                    drm_core_findmap(dev, init->buffers_offset);
                if (!dev->agp_buffer_map) {
                        DRM_ERROR("failed to find dma buffer region!\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                drm_core_ioremap(dev_priv->warp, dev);
@@ -877,7 +871,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
             ((dev->agp_buffer_map == NULL) ||
              (dev->agp_buffer_map->handle == NULL)))) {
                DRM_ERROR("failed to ioremap agp regions!\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        ret = mga_warp_install_microcode(dev_priv);
@@ -927,7 +921,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
 
        if (mga_freelist_init(dev, dev_priv) < 0) {
                DRM_ERROR("could not initialize freelist\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        return 0;
@@ -1007,20 +1001,17 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
        return 0;
 }
 
-int mga_dma_init(DRM_IOCTL_ARGS)
+int mga_dma_init(struct drm_device *dev, void *data,
+                struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_mga_init_t init;
+       drm_mga_init_t *init = data;
        int err;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data,
-                                sizeof(init));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       switch (init.func) {
+       switch (init->func) {
        case MGA_INIT_DMA:
-               err = mga_do_init_dma(dev, &init);
+               err = mga_do_init_dma(dev, init);
                if (err) {
                        (void)mga_do_cleanup_dma(dev, FULL_CLEANUP);
                }
@@ -1029,36 +1020,33 @@ int mga_dma_init(DRM_IOCTL_ARGS)
                return mga_do_cleanup_dma(dev, FULL_CLEANUP);
        }
 
-       return DRM_ERR(EINVAL);
+       return -EINVAL;
 }
 
 /* ================================================================
  * Primary DMA stream management
  */
 
-int mga_dma_flush(DRM_IOCTL_ARGS)
+int mga_dma_flush(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-       struct drm_lock lock;
-
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       struct drm_lock *lock = data;
 
-       DRM_COPY_FROM_USER_IOCTL(lock, (struct drm_lock __user *) data,
-                                sizeof(lock));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        DRM_DEBUG("%s%s%s\n",
-                 (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
-                 (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
-                 (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
+                 (lock->flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
+                 (lock->flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
+                 (lock->flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
 
        WRAP_WAIT_WITH_RETURN(dev_priv);
 
-       if (lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
+       if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
                mga_do_dma_flush(dev_priv);
        }
 
-       if (lock.flags & _DRM_LOCK_QUIESCENT) {
+       if (lock->flags & _DRM_LOCK_QUIESCENT) {
 #if MGA_DMA_DEBUG
                int ret = mga_do_wait_for_idle(dev_priv);
                if (ret < 0)
@@ -1072,12 +1060,12 @@ int mga_dma_flush(DRM_IOCTL_ARGS)
        }
 }
 
-int mga_dma_reset(DRM_IOCTL_ARGS)
+int mga_dma_reset(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        return mga_do_dma_reset(dev_priv);
 }
@@ -1086,7 +1074,8 @@ int mga_dma_reset(DRM_IOCTL_ARGS)
  * DMA buffer management
  */
 
-static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
+static int mga_dma_get_buffers(struct drm_device * dev,
+                              struct drm_file *file_priv, struct drm_dma * d)
 {
        struct drm_buf *buf;
        int i;
@@ -1094,61 +1083,56 @@ static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm
        for (i = d->granted_count; i < d->request_count; i++) {
                buf = mga_freelist_get(dev);
                if (!buf)
-                       return DRM_ERR(EAGAIN);
+                       return -EAGAIN;
 
-               buf->filp = filp;
+               buf->file_priv = file_priv;
 
                if (DRM_COPY_TO_USER(&d->request_indices[i],
                                     &buf->idx, sizeof(buf->idx)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
                if (DRM_COPY_TO_USER(&d->request_sizes[i],
                                     &buf->total, sizeof(buf->total)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
 
                d->granted_count++;
        }
        return 0;
 }
 
-int mga_dma_buffers(DRM_IOCTL_ARGS)
+int mga_dma_buffers(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        struct drm_device_dma *dma = dev->dma;
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-       struct drm_dma __user *argp = (void __user *)data;
-       struct drm_dma d;
+       struct drm_dma *d = data;
        int ret = 0;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        /* Please don't send us buffers.
         */
-       if (d.send_count != 0) {
+       if (d->send_count != 0) {
                DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
-                         DRM_CURRENTPID, d.send_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->send_count);
+               return -EINVAL;
        }
 
        /* We'll send you buffers.
         */
-       if (d.request_count < 0 || d.request_count > dma->buf_count) {
+       if (d->request_count < 0 || d->request_count > dma->buf_count) {
                DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
-                         DRM_CURRENTPID, d.request_count, dma->buf_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->request_count, dma->buf_count);
+               return -EINVAL;
        }
 
        WRAP_TEST_WITH_RETURN(dev_priv);
 
-       d.granted_count = 0;
+       d->granted_count = 0;
 
-       if (d.request_count) {
-               ret = mga_dma_get_buffers(filp, dev, &d);
+       if (d->request_count) {
+               ret = mga_dma_get_buffers(dev, file_priv, d);
        }
 
-       DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
        return ret;
 }
 
index 49253affa475ca75eb61212f85c4869ef2c9f96d..cd94c04e31c00cefa787168aa1f33887d091f7a5 100644 (file)
@@ -148,15 +148,20 @@ typedef struct drm_mga_private {
        unsigned int agp_size;
 } drm_mga_private_t;
 
-extern drm_ioctl_desc_t mga_ioctls[];
+extern struct drm_ioctl_desc mga_ioctls[];
 extern int mga_max_ioctl;
 
                                /* mga_dma.c */
-extern int mga_dma_bootstrap(DRM_IOCTL_ARGS);
-extern int mga_dma_init(DRM_IOCTL_ARGS);
-extern int mga_dma_flush(DRM_IOCTL_ARGS);
-extern int mga_dma_reset(DRM_IOCTL_ARGS);
-extern int mga_dma_buffers(DRM_IOCTL_ARGS);
+extern int mga_dma_bootstrap(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv);
+extern int mga_dma_init(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+extern int mga_dma_flush(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int mga_dma_reset(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+extern int mga_dma_buffers(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
 extern int mga_driver_load(struct drm_device *dev, unsigned long flags);
 extern int mga_driver_unload(struct drm_device * dev);
 extern void mga_driver_lastclose(struct drm_device * dev);
@@ -245,7 +250,7 @@ do {                                                                        \
                            dev_priv->prim.high_mark ) {                \
                        if ( MGA_DMA_DEBUG )                            \
                                DRM_INFO( "%s: wrap...\n", __FUNCTION__ );      \
-                       return DRM_ERR(EBUSY);                  \
+                       return -EBUSY;                  \
                }                                                       \
        }                                                               \
 } while (0)
@@ -256,7 +261,7 @@ do {                                                                        \
                if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {           \
                        if ( MGA_DMA_DEBUG )                            \
                                DRM_INFO( "%s: wrap...\n", __FUNCTION__ );      \
-                       return DRM_ERR(EBUSY);                  \
+                       return -EBUSY;                  \
                }                                                       \
                mga_do_dma_wrap_end( dev_priv );                        \
        }                                                               \
index d448b0aef33c3d2ef8fc8695eafd4e0ddce49f9b..5ec8b61c5d455b29321678e6f504e9b0a329dbfc 100644 (file)
@@ -392,7 +392,7 @@ static int mga_verify_context(drm_mga_private_t * dev_priv)
                          ctx->dstorg, dev_priv->front_offset,
                          dev_priv->back_offset);
                ctx->dstorg = 0;
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        return 0;
@@ -411,7 +411,7 @@ static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit)
        if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) {
                DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit);
                tex->texorg = 0;
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        return 0;
@@ -453,13 +453,13 @@ static int mga_verify_iload(drm_mga_private_t * dev_priv,
            dstorg + length > (dev_priv->texture_offset +
                               dev_priv->texture_size)) {
                DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (length & MGA_ILOAD_MASK) {
                DRM_ERROR("*** bad iload length: 0x%x\n",
                          length & MGA_ILOAD_MASK);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        return 0;
@@ -471,7 +471,7 @@ static int mga_verify_blit(drm_mga_private_t * dev_priv,
        if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
            (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) {
                DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        return 0;
 }
@@ -828,24 +828,20 @@ static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit
  *
  */
 
-static int mga_dma_clear(DRM_IOCTL_ARGS)
+static int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
        drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
-       drm_mga_clear_t clear;
+       drm_mga_clear_t *clear = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(clear, (drm_mga_clear_t __user *) data,
-                                sizeof(clear));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
 
        WRAP_TEST_WITH_RETURN(dev_priv);
 
-       mga_dma_dispatch_clear(dev, &clear);
+       mga_dma_dispatch_clear(dev, clear);
 
        /* Make sure we restore the 3D state next time.
         */
@@ -854,13 +850,12 @@ static int mga_dma_clear(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int mga_dma_swap(DRM_IOCTL_ARGS)
+static int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
        drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
@@ -876,37 +871,32 @@ static int mga_dma_swap(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int mga_dma_vertex(DRM_IOCTL_ARGS)
+static int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_mga_buf_priv_t *buf_priv;
-       drm_mga_vertex_t vertex;
-
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       drm_mga_vertex_t *vertex = data;
 
-       DRM_COPY_FROM_USER_IOCTL(vertex,
-                                (drm_mga_vertex_t __user *) data,
-                                sizeof(vertex));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (vertex.idx < 0 || vertex.idx > dma->buf_count)
-               return DRM_ERR(EINVAL);
-       buf = dma->buflist[vertex.idx];
+       if (vertex->idx < 0 || vertex->idx > dma->buf_count)
+               return -EINVAL;
+       buf = dma->buflist[vertex->idx];
        buf_priv = buf->dev_private;
 
-       buf->used = vertex.used;
-       buf_priv->discard = vertex.discard;
+       buf->used = vertex->used;
+       buf_priv->discard = vertex->discard;
 
        if (!mga_verify_state(dev_priv)) {
-               if (vertex.discard) {
+               if (vertex->discard) {
                        if (buf_priv->dispatched == 1)
                                AGE_BUFFER(buf_priv);
                        buf_priv->dispatched = 0;
                        mga_freelist_put(dev, buf);
                }
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        WRAP_TEST_WITH_RETURN(dev_priv);
@@ -916,82 +906,73 @@ static int mga_dma_vertex(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int mga_dma_indices(DRM_IOCTL_ARGS)
+static int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_mga_buf_priv_t *buf_priv;
-       drm_mga_indices_t indices;
+       drm_mga_indices_t *indices = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_COPY_FROM_USER_IOCTL(indices,
-                                (drm_mga_indices_t __user *) data,
-                                sizeof(indices));
+       if (indices->idx < 0 || indices->idx > dma->buf_count)
+               return -EINVAL;
 
-       if (indices.idx < 0 || indices.idx > dma->buf_count)
-               return DRM_ERR(EINVAL);
-
-       buf = dma->buflist[indices.idx];
+       buf = dma->buflist[indices->idx];
        buf_priv = buf->dev_private;
 
-       buf_priv->discard = indices.discard;
+       buf_priv->discard = indices->discard;
 
        if (!mga_verify_state(dev_priv)) {
-               if (indices.discard) {
+               if (indices->discard) {
                        if (buf_priv->dispatched == 1)
                                AGE_BUFFER(buf_priv);
                        buf_priv->dispatched = 0;
                        mga_freelist_put(dev, buf);
                }
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        WRAP_TEST_WITH_RETURN(dev_priv);
 
-       mga_dma_dispatch_indices(dev, buf, indices.start, indices.end);
+       mga_dma_dispatch_indices(dev, buf, indices->start, indices->end);
 
        return 0;
 }
 
-static int mga_dma_iload(DRM_IOCTL_ARGS)
+static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        struct drm_device_dma *dma = dev->dma;
        drm_mga_private_t *dev_priv = dev->dev_private;
        struct drm_buf *buf;
        drm_mga_buf_priv_t *buf_priv;
-       drm_mga_iload_t iload;
+       drm_mga_iload_t *iload = data;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(iload, (drm_mga_iload_t __user *) data,
-                                sizeof(iload));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
 #if 0
        if (mga_do_wait_for_idle(dev_priv) < 0) {
                if (MGA_DMA_DEBUG)
                        DRM_INFO("%s: -EBUSY\n", __FUNCTION__);
-               return DRM_ERR(EBUSY);
+               return -EBUSY;
        }
 #endif
-       if (iload.idx < 0 || iload.idx > dma->buf_count)
-               return DRM_ERR(EINVAL);
+       if (iload->idx < 0 || iload->idx > dma->buf_count)
+               return -EINVAL;
 
-       buf = dma->buflist[iload.idx];
+       buf = dma->buflist[iload->idx];
        buf_priv = buf->dev_private;
 
-       if (mga_verify_iload(dev_priv, iload.dstorg, iload.length)) {
+       if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) {
                mga_freelist_put(dev, buf);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        WRAP_TEST_WITH_RETURN(dev_priv);
 
-       mga_dma_dispatch_iload(dev, buf, iload.dstorg, iload.length);
+       mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length);
 
        /* Make sure we restore the 3D state next time.
         */
@@ -1000,28 +981,24 @@ static int mga_dma_iload(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int mga_dma_blit(DRM_IOCTL_ARGS)
+static int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
        drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
-       drm_mga_blit_t blit;
+       drm_mga_blit_t *blit = data;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(blit, (drm_mga_blit_t __user *) data,
-                                sizeof(blit));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
 
-       if (mga_verify_blit(dev_priv, blit.srcorg, blit.dstorg))
-               return DRM_ERR(EINVAL);
+       if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg))
+               return -EINVAL;
 
        WRAP_TEST_WITH_RETURN(dev_priv);
 
-       mga_dma_dispatch_blit(dev, &blit);
+       mga_dma_dispatch_blit(dev, blit);
 
        /* Make sure we restore the 3D state next time.
         */
@@ -1030,24 +1007,20 @@ static int mga_dma_blit(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int mga_getparam(DRM_IOCTL_ARGS)
+static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
-       drm_mga_getparam_t param;
+       drm_mga_getparam_t *param = data;
        int value;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(param, (drm_mga_getparam_t __user *) data,
-                                sizeof(param));
-
        DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
 
-       switch (param.param) {
+       switch (param->param) {
        case MGA_PARAM_IRQ_NR:
                value = dev->irq;
                break;
@@ -1055,36 +1028,35 @@ static int mga_getparam(DRM_IOCTL_ARGS)
                value = dev_priv->chipset;
                break;
        default:
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
 }
 
-static int mga_set_fence(DRM_IOCTL_ARGS)
+static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
-       u32 temp;
+       u32 *fence = data;
        DMA_LOCALS;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
 
-       /* I would normal do this assignment in the declaration of temp,
+       /* I would normal do this assignment in the declaration of fence,
         * but dev_priv may be NULL.
         */
 
-       temp = dev_priv->next_fence_to_post;
+       *fence = dev_priv->next_fence_to_post;
        dev_priv->next_fence_to_post++;
 
        BEGIN_DMA(1);
@@ -1093,53 +1065,40 @@ static int mga_set_fence(DRM_IOCTL_ARGS)
                  MGA_DMAPAD, 0x00000000, MGA_SOFTRAP, 0x00000000);
        ADVANCE_DMA();
 
-       if (DRM_COPY_TO_USER((u32 __user *) data, &temp, sizeof(u32))) {
-               DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
-       }
-
        return 0;
 }
 
-static int mga_wait_fence(DRM_IOCTL_ARGS)
+static int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file *
+file_priv)
 {
-       DRM_DEVICE;
        drm_mga_private_t *dev_priv = dev->dev_private;
-       u32 fence;
+       u32 *fence = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32));
-
        DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
 
-       mga_driver_fence_wait(dev, &fence);
-
-       if (DRM_COPY_TO_USER((u32 __user *) data, &fence, sizeof(u32))) {
-               DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
-       }
-
+       mga_driver_fence_wait(dev, fence);
        return 0;
 }
 
-drm_ioctl_desc_t mga_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+struct drm_ioctl_desc mga_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 };
 
 int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
index d67f4925fbac166a2d6976cf3c296e47c0ce61a5..651b93c8ab5dc5d8223a0185aebb531f919d7b2c 100644 (file)
@@ -141,7 +141,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
        if (size > dev_priv->warp->size) {
                DRM_ERROR("microcode too large! (%u > %lu)\n",
                          size, dev_priv->warp->size);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        switch (dev_priv->chipset) {
@@ -151,7 +151,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
        case MGA_CARD_TYPE_G200:
                return mga_warp_install_g200_microcode(dev_priv);
        default:
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 }
 
@@ -177,7 +177,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv)
                MGA_WRITE(MGA_WVRTXSZ, 7);
                break;
        default:
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
@@ -186,7 +186,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv)
        if (wmisc != WMISC_EXPECTED) {
                DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n",
                          wmisc, WMISC_EXPECTED);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        return 0;
index b163ed09bd8169b2b30982d39184835fe1b5c3c7..7d550aba165e6f7301410b1f2b915c3713fcdd67 100644 (file)
@@ -129,7 +129,7 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
 #if R128_FIFO_DEBUG
        DRM_ERROR("failed!\n");
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
@@ -146,7 +146,7 @@ static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
 #if R128_FIFO_DEBUG
        DRM_ERROR("failed!\n");
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
@@ -168,7 +168,7 @@ static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
 #if R128_FIFO_DEBUG
        DRM_ERROR("failed!\n");
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 /* ================================================================
@@ -227,7 +227,7 @@ int r128_do_cce_idle(drm_r128_private_t * dev_priv)
        DRM_ERROR("failed!\n");
        r128_status(dev_priv);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 /* Start the Concurrent Command Engine.
@@ -355,7 +355,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
 
        dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
        if (dev_priv == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        memset(dev_priv, 0, sizeof(drm_r128_private_t));
 
@@ -365,7 +365,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                DRM_ERROR("PCI GART memory not allocated!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->usec_timeout = init->usec_timeout;
@@ -374,7 +374,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                DRM_DEBUG("TIMEOUT problem!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->cce_mode = init->cce_mode;
@@ -394,7 +394,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                DRM_DEBUG("Bad cce_mode!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        switch (init->cce_mode) {
@@ -461,7 +461,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                DRM_ERROR("could not find sarea!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
@@ -469,21 +469,21 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                DRM_ERROR("could not find mmio region!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
        if (!dev_priv->cce_ring) {
                DRM_ERROR("could not find cce ring region!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
        if (!dev_priv->ring_rptr) {
                DRM_ERROR("could not find ring read pointer!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
@@ -491,7 +491,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                DRM_ERROR("could not find dma buffer region!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (!dev_priv->is_pci) {
@@ -501,7 +501,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                        DRM_ERROR("could not find agp texture region!\n");
                        dev->dev_private = (void *)dev_priv;
                        r128_do_cleanup_cce(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
 
@@ -520,7 +520,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                        DRM_ERROR("Could not ioremap agp regions!\n");
                        dev->dev_private = (void *)dev_priv;
                        r128_do_cleanup_cce(dev);
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
        } else
 #endif
@@ -567,7 +567,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
                        DRM_ERROR("failed to init PCI GART!\n");
                        dev->dev_private = (void *)dev_priv;
                        r128_do_cleanup_cce(dev);
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
                R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
 #if __OS_HAS_AGP
@@ -625,35 +625,30 @@ int r128_do_cleanup_cce(struct drm_device * dev)
        return 0;
 }
 
-int r128_cce_init(DRM_IOCTL_ARGS)
+int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_r128_init_t init;
+       drm_r128_init_t *init = data;
 
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_COPY_FROM_USER_IOCTL(init, (drm_r128_init_t __user *) data,
-                                sizeof(init));
-
-       switch (init.func) {
+       switch (init->func) {
        case R128_INIT_CCE:
-               return r128_do_init_cce(dev, &init);
+               return r128_do_init_cce(dev, init);
        case R128_CLEANUP_CCE:
                return r128_do_cleanup_cce(dev);
        }
 
-       return DRM_ERR(EINVAL);
+       return -EINVAL;
 }
 
-int r128_cce_start(DRM_IOCTL_ARGS)
+int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
                DRM_DEBUG("%s while CCE running\n", __FUNCTION__);
@@ -668,30 +663,26 @@ int r128_cce_start(DRM_IOCTL_ARGS)
 /* Stop the CCE.  The engine must have been idled before calling this
  * routine.
  */
-int r128_cce_stop(DRM_IOCTL_ARGS)
+int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
-       drm_r128_cce_stop_t stop;
+       drm_r128_cce_stop_t *stop = data;
        int ret;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t __user *) data,
-                                sizeof(stop));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        /* Flush any pending CCE commands.  This ensures any outstanding
         * commands are exectuted by the engine before we turn it off.
         */
-       if (stop.flush) {
+       if (stop->flush) {
                r128_do_cce_flush(dev_priv);
        }
 
        /* If we fail to make the engine go idle, we return an error
         * code so that the DRM ioctl wrapper can try again.
         */
-       if (stop.idle) {
+       if (stop->idle) {
                ret = r128_do_cce_idle(dev_priv);
                if (ret)
                        return ret;
@@ -711,17 +702,16 @@ int r128_cce_stop(DRM_IOCTL_ARGS)
 
 /* Just reset the CCE ring.  Called as part of an X Server engine reset.
  */
-int r128_cce_reset(DRM_IOCTL_ARGS)
+int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_DEBUG("%s called before init done\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        r128_do_cce_reset(dev_priv);
@@ -732,13 +722,12 @@ int r128_cce_reset(DRM_IOCTL_ARGS)
        return 0;
 }
 
-int r128_cce_idle(DRM_IOCTL_ARGS)
+int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (dev_priv->cce_running) {
                r128_do_cce_flush(dev_priv);
@@ -747,19 +736,18 @@ int r128_cce_idle(DRM_IOCTL_ARGS)
        return r128_do_cce_idle(dev_priv);
 }
 
-int r128_engine_reset(DRM_IOCTL_ARGS)
+int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        return r128_do_engine_reset(dev);
 }
 
-int r128_fullscreen(DRM_IOCTL_ARGS)
+int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       return DRM_ERR(EINVAL);
+       return -EINVAL;
 }
 
 /* ================================================================
@@ -780,7 +768,7 @@ static int r128_freelist_init(struct drm_device * dev)
 
        dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
        if (dev_priv->head == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t));
        dev_priv->head->age = R128_BUFFER_USED;
@@ -791,7 +779,7 @@ static int r128_freelist_init(struct drm_device * dev)
 
                entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
                if (!entry)
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
 
                entry->age = R128_BUFFER_FREE;
                entry->buf = buf;
@@ -828,7 +816,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev)
        for (i = 0; i < dma->buf_count; i++) {
                buf = dma->buflist[i];
                buf_priv = buf->dev_private;
-               if (buf->filp == 0)
+               if (buf->file_priv == 0)
                        return buf;
        }
 
@@ -883,10 +871,12 @@ int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
 
        /* FIXME: This is being ignored... */
        DRM_ERROR("failed!\n");
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
-static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
+static int r128_cce_get_buffers(struct drm_device * dev,
+                               struct drm_file *file_priv,
+                               struct drm_dma * d)
 {
        int i;
        struct drm_buf *buf;
@@ -894,57 +884,51 @@ static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct dr
        for (i = d->granted_count; i < d->request_count; i++) {
                buf = r128_freelist_get(dev);
                if (!buf)
-                       return DRM_ERR(EAGAIN);
+                       return -EAGAIN;
 
-               buf->filp = filp;
+               buf->file_priv = file_priv;
 
                if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
                                     sizeof(buf->idx)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
                if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
                                     sizeof(buf->total)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
 
                d->granted_count++;
        }
        return 0;
 }
 
-int r128_cce_buffers(DRM_IOCTL_ARGS)
+int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        struct drm_device_dma *dma = dev->dma;
        int ret = 0;
-       struct drm_dma __user *argp = (void __user *)data;
-       struct drm_dma d;
+       struct drm_dma *d = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        /* Please don't send us buffers.
         */
-       if (d.send_count != 0) {
+       if (d->send_count != 0) {
                DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
-                         DRM_CURRENTPID, d.send_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->send_count);
+               return -EINVAL;
        }
 
        /* We'll send you buffers.
         */
-       if (d.request_count < 0 || d.request_count > dma->buf_count) {
+       if (d->request_count < 0 || d->request_count > dma->buf_count) {
                DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
-                         DRM_CURRENTPID, d.request_count, dma->buf_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->request_count, dma->buf_count);
+               return -EINVAL;
        }
 
-       d.granted_count = 0;
+       d->granted_count = 0;
 
-       if (d.request_count) {
-               ret = r128_cce_get_buffers(filp, dev, &d);
+       if (d->request_count) {
+               ret = r128_cce_get_buffers(dev, file_priv, d);
        }
 
-       DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
        return ret;
 }
index e94a39c6e3270fa94c544fc6146987151d29bf2a..8d8878b55f5547e90aacc998ceac75977fe26dec 100644 (file)
@@ -222,11 +222,7 @@ typedef struct drm_r128_init {
                R128_INIT_CCE = 0x01,
                R128_CLEANUP_CCE = 0x02
        } func;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
-       int sarea_priv_offset;
-#else
        unsigned long sarea_priv_offset;
-#endif
        int is_pci;
        int cce_mode;
        int cce_secure;
@@ -240,21 +236,12 @@ typedef struct drm_r128_init {
        unsigned int depth_offset, depth_pitch;
        unsigned int span_offset;
 
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
-       unsigned int fb_offset;
-       unsigned int mmio_offset;
-       unsigned int ring_offset;
-       unsigned int ring_rptr_offset;
-       unsigned int buffers_offset;
-       unsigned int agp_textures_offset;
-#else
        unsigned long fb_offset;
        unsigned long mmio_offset;
        unsigned long ring_offset;
        unsigned long ring_rptr_offset;
        unsigned long buffers_offset;
        unsigned long agp_textures_offset;
-#endif
 } drm_r128_init_t;
 
 typedef struct drm_r128_cce_stop {
@@ -264,15 +251,10 @@ typedef struct drm_r128_cce_stop {
 
 typedef struct drm_r128_clear {
        unsigned int flags;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
-       int x, y, w, h;
-#endif
        unsigned int clear_color;
        unsigned int clear_depth;
-#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
        unsigned int color_mask;
        unsigned int depth_mask;
-#endif
 } drm_r128_clear_t;
 
 typedef struct drm_r128_vertex {
index 72249fb2fd1c827a4bcbe54e33114c4cde1b6a3c..250d2aa46581750a349a85fe8742ea0b0aa519d9 100644 (file)
@@ -129,18 +129,18 @@ typedef struct drm_r128_buf_priv {
        drm_r128_freelist_t *list_entry;
 } drm_r128_buf_priv_t;
 
-extern drm_ioctl_desc_t r128_ioctls[];
+extern struct drm_ioctl_desc r128_ioctls[];
 extern int r128_max_ioctl;
 
                                /* r128_cce.c */
-extern int r128_cce_init(DRM_IOCTL_ARGS);
-extern int r128_cce_start(DRM_IOCTL_ARGS);
-extern int r128_cce_stop(DRM_IOCTL_ARGS);
-extern int r128_cce_reset(DRM_IOCTL_ARGS);
-extern int r128_cce_idle(DRM_IOCTL_ARGS);
-extern int r128_engine_reset(DRM_IOCTL_ARGS);
-extern int r128_fullscreen(DRM_IOCTL_ARGS);
-extern int r128_cce_buffers(DRM_IOCTL_ARGS);
+extern int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
 
 extern void r128_freelist_reset(struct drm_device * dev);
 
@@ -156,7 +156,8 @@ extern void r128_driver_irq_preinstall(struct drm_device * dev);
 extern void r128_driver_irq_postinstall(struct drm_device * dev);
 extern void r128_driver_irq_uninstall(struct drm_device * dev);
 extern void r128_driver_lastclose(struct drm_device * dev);
-extern void r128_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void r128_driver_preclose(struct drm_device * dev,
+                                struct drm_file *file_priv);
 
 extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
                              unsigned long arg);
@@ -428,7 +429,7 @@ do {                                                                        \
                        DRM_UDELAY(1);                          \
                }                                                       \
                DRM_ERROR( "ring space check failed!\n" );              \
-               return DRM_ERR(EBUSY);                          \
+               return -EBUSY;                          \
        }                                                               \
  __ring_space_done:                                                    \
        ;                                                               \
index 7b334fb7d649f9e78286bde2659a95d816dd8da2..b7f483cac6d4b7973f1627912cee23235485af54 100644 (file)
@@ -776,8 +776,9 @@ static void r128_cce_dispatch_indices(struct drm_device * dev,
        sarea_priv->nbox = 0;
 }
 
-static int r128_cce_dispatch_blit(DRMFILE filp,
-                                 struct drm_device * dev, drm_r128_blit_t * blit)
+static int r128_cce_dispatch_blit(struct drm_device * dev,
+                                 struct drm_file *file_priv,
+                                 drm_r128_blit_t * blit)
 {
        drm_r128_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
@@ -809,7 +810,7 @@ static int r128_cce_dispatch_blit(DRMFILE filp,
                break;
        default:
                DRM_ERROR("invalid blit format %d\n", blit->format);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        /* Flush the pixel cache, and mark the contents as Read Invalid.
@@ -829,14 +830,14 @@ static int r128_cce_dispatch_blit(DRMFILE filp,
        buf = dma->buflist[blit->idx];
        buf_priv = buf->dev_private;
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
        if (buf->pending) {
                DRM_ERROR("sending pending buffer %d\n", blit->idx);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        buf_priv->discard = 1;
@@ -900,22 +901,22 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
 
        count = depth->n;
        if (count > 4096 || count <= 0)
-               return DRM_ERR(EMSGSIZE);
+               return -EMSGSIZE;
 
        if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
        if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        buffer_size = depth->n * sizeof(u32);
        buffer = drm_alloc(buffer_size, DRM_MEM_BUFS);
        if (buffer == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
                drm_free(buffer, buffer_size, DRM_MEM_BUFS);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        mask_size = depth->n * sizeof(u8);
@@ -923,12 +924,12 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
                mask = drm_alloc(mask_size, DRM_MEM_BUFS);
                if (mask == NULL) {
                        drm_free(buffer, buffer_size, DRM_MEM_BUFS);
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
                if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
                        drm_free(buffer, buffer_size, DRM_MEM_BUFS);
                        drm_free(mask, mask_size, DRM_MEM_BUFS);
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
                }
 
                for (i = 0; i < count; i++, x++) {
@@ -996,28 +997,28 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
 
        count = depth->n;
        if (count > 4096 || count <= 0)
-               return DRM_ERR(EMSGSIZE);
+               return -EMSGSIZE;
 
        xbuf_size = count * sizeof(*x);
        ybuf_size = count * sizeof(*y);
        x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
        if (x == NULL) {
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
        if (y == NULL) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
                drm_free(y, ybuf_size, DRM_MEM_BUFS);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
        if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
                drm_free(y, ybuf_size, DRM_MEM_BUFS);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        buffer_size = depth->n * sizeof(u32);
@@ -1025,13 +1026,13 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
        if (buffer == NULL) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
                drm_free(y, ybuf_size, DRM_MEM_BUFS);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
                drm_free(y, ybuf_size, DRM_MEM_BUFS);
                drm_free(buffer, buffer_size, DRM_MEM_BUFS);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        if (depth->mask) {
@@ -1041,14 +1042,14 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
                        drm_free(x, xbuf_size, DRM_MEM_BUFS);
                        drm_free(y, ybuf_size, DRM_MEM_BUFS);
                        drm_free(buffer, buffer_size, DRM_MEM_BUFS);
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
                if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
                        drm_free(x, xbuf_size, DRM_MEM_BUFS);
                        drm_free(y, ybuf_size, DRM_MEM_BUFS);
                        drm_free(buffer, buffer_size, DRM_MEM_BUFS);
                        drm_free(mask, mask_size, DRM_MEM_BUFS);
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
                }
 
                for (i = 0; i < count; i++) {
@@ -1115,13 +1116,13 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev,
 
        count = depth->n;
        if (count > 4096 || count <= 0)
-               return DRM_ERR(EMSGSIZE);
+               return -EMSGSIZE;
 
        if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
        if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        BEGIN_RING(7);
@@ -1159,7 +1160,7 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
 
        count = depth->n;
        if (count > 4096 || count <= 0)
-               return DRM_ERR(EMSGSIZE);
+               return -EMSGSIZE;
 
        if (count > dev_priv->depth_pitch) {
                count = dev_priv->depth_pitch;
@@ -1169,22 +1170,22 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
        ybuf_size = count * sizeof(*y);
        x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
        if (x == NULL) {
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
        if (y == NULL) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
                drm_free(y, ybuf_size, DRM_MEM_BUFS);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
        if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) {
                drm_free(x, xbuf_size, DRM_MEM_BUFS);
                drm_free(y, ybuf_size, DRM_MEM_BUFS);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        for (i = 0; i < count; i++) {
@@ -1241,25 +1242,21 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple)
  * IOCTL functions
  */
 
-static int r128_cce_clear(DRM_IOCTL_ARGS)
+static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
-       drm_r128_clear_t clear;
+       drm_r128_clear_t *clear = data;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(clear, (drm_r128_clear_t __user *) data,
-                                sizeof(clear));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
        if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
 
-       r128_cce_dispatch_clear(dev, &clear);
+       r128_cce_dispatch_clear(dev, clear);
        COMMIT_RING();
 
        /* Make sure we restore the 3D state next time.
@@ -1309,13 +1306,12 @@ static int r128_do_cleanup_pageflip(struct drm_device * dev)
  * They can & should be intermixed to support multiple 3d windows.
  */
 
-static int r128_cce_flip(DRM_IOCTL_ARGS)
+static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
@@ -1328,14 +1324,13 @@ static int r128_cce_flip(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int r128_cce_swap(DRM_IOCTL_ARGS)
+static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
@@ -1350,58 +1345,54 @@ static int r128_cce_swap(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int r128_cce_vertex(DRM_IOCTL_ARGS)
+static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_r128_buf_priv_t *buf_priv;
-       drm_r128_vertex_t vertex;
+       drm_r128_vertex_t *vertex = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(vertex, (drm_r128_vertex_t __user *) data,
-                                sizeof(vertex));
-
        DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
-                 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
+                 DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
 
-       if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+       if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         vertex.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         vertex->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
-       if (vertex.prim < 0 ||
-           vertex.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
-               DRM_ERROR("buffer prim %d\n", vertex.prim);
-               return DRM_ERR(EINVAL);
+       if (vertex->prim < 0 ||
+           vertex->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+               DRM_ERROR("buffer prim %d\n", vertex->prim);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       buf = dma->buflist[vertex.idx];
+       buf = dma->buflist[vertex->idx];
        buf_priv = buf->dev_private;
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
        if (buf->pending) {
-               DRM_ERROR("sending pending buffer %d\n", vertex.idx);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+               return -EINVAL;
        }
 
-       buf->used = vertex.count;
-       buf_priv->prim = vertex.prim;
-       buf_priv->discard = vertex.discard;
+       buf->used = vertex->count;
+       buf_priv->prim = vertex->prim;
+       buf_priv->discard = vertex->discard;
 
        r128_cce_dispatch_vertex(dev, buf);
 
@@ -1409,134 +1400,123 @@ static int r128_cce_vertex(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int r128_cce_indices(DRM_IOCTL_ARGS)
+static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_r128_buf_priv_t *buf_priv;
-       drm_r128_indices_t elts;
+       drm_r128_indices_t *elts = data;
        int count;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(elts, (drm_r128_indices_t __user *) data,
-                                sizeof(elts));
-
        DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID,
-                 elts.idx, elts.start, elts.end, elts.discard);
+                 elts->idx, elts->start, elts->end, elts->discard);
 
-       if (elts.idx < 0 || elts.idx >= dma->buf_count) {
+       if (elts->idx < 0 || elts->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         elts.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         elts->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
-       if (elts.prim < 0 || elts.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
-               DRM_ERROR("buffer prim %d\n", elts.prim);
-               return DRM_ERR(EINVAL);
+       if (elts->prim < 0 ||
+           elts->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+               DRM_ERROR("buffer prim %d\n", elts->prim);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       buf = dma->buflist[elts.idx];
+       buf = dma->buflist[elts->idx];
        buf_priv = buf->dev_private;
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
        if (buf->pending) {
-               DRM_ERROR("sending pending buffer %d\n", elts.idx);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("sending pending buffer %d\n", elts->idx);
+               return -EINVAL;
        }
 
-       count = (elts.end - elts.start) / sizeof(u16);
-       elts.start -= R128_INDEX_PRIM_OFFSET;
+       count = (elts->end - elts->start) / sizeof(u16);
+       elts->start -= R128_INDEX_PRIM_OFFSET;
 
-       if (elts.start & 0x7) {
-               DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
-               return DRM_ERR(EINVAL);
+       if (elts->start & 0x7) {
+               DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
+               return -EINVAL;
        }
-       if (elts.start < buf->used) {
-               DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
-               return DRM_ERR(EINVAL);
+       if (elts->start < buf->used) {
+               DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
+               return -EINVAL;
        }
 
-       buf->used = elts.end;
-       buf_priv->prim = elts.prim;
-       buf_priv->discard = elts.discard;
+       buf->used = elts->end;
+       buf_priv->prim = elts->prim;
+       buf_priv->discard = elts->discard;
 
-       r128_cce_dispatch_indices(dev, buf, elts.start, elts.end, count);
+       r128_cce_dispatch_indices(dev, buf, elts->start, elts->end, count);
 
        COMMIT_RING();
        return 0;
 }
 
-static int r128_cce_blit(DRM_IOCTL_ARGS)
+static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        struct drm_device_dma *dma = dev->dma;
        drm_r128_private_t *dev_priv = dev->dev_private;
-       drm_r128_blit_t blit;
+       drm_r128_blit_t *blit = data;
        int ret;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(blit, (drm_r128_blit_t __user *) data,
-                                sizeof(blit));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit.idx);
+       DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx);
 
-       if (blit.idx < 0 || blit.idx >= dma->buf_count) {
+       if (blit->idx < 0 || blit->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         blit.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         blit->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       ret = r128_cce_dispatch_blit(filp, dev, &blit);
+       ret = r128_cce_dispatch_blit(dev, file_priv, blit);
 
        COMMIT_RING();
        return ret;
 }
 
-static int r128_cce_depth(DRM_IOCTL_ARGS)
+static int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
-       drm_r128_depth_t depth;
+       drm_r128_depth_t *depth = data;
        int ret;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(depth, (drm_r128_depth_t __user *) data,
-                                sizeof(depth));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
-       ret = DRM_ERR(EINVAL);
-       switch (depth.func) {
+       ret = -EINVAL;
+       switch (depth->func) {
        case R128_WRITE_SPAN:
-               ret = r128_cce_dispatch_write_span(dev, &depth);
+               ret = r128_cce_dispatch_write_span(dev, depth);
                break;
        case R128_WRITE_PIXELS:
-               ret = r128_cce_dispatch_write_pixels(dev, &depth);
+               ret = r128_cce_dispatch_write_pixels(dev, depth);
                break;
        case R128_READ_SPAN:
-               ret = r128_cce_dispatch_read_span(dev, &depth);
+               ret = r128_cce_dispatch_read_span(dev, depth);
                break;
        case R128_READ_PIXELS:
-               ret = r128_cce_dispatch_read_pixels(dev, &depth);
+               ret = r128_cce_dispatch_read_pixels(dev, depth);
                break;
        }
 
@@ -1544,20 +1524,16 @@ static int r128_cce_depth(DRM_IOCTL_ARGS)
        return ret;
 }
 
-static int r128_cce_stipple(DRM_IOCTL_ARGS)
+static int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
-       drm_r128_stipple_t stipple;
+       drm_r128_stipple_t *stipple = data;
        u32 mask[32];
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(stipple, (drm_r128_stipple_t __user *) data,
-                                sizeof(stipple));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
-               return DRM_ERR(EFAULT);
+       if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+               return -EFAULT;
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
@@ -1567,61 +1543,58 @@ static int r128_cce_stipple(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int r128_cce_indirect(DRM_IOCTL_ARGS)
+static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_r128_buf_priv_t *buf_priv;
-       drm_r128_indirect_t indirect;
+       drm_r128_indirect_t *indirect = data;
 #if 0
        RING_LOCALS;
 #endif
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(indirect, (drm_r128_indirect_t __user *) data,
-                                sizeof(indirect));
-
        DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
-                 indirect.idx, indirect.start, indirect.end, indirect.discard);
+                 indirect->idx, indirect->start, indirect->end,
+                 indirect->discard);
 
-       if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
+       if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         indirect.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         indirect->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
 
-       buf = dma->buflist[indirect.idx];
+       buf = dma->buflist[indirect->idx];
        buf_priv = buf->dev_private;
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
        if (buf->pending) {
-               DRM_ERROR("sending pending buffer %d\n", indirect.idx);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("sending pending buffer %d\n", indirect->idx);
+               return -EINVAL;
        }
 
-       if (indirect.start < buf->used) {
+       if (indirect->start < buf->used) {
                DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
-                         indirect.start, buf->used);
-               return DRM_ERR(EINVAL);
+                         indirect->start, buf->used);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       buf->used = indirect.end;
-       buf_priv->discard = indirect.discard;
+       buf->used = indirect->end;
+       buf_priv->discard = indirect->discard;
 
 #if 0
        /* Wait for the 3D stream to idle before the indirect buffer
@@ -1636,46 +1609,42 @@ static int r128_cce_indirect(DRM_IOCTL_ARGS)
         * X server.  This is insecure and is thus only available to
         * privileged clients.
         */
-       r128_cce_dispatch_indirect(dev, buf, indirect.start, indirect.end);
+       r128_cce_dispatch_indirect(dev, buf, indirect->start, indirect->end);
 
        COMMIT_RING();
        return 0;
 }
 
-static int r128_getparam(DRM_IOCTL_ARGS)
+static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_r128_private_t *dev_priv = dev->dev_private;
-       drm_r128_getparam_t param;
+       drm_r128_getparam_t *param = data;
        int value;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(param, (drm_r128_getparam_t __user *) data,
-                                sizeof(param));
-
        DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
 
-       switch (param.param) {
+       switch (param->param) {
        case R128_PARAM_IRQ_NR:
                value = dev->irq;
                break;
        default:
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
 }
 
-void r128_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void r128_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
        if (dev->dev_private) {
                drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1690,24 +1659,24 @@ void r128_driver_lastclose(struct drm_device * dev)
        r128_do_cleanup_cce(dev);
 }
 
-drm_ioctl_desc_t r128_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_R128_INIT)] = {r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_R128_CCE_START)] = {r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_R128_CCE_STOP)] = {r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_R128_CCE_RESET)] = {r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_R128_CCE_IDLE)] = {r128_cce_idle, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_RESET)] = {r128_engine_reset, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = {r128_fullscreen, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_SWAP)] = {r128_cce_swap, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_FLIP)] = {r128_cce_flip, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_CLEAR)] = {r128_cce_clear, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_VERTEX)] = {r128_cce_vertex, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_INDICES)] = {r128_cce_indices, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_BLIT)] = {r128_cce_blit, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_DEPTH)] = {r128_cce_depth, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_STIPPLE)] = {r128_cce_stipple, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_R128_INDIRECT)] = {r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_R128_GETPARAM)] = {r128_getparam, DRM_AUTH},
+struct drm_ioctl_desc r128_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_R128_CCE_IDLE, r128_cce_idle, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_RESET, r128_engine_reset, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_FULLSCREEN, r128_fullscreen, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_SWAP, r128_cce_swap, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_FLIP, r128_cce_flip, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_CLEAR, r128_cce_clear, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_VERTEX, r128_cce_vertex, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_INDICES, r128_cce_indices, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_BLIT, r128_cce_blit, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_DEPTH, r128_cce_depth, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_STIPPLE, r128_cce_stipple, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_R128_GETPARAM, r128_getparam, DRM_AUTH),
 };
 
 int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls);
index 4e5aca6ba59aef89fc1b32d838be9cd435aa1f96..59b2944811c50c7c9e0269585ba525ce88a49a4e 100644 (file)
@@ -74,7 +74,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
                        if (DRM_COPY_FROM_USER_UNCHECKED
                            (&box, &cmdbuf->boxes[n + i], sizeof(box))) {
                                DRM_ERROR("copy cliprect faulted\n");
-                               return DRM_ERR(EFAULT);
+                               return -EFAULT;
                        }
 
                        box.x1 =
@@ -263,7 +263,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
                DRM_ERROR
                    ("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
                     reg, sz);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        for (i = 0; i < sz; i++) {
                values[i] = ((int *)cmdbuf->buf)[i];
@@ -275,13 +275,13 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
                                DRM_ERROR
                                    ("Offset failed range check (reg=%04x sz=%d)\n",
                                     reg, sz);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        break;
                default:
                        DRM_ERROR("Register %04x failed check as flag=%02x\n",
                                  reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
 
@@ -317,12 +317,12 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
                return 0;
 
        if (sz * 4 > cmdbuf->bufsz)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        if (reg + sz * 4 >= 0x10000) {
                DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg,
                          sz);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (r300_check_range(reg, sz)) {
@@ -362,7 +362,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
        if (!sz)
                return 0;
        if (sz * 16 > cmdbuf->bufsz)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        BEGIN_RING(5 + sz * 4);
        /* Wait for VAP to come to senses.. */
@@ -391,7 +391,7 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
        RING_LOCALS;
 
        if (8 * 4 > cmdbuf->bufsz)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        BEGIN_RING(10);
        OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));
@@ -421,7 +421,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
        if ((count + 1) > MAX_ARRAY_PACKET) {
                DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
                          count);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        memset(payload, 0, MAX_ARRAY_PACKET * 4);
        memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4);
@@ -437,7 +437,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
                        DRM_ERROR
                            ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
                             k, i);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                k++;
                i++;
@@ -448,7 +448,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
                        DRM_ERROR
                            ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
                             k, i);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                k++;
                i++;
@@ -458,7 +458,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
                DRM_ERROR
                    ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
                     k, i, narrays, count + 1);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        /* all clear, output packet */
@@ -492,7 +492,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
                        ret = !radeon_check_offset(dev_priv, offset);
                        if (ret) {
                                DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                }
 
@@ -502,7 +502,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
                        ret = !radeon_check_offset(dev_priv, offset);
                        if (ret) {
                                DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        
                }
@@ -530,12 +530,12 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
 
        if ((cmd[1] & 0x8000ffff) != 0x80000810) {
                DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        ret = !radeon_check_offset(dev_priv, cmd[2]);
        if (ret) {
                DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        BEGIN_RING(count+2);
@@ -557,7 +557,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
        RING_LOCALS;
 
        if (4 > cmdbuf->bufsz)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        /* Fixme !! This simply emits a packet without much checking.
           We need to be smarter. */
@@ -568,7 +568,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
        /* Is it packet 3 ? */
        if ((header >> 30) != 0x3) {
                DRM_ERROR("Not a packet3 header (0x%08x)\n", header);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        count = (header >> 16) & 0x3fff;
@@ -578,7 +578,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
                DRM_ERROR
                    ("Expected packet3 of length %d but have only %d bytes left\n",
                     (count + 2) * 4, cmdbuf->bufsz);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        /* Is it a packet type we know about ? */
@@ -600,7 +600,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
                break;
        default:
                DRM_ERROR("Unknown packet3 header (0x%08x)\n", header);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        BEGIN_RING(count + 2);
@@ -664,7 +664,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
                        DRM_ERROR("bad packet3 type %i at %p\n",
                                  header.packet3.packet,
                                  cmdbuf->buf - sizeof(header));
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                n += R300_SIMULTANEOUS_CLIPRECTS;
@@ -726,11 +726,11 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
        
        if (cmdbuf->bufsz < 
            (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        
        if (header.scratch.reg >= 5) {
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        
        dev_priv->scratch_ages[header.scratch.reg]++;
@@ -745,21 +745,21 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
                buf_idx *= 2; /* 8 bytes per buf */
                
                if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                                        
                if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                                        
                if (h_pending == 0) {
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                                        
                h_pending--;
                                                
                if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                                        
                cmdbuf->buf += sizeof(buf_idx);
@@ -780,8 +780,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
  * Called by the ioctl handler function radeon_cp_cmdbuf.
  */
 int r300_do_cp_cmdbuf(struct drm_device *dev,
-                     DRMFILE filp,
-                     struct drm_file *filp_priv,
+                     struct drm_file *file_priv,
                      drm_radeon_kcmd_buffer_t *cmdbuf)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -879,15 +878,16 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
                        if (idx < 0 || idx >= dma->buf_count) {
                                DRM_ERROR("buffer index %d (of %d max)\n",
                                          idx, dma->buf_count - 1);
-                               ret = DRM_ERR(EINVAL);
+                               ret = -EINVAL;
                                goto cleanup;
                        }
 
                        buf = dma->buflist[idx];
-                       if (buf->filp != filp || buf->pending) {
+                       if (buf->file_priv != file_priv || buf->pending) {
                                DRM_ERROR("bad buffer %p %p %d\n",
-                                         buf->filp, filp, buf->pending);
-                               ret = DRM_ERR(EINVAL);
+                                         buf->file_priv, file_priv,
+                                         buf->pending);
+                               ret = -EINVAL;
                                goto cleanup;
                        }
 
@@ -924,7 +924,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
                        DRM_ERROR("bad cmd_type %i at %p\n",
                                  header.header.cmd_type,
                                  cmdbuf->buf - sizeof(header));
-                       ret = DRM_ERR(EINVAL);
+                       ret = -EINVAL;
                        goto cleanup;
                }
        }
index af5790f8fd53a2631478c77d0aa433de65c66995..335423c5c18662e4993428d49db05d37c4e4fdd0 100644 (file)
@@ -889,7 +889,7 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
        DRM_ERROR("failed!\n");
        radeon_status(dev_priv);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
@@ -910,7 +910,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
        DRM_ERROR("failed!\n");
        radeon_status(dev_priv);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
@@ -936,7 +936,7 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
        DRM_ERROR("failed!\n");
        radeon_status(dev_priv);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 /* ================================================================
@@ -1394,7 +1394,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
        if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
                DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
@@ -1409,7 +1409,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
        if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
                DRM_ERROR("PCI GART memory not allocated!\n");
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->usec_timeout = init->usec_timeout;
@@ -1417,7 +1417,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
            dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
                DRM_DEBUG("TIMEOUT problem!\n");
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        /* Enable vblank on CRTC1 for older X servers
@@ -1446,7 +1446,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
            (init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) {
                DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode);
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        switch (init->fb_bpp) {
@@ -1515,27 +1515,27 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
        if (!dev_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
        if (!dev_priv->cp_ring) {
                DRM_ERROR("could not find cp ring region!\n");
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
        if (!dev_priv->ring_rptr) {
                DRM_ERROR("could not find ring read pointer!\n");
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        dev->agp_buffer_token = init->buffers_offset;
        dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
        if (!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
                radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (init->gart_textures_offset) {
@@ -1544,7 +1544,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
                if (!dev_priv->gart_textures) {
                        DRM_ERROR("could not find GART texture region!\n");
                        radeon_do_cleanup_cp(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
 
@@ -1562,7 +1562,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
                    !dev->agp_buffer_map->handle) {
                        DRM_ERROR("could not find ioremap agp regions!\n");
                        radeon_do_cleanup_cp(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        } else
 #endif
@@ -1710,14 +1710,14 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
                                DRM_ERROR
                                    ("Cannot use PCI Express without GART in FB memory\n");
                                radeon_do_cleanup_cp(dev);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                }
 
                if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
                        DRM_ERROR("failed to init PCI GART!\n");
                        radeon_do_cleanup_cp(dev);
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
 
                /* Turn on PCI GART */
@@ -1797,7 +1797,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
 
        if (!dev_priv) {
                DRM_ERROR("Called with no initialization\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        DRM_DEBUG("Starting radeon_do_resume_cp()\n");
@@ -1823,38 +1823,33 @@ static int radeon_do_resume_cp(struct drm_device * dev)
        return 0;
 }
 
-int radeon_cp_init(DRM_IOCTL_ARGS)
+int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_radeon_init_t init;
+       drm_radeon_init_t *init = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_COPY_FROM_USER_IOCTL(init, (drm_radeon_init_t __user *) data,
-                                sizeof(init));
-
-       if (init.func == RADEON_INIT_R300_CP)
+       if (init->func == RADEON_INIT_R300_CP)
                r300_init_reg_flags();
 
-       switch (init.func) {
+       switch (init->func) {
        case RADEON_INIT_CP:
        case RADEON_INIT_R200_CP:
        case RADEON_INIT_R300_CP:
-               return radeon_do_init_cp(dev, &init);
+               return radeon_do_init_cp(dev, init);
        case RADEON_CLEANUP_CP:
                return radeon_do_cleanup_cp(dev);
        }
 
-       return DRM_ERR(EINVAL);
+       return -EINVAL;
 }
 
-int radeon_cp_start(DRM_IOCTL_ARGS)
+int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (dev_priv->cp_running) {
                DRM_DEBUG("%s while CP running\n", __FUNCTION__);
@@ -1874,18 +1869,14 @@ int radeon_cp_start(DRM_IOCTL_ARGS)
 /* Stop the CP.  The engine must have been idled before calling this
  * routine.
  */
-int radeon_cp_stop(DRM_IOCTL_ARGS)
+int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_cp_stop_t stop;
+       drm_radeon_cp_stop_t *stop = data;
        int ret;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(stop, (drm_radeon_cp_stop_t __user *) data,
-                                sizeof(stop));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv->cp_running)
                return 0;
@@ -1893,14 +1884,14 @@ int radeon_cp_stop(DRM_IOCTL_ARGS)
        /* Flush any pending CP commands.  This ensures any outstanding
         * commands are exectuted by the engine before we turn it off.
         */
-       if (stop.flush) {
+       if (stop->flush) {
                radeon_do_cp_flush(dev_priv);
        }
 
        /* If we fail to make the engine go idle, we return an error
         * code so that the DRM ioctl wrapper can try again.
         */
-       if (stop.idle) {
+       if (stop->idle) {
                ret = radeon_do_cp_idle(dev_priv);
                if (ret)
                        return ret;
@@ -1963,17 +1954,16 @@ void radeon_do_release(struct drm_device * dev)
 
 /* Just reset the CP ring.  Called as part of an X Server engine reset.
  */
-int radeon_cp_reset(DRM_IOCTL_ARGS)
+int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_DEBUG("%s called before init done\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        radeon_do_cp_reset(dev_priv);
@@ -1984,32 +1974,29 @@ int radeon_cp_reset(DRM_IOCTL_ARGS)
        return 0;
 }
 
-int radeon_cp_idle(DRM_IOCTL_ARGS)
+int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        return radeon_do_cp_idle(dev_priv);
 }
 
 /* Added by Charl P. Botha to call radeon_do_resume_cp().
  */
-int radeon_cp_resume(DRM_IOCTL_ARGS)
+int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
 
        return radeon_do_resume_cp(dev);
 }
 
-int radeon_engine_reset(DRM_IOCTL_ARGS)
+int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        return radeon_do_engine_reset(dev);
 }
@@ -2020,7 +2007,7 @@ int radeon_engine_reset(DRM_IOCTL_ARGS)
 
 /* KW: Deprecated to say the least:
  */
-int radeon_fullscreen(DRM_IOCTL_ARGS)
+int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        return 0;
 }
@@ -2066,8 +2053,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
                for (i = start; i < dma->buf_count; i++) {
                        buf = dma->buflist[i];
                        buf_priv = buf->dev_private;
-                       if (buf->filp == 0 || (buf->pending &&
-                                              buf_priv->age <= done_age)) {
+                       if (buf->file_priv == NULL || (buf->pending &&
+                                                      buf_priv->age <=
+                                                      done_age)) {
                                dev_priv->stats.requested_bufs++;
                                buf->pending = 0;
                                return buf;
@@ -2106,8 +2094,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
                for (i = start; i < dma->buf_count; i++) {
                        buf = dma->buflist[i];
                        buf_priv = buf->dev_private;
-                       if (buf->filp == 0 || (buf->pending &&
-                                              buf_priv->age <= done_age)) {
+                       if (buf->file_priv == 0 || (buf->pending &&
+                                                   buf_priv->age <=
+                                                   done_age)) {
                                dev_priv->stats.requested_bufs++;
                                buf->pending = 0;
                                return buf;
@@ -2167,10 +2156,11 @@ int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n)
        radeon_status(dev_priv);
        DRM_ERROR("failed!\n");
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
-static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev,
+static int radeon_cp_get_buffers(struct drm_device *dev,
+                                struct drm_file *file_priv,
                                 struct drm_dma * d)
 {
        int i;
@@ -2179,58 +2169,52 @@ static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev,
        for (i = d->granted_count; i < d->request_count; i++) {
                buf = radeon_freelist_get(dev);
                if (!buf)
-                       return DRM_ERR(EBUSY);  /* NOTE: broken client */
+                       return -EBUSY;  /* NOTE: broken client */
 
-               buf->filp = filp;
+               buf->file_priv = file_priv;
 
                if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
                                     sizeof(buf->idx)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
                if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
                                     sizeof(buf->total)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
 
                d->granted_count++;
        }
        return 0;
 }
 
-int radeon_cp_buffers(DRM_IOCTL_ARGS)
+int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        struct drm_device_dma *dma = dev->dma;
        int ret = 0;
-       struct drm_dma __user *argp = (void __user *)data;
-       struct drm_dma d;
+       struct drm_dma *d = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        /* Please don't send us buffers.
         */
-       if (d.send_count != 0) {
+       if (d->send_count != 0) {
                DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
-                         DRM_CURRENTPID, d.send_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->send_count);
+               return -EINVAL;
        }
 
        /* We'll send you buffers.
         */
-       if (d.request_count < 0 || d.request_count > dma->buf_count) {
+       if (d->request_count < 0 || d->request_count > dma->buf_count) {
                DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
-                         DRM_CURRENTPID, d.request_count, dma->buf_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->request_count, dma->buf_count);
+               return -EINVAL;
        }
 
-       d.granted_count = 0;
+       d->granted_count = 0;
 
-       if (d.request_count) {
-               ret = radeon_cp_get_buffers(filp, dev, &d);
+       if (d->request_count) {
+               ret = radeon_cp_get_buffers(dev, file_priv, d);
        }
 
-       DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
        return ret;
 }
 
@@ -2241,7 +2225,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
 
        dev_priv = drm_alloc(sizeof(drm_radeon_private_t), DRM_MEM_DRIVER);
        if (dev_priv == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        memset(dev_priv, 0, sizeof(drm_radeon_private_t));
        dev->dev_private = (void *)dev_priv;
index 3b3d9357201ca18482265c49f2d7fb3b4af69113..e4077bc212b32fb0460ddba4db60fcbf28415d87 100644 (file)
@@ -188,7 +188,7 @@ struct mem_block {
        struct mem_block *prev;
        int start;
        int size;
-       DRMFILE filp;           /* 0: free, -1: heap, other: real files */
+       struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
 };
 
 struct radeon_surface {
@@ -203,7 +203,7 @@ struct radeon_virt_surface {
        u32 lower;
        u32 upper;
        u32 flags;
-       DRMFILE filp;
+       struct drm_file *file_priv;
 };
 
 typedef struct drm_radeon_private {
@@ -307,7 +307,7 @@ typedef struct drm_radeon_kcmd_buffer {
 } drm_radeon_kcmd_buffer_t;
 
 extern int radeon_no_wb;
-extern drm_ioctl_desc_t radeon_ioctls[];
+extern struct drm_ioctl_desc radeon_ioctls[];
 extern int radeon_max_ioctl;
 
 /* Check whether the given hardware address is inside the framebuffer or the
@@ -326,15 +326,15 @@ static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
 }
 
                                /* radeon_cp.c */
-extern int radeon_cp_init(DRM_IOCTL_ARGS);
-extern int radeon_cp_start(DRM_IOCTL_ARGS);
-extern int radeon_cp_stop(DRM_IOCTL_ARGS);
-extern int radeon_cp_reset(DRM_IOCTL_ARGS);
-extern int radeon_cp_idle(DRM_IOCTL_ARGS);
-extern int radeon_cp_resume(DRM_IOCTL_ARGS);
-extern int radeon_engine_reset(DRM_IOCTL_ARGS);
-extern int radeon_fullscreen(DRM_IOCTL_ARGS);
-extern int radeon_cp_buffers(DRM_IOCTL_ARGS);
+extern int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
 
 extern void radeon_freelist_reset(struct drm_device * dev);
 extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
@@ -347,15 +347,16 @@ extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
 extern int radeon_presetup(struct drm_device *dev);
 extern int radeon_driver_postcleanup(struct drm_device *dev);
 
-extern int radeon_mem_alloc(DRM_IOCTL_ARGS);
-extern int radeon_mem_free(DRM_IOCTL_ARGS);
-extern int radeon_mem_init_heap(DRM_IOCTL_ARGS);
+extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern void radeon_mem_takedown(struct mem_block **heap);
-extern void radeon_mem_release(DRMFILE filp, struct mem_block *heap);
+extern void radeon_mem_release(struct drm_file *file_priv,
+                              struct mem_block *heap);
 
                                /* radeon_irq.c */
-extern int radeon_irq_emit(DRM_IOCTL_ARGS);
-extern int radeon_irq_wait(DRM_IOCTL_ARGS);
+extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
 
 extern void radeon_do_release(struct drm_device * dev);
 extern int radeon_driver_vblank_wait(struct drm_device * dev,
@@ -372,7 +373,7 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
 extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
 extern int radeon_driver_unload(struct drm_device *dev);
 extern int radeon_driver_firstopen(struct drm_device *dev);
-extern void radeon_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv);
 extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp);
 extern void radeon_driver_lastclose(struct drm_device * dev);
 extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
@@ -382,8 +383,8 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
 /* r300_cmdbuf.c */
 extern void r300_init_reg_flags(void);
 
-extern int r300_do_cp_cmdbuf(struct drm_device * dev, DRMFILE filp,
-                            struct drm_file * filp_priv,
+extern int r300_do_cp_cmdbuf(struct drm_device * dev,
+                            struct drm_file *file_priv,
                             drm_radeon_kcmd_buffer_t * cmdbuf);
 
 /* Flags for stats.boxes
index ad8a0ac7182e9ead9d1498fd57b3dc28cdbb95de..f89e57665b64fdd3874f88e8bd7c4e70df207f24 100644 (file)
@@ -155,7 +155,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence
        atomic_t *counter;
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (crtc == DRM_RADEON_VBLANK_CRTC1) {
@@ -165,7 +165,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence
                counter = &dev->vbl_received2;
                ack |= RADEON_CRTC2_VBLANK_STAT;
        } else
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        radeon_acknowledge_irqs(dev_priv, ack);
 
@@ -196,28 +196,24 @@ int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
 
 /* Needs the lock as it touches the ring.
  */
-int radeon_irq_emit(DRM_IOCTL_ARGS)
+int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_irq_emit_t emit;
+       drm_radeon_irq_emit_t *emit = data;
        int result;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(emit, (drm_radeon_irq_emit_t __user *) data,
-                                sizeof(emit));
-
        result = radeon_emit_irq(dev);
 
-       if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
+       if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
@@ -225,21 +221,17 @@ int radeon_irq_emit(DRM_IOCTL_ARGS)
 
 /* Doesn't need the hardware lock.
  */
-int radeon_irq_wait(DRM_IOCTL_ARGS)
+int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_irq_wait_t irqwait;
+       drm_radeon_irq_wait_t *irqwait = data;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_radeon_irq_wait_t __user *) data,
-                                sizeof(irqwait));
-
-       return radeon_wait_irq(dev, irqwait.irq_seq);
+       return radeon_wait_irq(dev, irqwait->irq_seq);
 }
 
 static void radeon_enable_interrupt(struct drm_device *dev)
@@ -320,7 +312,7 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
        drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
        if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
                DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        dev_priv->vblank_crtc = (unsigned int)value;
        radeon_enable_interrupt(dev);
index 517cad8b6e3a586b825a14ea3e0118f864846c8e..a29acfe2f973c970a3dfbf7600fd7530582fd53d 100644 (file)
@@ -39,7 +39,7 @@
  */
 
 static struct mem_block *split_block(struct mem_block *p, int start, int size,
-                                    DRMFILE filp)
+                                    struct drm_file *file_priv)
 {
        /* Maybe cut off the start of an existing block */
        if (start > p->start) {
@@ -49,7 +49,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
                        goto out;
                newblock->start = start;
                newblock->size = p->size - (start - p->start);
-               newblock->filp = NULL;
+               newblock->file_priv = NULL;
                newblock->next = p->next;
                newblock->prev = p;
                p->next->prev = newblock;
@@ -66,7 +66,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
                        goto out;
                newblock->start = start + size;
                newblock->size = p->size - size;
-               newblock->filp = NULL;
+               newblock->file_priv = NULL;
                newblock->next = p->next;
                newblock->prev = p;
                p->next->prev = newblock;
@@ -76,20 +76,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
 
       out:
        /* Our block is in the middle */
-       p->filp = filp;
+       p->file_priv = file_priv;
        return p;
 }
 
 static struct mem_block *alloc_block(struct mem_block *heap, int size,
-                                    int align2, DRMFILE filp)
+                                    int align2, struct drm_file *file_priv)
 {
        struct mem_block *p;
        int mask = (1 << align2) - 1;
 
        list_for_each(p, heap) {
                int start = (p->start + mask) & ~mask;
-               if (p->filp == 0 && start + size <= p->start + p->size)
-                       return split_block(p, start, size, filp);
+               if (p->file_priv == 0 && start + size <= p->start + p->size)
+                       return split_block(p, start, size, file_priv);
        }
 
        return NULL;
@@ -108,12 +108,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start)
 
 static void free_block(struct mem_block *p)
 {
-       p->filp = NULL;
+       p->file_priv = NULL;
 
-       /* Assumes a single contiguous range.  Needs a special filp in
+       /* Assumes a single contiguous range.  Needs a special file_priv in
         * 'heap' to stop it being subsumed.
         */
-       if (p->next->filp == 0) {
+       if (p->next->file_priv == 0) {
                struct mem_block *q = p->next;
                p->size += q->size;
                p->next = q->next;
@@ -121,7 +121,7 @@ static void free_block(struct mem_block *p)
                drm_free(q, sizeof(*q), DRM_MEM_BUFS);
        }
 
-       if (p->prev->filp == 0) {
+       if (p->prev->file_priv == 0) {
                struct mem_block *q = p->prev;
                q->size += p->size;
                q->next = p->next;
@@ -137,28 +137,28 @@ static int init_heap(struct mem_block **heap, int start, int size)
        struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
 
        if (!blocks)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS);
        if (!*heap) {
                drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        blocks->start = start;
        blocks->size = size;
-       blocks->filp = NULL;
+       blocks->file_priv = NULL;
        blocks->next = blocks->prev = *heap;
 
        memset(*heap, 0, sizeof(**heap));
-       (*heap)->filp = (DRMFILE) - 1;
+       (*heap)->file_priv = (struct drm_file *) - 1;
        (*heap)->next = (*heap)->prev = blocks;
        return 0;
 }
 
 /* Free all blocks associated with the releasing file.
  */
-void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
+void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap)
 {
        struct mem_block *p;
 
@@ -166,15 +166,15 @@ void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
                return;
 
        list_for_each(p, heap) {
-               if (p->filp == filp)
-                       p->filp = NULL;
+               if (p->file_priv == file_priv)
+                       p->file_priv = NULL;
        }
 
-       /* Assumes a single contiguous range.  Needs a special filp in
+       /* Assumes a single contiguous range.  Needs a special file_priv in
         * 'heap' to stop it being subsumed.
         */
        list_for_each(p, heap) {
-               while (p->filp == 0 && p->next->filp == 0) {
+               while (p->file_priv == 0 && p->next->file_priv == 0) {
                        struct mem_block *q = p->next;
                        p->size += q->size;
                        p->next = q->next;
@@ -217,98 +217,86 @@ static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region)
        }
 }
 
-int radeon_mem_alloc(DRM_IOCTL_ARGS)
+int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_mem_alloc_t alloc;
+       drm_radeon_mem_alloc_t *alloc = data;
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(alloc, (drm_radeon_mem_alloc_t __user *) data,
-                                sizeof(alloc));
-
-       heap = get_heap(dev_priv, alloc.region);
+       heap = get_heap(dev_priv, alloc->region);
        if (!heap || !*heap)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
        /* Make things easier on ourselves: all allocations at least
         * 4k aligned.
         */
-       if (alloc.alignment < 12)
-               alloc.alignment = 12;
+       if (alloc->alignment < 12)
+               alloc->alignment = 12;
 
-       block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
+       block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
 
        if (!block)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
-       if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
+       if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
+                            sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
 }
 
-int radeon_mem_free(DRM_IOCTL_ARGS)
+int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_mem_free_t memfree;
+       drm_radeon_mem_free_t *memfree = data;
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
-                                sizeof(memfree));
-
-       heap = get_heap(dev_priv, memfree.region);
+       heap = get_heap(dev_priv, memfree->region);
        if (!heap || !*heap)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
-       block = find_block(*heap, memfree.region_offset);
+       block = find_block(*heap, memfree->region_offset);
        if (!block)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
-       if (block->filp != filp)
-               return DRM_ERR(EPERM);
+       if (block->file_priv != file_priv)
+               return -EPERM;
 
        free_block(block);
        return 0;
 }
 
-int radeon_mem_init_heap(DRM_IOCTL_ARGS)
+int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_mem_init_heap_t initheap;
+       drm_radeon_mem_init_heap_t *initheap = data;
        struct mem_block **heap;
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(initheap,
-                                (drm_radeon_mem_init_heap_t __user *) data,
-                                sizeof(initheap));
-
-       heap = get_heap(dev_priv, initheap.region);
+       heap = get_heap(dev_priv, initheap->region);
        if (!heap)
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
        if (*heap) {
                DRM_ERROR("heap already initialized?");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
-       return init_heap(heap, initheap.start, initheap.size);
+       return init_heap(heap, initheap->start, initheap->size);
 }
index 3ddf86f2abf0d9ecd4ab1b47ed70fef3390fbd94..69c9f2febf43a9b42bb05dada49ac9df8e572c46 100644 (file)
@@ -39,7 +39,7 @@
 
 static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
                                                    dev_priv,
-                                                   struct drm_file * filp_priv,
+                                                   struct drm_file * file_priv,
                                                    u32 *offset)
 {
        u64 off = *offset;
@@ -71,7 +71,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
         * magic offset we get from SETPARAM or calculated from fb_location
         */
        if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
-               radeon_priv = filp_priv->driver_priv;
+               radeon_priv = file_priv->driver_priv;
                off += radeon_priv->radeon_fb_delta;
        }
 
@@ -85,29 +85,29 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
                *offset = off;
                return 0;
        }
-       return DRM_ERR(EINVAL);
+       return -EINVAL;
 }
 
 static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
                                                     dev_priv,
-                                                    struct drm_file * filp_priv,
+                                                    struct drm_file *file_priv,
                                                     int id, u32 *data)
 {
        switch (id) {
 
        case RADEON_EMIT_PP_MISC:
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                    &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
                        DRM_ERROR("Invalid depth buffer offset\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
 
        case RADEON_EMIT_PP_CNTL:
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                    &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
                        DRM_ERROR("Invalid colour buffer offset\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
 
@@ -117,20 +117,20 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
        case R200_EMIT_PP_TXOFFSET_3:
        case R200_EMIT_PP_TXOFFSET_4:
        case R200_EMIT_PP_TXOFFSET_5:
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                                                  &data[0])) {
                        DRM_ERROR("Invalid R200 texture offset\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
 
        case RADEON_EMIT_PP_TXFILTER_0:
        case RADEON_EMIT_PP_TXFILTER_1:
        case RADEON_EMIT_PP_TXFILTER_2:
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                    &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
                        DRM_ERROR("Invalid R100 texture offset\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
 
@@ -143,11 +143,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
                        int i;
                        for (i = 0; i < 5; i++) {
                                if (radeon_check_and_fixup_offset(dev_priv,
-                                                                 filp_priv,
+                                                                 file_priv,
                                                                  &data[i])) {
                                        DRM_ERROR
                                            ("Invalid R200 cubic texture offset\n");
-                                       return DRM_ERR(EINVAL);
+                                       return -EINVAL;
                                }
                        }
                        break;
@@ -159,11 +159,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
                        int i;
                        for (i = 0; i < 5; i++) {
                                if (radeon_check_and_fixup_offset(dev_priv,
-                                                                 filp_priv,
+                                                                 file_priv,
                                                                  &data[i])) {
                                        DRM_ERROR
                                            ("Invalid R100 cubic texture offset\n");
-                                       return DRM_ERR(EINVAL);
+                                       return -EINVAL;
                                }
                        }
                }
@@ -256,7 +256,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
 
        default:
                DRM_ERROR("Unknown state packet ID %d\n", id);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        return 0;
@@ -264,7 +264,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
 
 static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
                                                     dev_priv,
-                                                    struct drm_file *filp_priv,
+                                                    struct drm_file *file_priv,
                                                     drm_radeon_kcmd_buffer_t *
                                                     cmdbuf,
                                                     unsigned int *cmdsz)
@@ -277,12 +277,12 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
 
        if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
                DRM_ERROR("Not a type 3 packet\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (4 * *cmdsz > cmdbuf->bufsz) {
                DRM_ERROR("Packet size larger than size of data provided\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        switch(cmd[0] & 0xff00) {
@@ -307,7 +307,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
                /* safe but r200 only */
                if (dev_priv->microcode_version != UCODE_R200) {
                        DRM_ERROR("Invalid 3d packet for r100-class chip\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
 
@@ -317,7 +317,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
                if (count > 18) { /* 12 arrays max */
                        DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
                                  count);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                /* carefully check packet contents */
@@ -326,22 +326,25 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
                i = 2;
                while ((k < narrays) && (i < (count + 2))) {
                        i++;            /* skip attribute field */
-                       if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+                       if (radeon_check_and_fixup_offset(dev_priv, file_priv,
+                                                         &cmd[i])) {
                                DRM_ERROR
                                    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
                                     k, i);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        k++;
                        i++;
                        if (k == narrays)
                                break;
                        /* have one more to process, they come in pairs */
-                       if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+                       if (radeon_check_and_fixup_offset(dev_priv,
+                                                         file_priv, &cmd[i]))
+                       {
                                DRM_ERROR
                                    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
                                     k, i);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        k++;
                        i++;
@@ -351,33 +354,33 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
                        DRM_ERROR
                            ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
                              k, i, narrays, count + 1);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
 
        case RADEON_3D_RNDR_GEN_INDX_PRIM:
                if (dev_priv->microcode_version != UCODE_R100) {
                        DRM_ERROR("Invalid 3d packet for r200-class chip\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) {
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) {
                                DRM_ERROR("Invalid rndr_gen_indx offset\n");
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                }
                break;
 
        case RADEON_CP_INDX_BUFFER:
                if (dev_priv->microcode_version != UCODE_R200) {
                        DRM_ERROR("Invalid 3d packet for r100-class chip\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                if ((cmd[1] & 0x8000ffff) != 0x80000810) {
                        DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) {
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) {
                        DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
 
@@ -389,9 +392,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
                              | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
                        offset = cmd[2] << 10;
                        if (radeon_check_and_fixup_offset
-                           (dev_priv, filp_priv, &offset)) {
+                           (dev_priv, file_priv, &offset)) {
                                DRM_ERROR("Invalid first packet offset\n");
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
                }
@@ -400,9 +403,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
                    (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
                        offset = cmd[3] << 10;
                        if (radeon_check_and_fixup_offset
-                           (dev_priv, filp_priv, &offset)) {
+                           (dev_priv, file_priv, &offset)) {
                                DRM_ERROR("Invalid second packet offset\n");
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
                }
@@ -410,7 +413,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
 
        default:
                DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        return 0;
@@ -439,7 +442,7 @@ static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
 /* Emit 1.1 state
  */
 static int radeon_emit_state(drm_radeon_private_t * dev_priv,
-                            struct drm_file * filp_priv,
+                            struct drm_file *file_priv,
                             drm_radeon_context_regs_t * ctx,
                             drm_radeon_texture_regs_t * tex,
                             unsigned int dirty)
@@ -448,16 +451,16 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
        DRM_DEBUG("dirty=0x%08x\n", dirty);
 
        if (dirty & RADEON_UPLOAD_CONTEXT) {
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                                                  &ctx->rb3d_depthoffset)) {
                        DRM_ERROR("Invalid depth buffer offset\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                                                  &ctx->rb3d_coloroffset)) {
                        DRM_ERROR("Invalid depth buffer offset\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                BEGIN_RING(14);
@@ -543,10 +546,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
        }
 
        if (dirty & RADEON_UPLOAD_TEX0) {
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                                                  &tex[0].pp_txoffset)) {
                        DRM_ERROR("Invalid texture offset for unit 0\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                BEGIN_RING(9);
@@ -563,10 +566,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
        }
 
        if (dirty & RADEON_UPLOAD_TEX1) {
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                                                  &tex[1].pp_txoffset)) {
                        DRM_ERROR("Invalid texture offset for unit 1\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                BEGIN_RING(9);
@@ -583,10 +586,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
        }
 
        if (dirty & RADEON_UPLOAD_TEX2) {
-               if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+               if (radeon_check_and_fixup_offset(dev_priv, file_priv,
                                                  &tex[2].pp_txoffset)) {
                        DRM_ERROR("Invalid texture offset for unit 2\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                BEGIN_RING(9);
@@ -608,7 +611,7 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
 /* Emit 1.2 state
  */
 static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
-                             struct drm_file * filp_priv,
+                             struct drm_file *file_priv,
                              drm_radeon_state_t * state)
 {
        RING_LOCALS;
@@ -621,7 +624,7 @@ static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
                ADVANCE_RING();
        }
 
-       return radeon_emit_state(dev_priv, filp_priv, &state->context,
+       return radeon_emit_state(dev_priv, file_priv, &state->context,
                                 state->tex, state->dirty);
 }
 
@@ -1646,13 +1649,12 @@ static void radeon_cp_dispatch_indices(struct drm_device * dev,
 
 #define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
 
-static int radeon_cp_dispatch_texture(DRMFILE filp,
-                                     struct drm_device * dev,
+static int radeon_cp_dispatch_texture(struct drm_device * dev,
+                                     struct drm_file *file_priv,
                                      drm_radeon_texture_t * tex,
                                      drm_radeon_tex_image_t * image)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       struct drm_file *filp_priv;
        struct drm_buf *buf;
        u32 format;
        u32 *buffer;
@@ -1664,11 +1666,9 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
        u32 offset;
        RING_LOCALS;
 
-       DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
-       if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
+       if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
                DRM_ERROR("Invalid destination offset\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
@@ -1711,11 +1711,11 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
                break;
        default:
                DRM_ERROR("invalid texture format %d\n", tex->format);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        spitch = blit_width >> 6;
        if (spitch == 0 && image->height > 1)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        texpitch = tex->pitch;
        if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
@@ -1760,8 +1760,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
                if (!buf) {
                        DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
                        if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
-                               return DRM_ERR(EFAULT);
-                       return DRM_ERR(EAGAIN);
+                               return -EFAULT;
+                       return -EAGAIN;
                }
 
                /* Dispatch the indirect buffer.
@@ -1774,7 +1774,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
        do { \
                if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
                        DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
-                       return DRM_ERR(EFAULT); \
+                       return -EFAULT; \
                } \
        } while(0)
 
@@ -1841,7 +1841,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
                }
 
 #undef RADEON_COPY_MT
-               buf->filp = filp;
+               buf->file_priv = file_priv;
                buf->used = size;
                offset = dev_priv->gart_buffers_offset + buf->offset;
                BEGIN_RING(9);
@@ -1861,6 +1861,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
                OUT_RING((image->width << 16) | height);
                RADEON_WAIT_UNTIL_2D_IDLE();
                ADVANCE_RING();
+               COMMIT_RING();
 
                radeon_cp_discard_buffer(dev, buf);
 
@@ -1878,6 +1879,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
        RADEON_FLUSH_CACHE();
        RADEON_WAIT_UNTIL_2D_IDLE();
        ADVANCE_RING();
+       COMMIT_RING();
+
        return 0;
 }
 
@@ -1929,7 +1932,8 @@ static void radeon_apply_surface_regs(int surf_index,
  * not always be available.
  */
 static int alloc_surface(drm_radeon_surface_alloc_t *new,
-                        drm_radeon_private_t *dev_priv, DRMFILE filp)
+                        drm_radeon_private_t *dev_priv,
+                        struct drm_file *file_priv)
 {
        struct radeon_virt_surface *s;
        int i;
@@ -1959,7 +1963,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
 
        /* find a virtual surface */
        for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
-               if (dev_priv->virt_surfaces[i].filp == 0)
+               if (dev_priv->virt_surfaces[i].file_priv == 0)
                        break;
        if (i == 2 * RADEON_MAX_SURFACES) {
                return -1;
@@ -1977,7 +1981,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
                        s->lower = new_lower;
                        s->upper = new_upper;
                        s->flags = new->flags;
-                       s->filp = filp;
+                       s->file_priv = file_priv;
                        dev_priv->surfaces[i].refcount++;
                        dev_priv->surfaces[i].lower = s->lower;
                        radeon_apply_surface_regs(s->surface_index, dev_priv);
@@ -1993,7 +1997,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
                        s->lower = new_lower;
                        s->upper = new_upper;
                        s->flags = new->flags;
-                       s->filp = filp;
+                       s->file_priv = file_priv;
                        dev_priv->surfaces[i].refcount++;
                        dev_priv->surfaces[i].upper = s->upper;
                        radeon_apply_surface_regs(s->surface_index, dev_priv);
@@ -2009,7 +2013,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
                        s->lower = new_lower;
                        s->upper = new_upper;
                        s->flags = new->flags;
-                       s->filp = filp;
+                       s->file_priv = file_priv;
                        dev_priv->surfaces[i].refcount = 1;
                        dev_priv->surfaces[i].lower = s->lower;
                        dev_priv->surfaces[i].upper = s->upper;
@@ -2023,7 +2027,8 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
        return -1;
 }
 
-static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
+static int free_surface(struct drm_file *file_priv,
+                       drm_radeon_private_t * dev_priv,
                        int lower)
 {
        struct radeon_virt_surface *s;
@@ -2031,8 +2036,9 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
        /* find the virtual surface */
        for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
                s = &(dev_priv->virt_surfaces[i]);
-               if (s->filp) {
-                       if ((lower == s->lower) && (filp == s->filp)) {
+               if (s->file_priv) {
+                       if ((lower == s->lower) && (file_priv == s->file_priv))
+                       {
                                if (dev_priv->surfaces[s->surface_index].
                                    lower == s->lower)
                                        dev_priv->surfaces[s->surface_index].
@@ -2048,7 +2054,7 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
                                    refcount == 0)
                                        dev_priv->surfaces[s->surface_index].
                                            flags = 0;
-                               s->filp = NULL;
+                               s->file_priv = NULL;
                                radeon_apply_surface_regs(s->surface_index,
                                                          dev_priv);
                                return 0;
@@ -2058,13 +2064,13 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
        return 1;
 }
 
-static void radeon_surfaces_release(DRMFILE filp,
+static void radeon_surfaces_release(struct drm_file *file_priv,
                                    drm_radeon_private_t * dev_priv)
 {
        int i;
        for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
-               if (dev_priv->virt_surfaces[i].filp == filp)
-                       free_surface(filp, dev_priv,
+               if (dev_priv->virt_surfaces[i].file_priv == file_priv)
+                       free_surface(file_priv, dev_priv,
                                     dev_priv->virt_surfaces[i].lower);
        }
 }
@@ -2072,61 +2078,48 @@ static void radeon_surfaces_release(DRMFILE filp,
 /* ================================================================
  * IOCTL functions
  */
-static int radeon_surface_alloc(DRM_IOCTL_ARGS)
+static int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_surface_alloc_t alloc;
+       drm_radeon_surface_alloc_t *alloc = data;
 
-       DRM_COPY_FROM_USER_IOCTL(alloc,
-                                (drm_radeon_surface_alloc_t __user *) data,
-                                sizeof(alloc));
-
-       if (alloc_surface(&alloc, dev_priv, filp) == -1)
-               return DRM_ERR(EINVAL);
+       if (alloc_surface(alloc, dev_priv, file_priv) == -1)
+               return -EINVAL;
        else
                return 0;
 }
 
-static int radeon_surface_free(DRM_IOCTL_ARGS)
+static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_surface_free_t memfree;
-
-       DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
-                                sizeof(memfree));
+       drm_radeon_surface_free_t *memfree = data;
 
-       if (free_surface(filp, dev_priv, memfree.address))
-               return DRM_ERR(EINVAL);
+       if (free_surface(file_priv, dev_priv, memfree->address))
+               return -EINVAL;
        else
                return 0;
 }
 
-static int radeon_cp_clear(DRM_IOCTL_ARGS)
+static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
        drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-       drm_radeon_clear_t clear;
+       drm_radeon_clear_t *clear = data;
        drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
-                                sizeof(clear));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
        if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
 
-       if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
+       if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes,
                               sarea_priv->nbox * sizeof(depth_boxes[0])))
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
-       radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
+       radeon_cp_dispatch_clear(dev, clear, depth_boxes);
 
        COMMIT_RING();
        return 0;
@@ -2162,13 +2155,12 @@ static int radeon_do_init_pageflip(struct drm_device * dev)
 /* Swapping and flipping are different operations, need different ioctls.
  * They can & should be intermixed to support multiple 3d windows.
  */
-static int radeon_cp_flip(DRM_IOCTL_ARGS)
+static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
@@ -2181,14 +2173,13 @@ static int radeon_cp_flip(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int radeon_cp_swap(DRM_IOCTL_ARGS)
+static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
        drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
@@ -2202,64 +2193,57 @@ static int radeon_cp_swap(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int radeon_cp_vertex(DRM_IOCTL_ARGS)
+static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       struct drm_file *filp_priv;
        drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
-       drm_radeon_vertex_t vertex;
+       drm_radeon_vertex_t *vertex = data;
        drm_radeon_tcl_prim_t prim;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
-                                sizeof(vertex));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
-                 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
+                 DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
 
-       if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+       if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         vertex.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         vertex->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
-       if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
-               DRM_ERROR("buffer prim %d\n", vertex.prim);
-               return DRM_ERR(EINVAL);
+       if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
+               DRM_ERROR("buffer prim %d\n", vertex->prim);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       buf = dma->buflist[vertex.idx];
+       buf = dma->buflist[vertex->idx];
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
        if (buf->pending) {
-               DRM_ERROR("sending pending buffer %d\n", vertex.idx);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+               return -EINVAL;
        }
 
        /* Build up a prim_t record:
         */
-       if (vertex.count) {
-               buf->used = vertex.count;       /* not used? */
+       if (vertex->count) {
+               buf->used = vertex->count;      /* not used? */
 
                if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
-                       if (radeon_emit_state(dev_priv, filp_priv,
+                       if (radeon_emit_state(dev_priv, file_priv,
                                              &sarea_priv->context_state,
                                              sarea_priv->tex_state,
                                              sarea_priv->dirty)) {
                                DRM_ERROR("radeon_emit_state failed\n");
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
 
                        sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
@@ -2269,15 +2253,15 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
                }
 
                prim.start = 0;
-               prim.finish = vertex.count;     /* unused */
-               prim.prim = vertex.prim;
-               prim.numverts = vertex.count;
+               prim.finish = vertex->count;    /* unused */
+               prim.prim = vertex->prim;
+               prim.numverts = vertex->count;
                prim.vc_format = dev_priv->sarea_priv->vc_format;
 
                radeon_cp_dispatch_vertex(dev, buf, &prim);
        }
 
-       if (vertex.discard) {
+       if (vertex->discard) {
                radeon_cp_discard_buffer(dev, buf);
        }
 
@@ -2285,74 +2269,68 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int radeon_cp_indices(DRM_IOCTL_ARGS)
+static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       struct drm_file *filp_priv;
        drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
-       drm_radeon_indices_t elts;
+       drm_radeon_indices_t *elts = data;
        drm_radeon_tcl_prim_t prim;
        int count;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
-                                sizeof(elts));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
-                 DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
+                 DRM_CURRENTPID, elts->idx, elts->start, elts->end,
+                 elts->discard);
 
-       if (elts.idx < 0 || elts.idx >= dma->buf_count) {
+       if (elts->idx < 0 || elts->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         elts.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         elts->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
-       if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
-               DRM_ERROR("buffer prim %d\n", elts.prim);
-               return DRM_ERR(EINVAL);
+       if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
+               DRM_ERROR("buffer prim %d\n", elts->prim);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       buf = dma->buflist[elts.idx];
+       buf = dma->buflist[elts->idx];
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
        if (buf->pending) {
-               DRM_ERROR("sending pending buffer %d\n", elts.idx);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("sending pending buffer %d\n", elts->idx);
+               return -EINVAL;
        }
 
-       count = (elts.end - elts.start) / sizeof(u16);
-       elts.start -= RADEON_INDEX_PRIM_OFFSET;
+       count = (elts->end - elts->start) / sizeof(u16);
+       elts->start -= RADEON_INDEX_PRIM_OFFSET;
 
-       if (elts.start & 0x7) {
-               DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
-               return DRM_ERR(EINVAL);
+       if (elts->start & 0x7) {
+               DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
+               return -EINVAL;
        }
-       if (elts.start < buf->used) {
-               DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
-               return DRM_ERR(EINVAL);
+       if (elts->start < buf->used) {
+               DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
+               return -EINVAL;
        }
 
-       buf->used = elts.end;
+       buf->used = elts->end;
 
        if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
-               if (radeon_emit_state(dev_priv, filp_priv,
+               if (radeon_emit_state(dev_priv, file_priv,
                                      &sarea_priv->context_state,
                                      sarea_priv->tex_state,
                                      sarea_priv->dirty)) {
                        DRM_ERROR("radeon_emit_state failed\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
 
                sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
@@ -2363,15 +2341,15 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
 
        /* Build up a prim_t record:
         */
-       prim.start = elts.start;
-       prim.finish = elts.end;
-       prim.prim = elts.prim;
+       prim.start = elts->start;
+       prim.finish = elts->end;
+       prim.prim = elts->prim;
        prim.offset = 0;        /* offset from start of dma buffers */
        prim.numverts = RADEON_MAX_VB_VERTS;    /* duh */
        prim.vc_format = dev_priv->sarea_priv->vc_format;
 
        radeon_cp_dispatch_indices(dev, buf, &prim);
-       if (elts.discard) {
+       if (elts->discard) {
                radeon_cp_discard_buffer(dev, buf);
        }
 
@@ -2379,52 +2357,43 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int radeon_cp_texture(DRM_IOCTL_ARGS)
+static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_texture_t tex;
+       drm_radeon_texture_t *tex = data;
        drm_radeon_tex_image_t image;
        int ret;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
-                                sizeof(tex));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (tex.image == NULL) {
+       if (tex->image == NULL) {
                DRM_ERROR("null texture image!\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (DRM_COPY_FROM_USER(&image,
-                              (drm_radeon_tex_image_t __user *) tex.image,
+                              (drm_radeon_tex_image_t __user *) tex->image,
                               sizeof(image)))
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
+       ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
 
-       COMMIT_RING();
        return ret;
 }
 
-static int radeon_cp_stipple(DRM_IOCTL_ARGS)
+static int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_stipple_t stipple;
+       drm_radeon_stipple_t *stipple = data;
        u32 mask[32];
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
-                                sizeof(stipple));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
-               return DRM_ERR(EFAULT);
+       if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+               return -EFAULT;
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
@@ -2434,52 +2403,48 @@ static int radeon_cp_stipple(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int radeon_cp_indirect(DRM_IOCTL_ARGS)
+static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
-       drm_radeon_indirect_t indirect;
+       drm_radeon_indirect_t *indirect = data;
        RING_LOCALS;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(indirect,
-                                (drm_radeon_indirect_t __user *) data,
-                                sizeof(indirect));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
-                 indirect.idx, indirect.start, indirect.end, indirect.discard);
+                 indirect->idx, indirect->start, indirect->end,
+                 indirect->discard);
 
-       if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
+       if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         indirect.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         indirect->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
 
-       buf = dma->buflist[indirect.idx];
+       buf = dma->buflist[indirect->idx];
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
        if (buf->pending) {
-               DRM_ERROR("sending pending buffer %d\n", indirect.idx);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("sending pending buffer %d\n", indirect->idx);
+               return -EINVAL;
        }
 
-       if (indirect.start < buf->used) {
+       if (indirect->start < buf->used) {
                DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
-                         indirect.start, buf->used);
-               return DRM_ERR(EINVAL);
+                         indirect->start, buf->used);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       buf->used = indirect.end;
+       buf->used = indirect->end;
 
        /* Wait for the 3D stream to idle before the indirect buffer
         * containing 2D acceleration commands is processed.
@@ -2494,8 +2459,8 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
         * X server.  This is insecure and is thus only available to
         * privileged clients.
         */
-       radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
-       if (indirect.discard) {
+       radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
+       if (indirect->discard) {
                radeon_cp_discard_buffer(dev, buf);
        }
 
@@ -2503,71 +2468,64 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
        return 0;
 }
 
-static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
+static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       struct drm_file *filp_priv;
        drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
-       drm_radeon_vertex2_t vertex;
+       drm_radeon_vertex2_t *vertex = data;
        int i;
        unsigned char laststate;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
-                                sizeof(vertex));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        DRM_DEBUG("pid=%d index=%d discard=%d\n",
-                 DRM_CURRENTPID, vertex.idx, vertex.discard);
+                 DRM_CURRENTPID, vertex->idx, vertex->discard);
 
-       if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+       if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
                DRM_ERROR("buffer index %d (of %d max)\n",
-                         vertex.idx, dma->buf_count - 1);
-               return DRM_ERR(EINVAL);
+                         vertex->idx, dma->buf_count - 1);
+               return -EINVAL;
        }
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       buf = dma->buflist[vertex.idx];
+       buf = dma->buflist[vertex->idx];
 
-       if (buf->filp != filp) {
+       if (buf->file_priv != file_priv) {
                DRM_ERROR("process %d using buffer owned by %p\n",
-                         DRM_CURRENTPID, buf->filp);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, buf->file_priv);
+               return -EINVAL;
        }
 
        if (buf->pending) {
-               DRM_ERROR("sending pending buffer %d\n", vertex.idx);
-               return DRM_ERR(EINVAL);
+               DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+               return -EINVAL;
        }
 
        if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
-       for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
+       for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) {
                drm_radeon_prim_t prim;
                drm_radeon_tcl_prim_t tclprim;
 
-               if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
-                       return DRM_ERR(EFAULT);
+               if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim)))
+                       return -EFAULT;
 
                if (prim.stateidx != laststate) {
                        drm_radeon_state_t state;
 
                        if (DRM_COPY_FROM_USER(&state,
-                                              &vertex.state[prim.stateidx],
+                                              &vertex->state[prim.stateidx],
                                               sizeof(state)))
-                               return DRM_ERR(EFAULT);
+                               return -EFAULT;
 
-                       if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
+                       if (radeon_emit_state2(dev_priv, file_priv, &state)) {
                                DRM_ERROR("radeon_emit_state2 failed\n");
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
 
                        laststate = prim.stateidx;
@@ -2594,7 +2552,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
                        sarea_priv->nbox = 0;
        }
 
-       if (vertex.discard) {
+       if (vertex->discard) {
                radeon_cp_discard_buffer(dev, buf);
        }
 
@@ -2603,7 +2561,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
 }
 
 static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
-                              struct drm_file * filp_priv,
+                              struct drm_file *file_priv,
                               drm_radeon_cmd_header_t header,
                               drm_radeon_kcmd_buffer_t *cmdbuf)
 {
@@ -2613,19 +2571,19 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
        RING_LOCALS;
 
        if (id >= RADEON_MAX_STATE_PACKETS)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
        sz = packet[id].len;
        reg = packet[id].start;
 
        if (sz * sizeof(int) > cmdbuf->bufsz) {
                DRM_ERROR("Packet size provided larger than data provided\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
+       if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, data)) {
                DRM_ERROR("Packet verification failed\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        BEGIN_RING(sz + 1);
@@ -2713,7 +2671,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
         if (!sz)
                 return 0;
         if (sz * 4 > cmdbuf->bufsz)
-                return DRM_ERR(EINVAL);
+                return -EINVAL;
 
        BEGIN_RING(5 + sz);
        OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
@@ -2729,7 +2687,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
 }
 
 static int radeon_emit_packet3(struct drm_device * dev,
-                              struct drm_file * filp_priv,
+                              struct drm_file *file_priv,
                               drm_radeon_kcmd_buffer_t *cmdbuf)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2739,7 +2697,7 @@ static int radeon_emit_packet3(struct drm_device * dev,
 
        DRM_DEBUG("\n");
 
-       if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
+       if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
                                                  cmdbuf, &cmdsz))) {
                DRM_ERROR("Packet verification failed\n");
                return ret;
@@ -2755,7 +2713,7 @@ static int radeon_emit_packet3(struct drm_device * dev,
 }
 
 static int radeon_emit_packet3_cliprect(struct drm_device *dev,
-                                       struct drm_file *filp_priv,
+                                       struct drm_file *file_priv,
                                        drm_radeon_kcmd_buffer_t *cmdbuf,
                                        int orig_nbox)
 {
@@ -2769,7 +2727,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
 
        DRM_DEBUG("\n");
 
-       if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
+       if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
                                                  cmdbuf, &cmdsz))) {
                DRM_ERROR("Packet verification failed\n");
                return ret;
@@ -2781,7 +2739,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
        do {
                if (i < cmdbuf->nbox) {
                        if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
-                               return DRM_ERR(EFAULT);
+                               return -EFAULT;
                        /* FIXME The second and subsequent times round
                         * this loop, send a WAIT_UNTIL_3D_IDLE before
                         * calling emit_clip_rect(). This fixes a
@@ -2839,62 +2797,54 @@ static int radeon_emit_wait(struct drm_device * dev, int flags)
                ADVANCE_RING();
                break;
        default:
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        return 0;
 }
 
-static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
+static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       struct drm_file *filp_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf = NULL;
        int idx;
-       drm_radeon_kcmd_buffer_t cmdbuf;
+       drm_radeon_kcmd_buffer_t *cmdbuf = data;
        drm_radeon_cmd_header_t header;
        int orig_nbox, orig_bufsz;
        char *kbuf = NULL;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(cmdbuf,
-                                (drm_radeon_cmd_buffer_t __user *) data,
-                                sizeof(cmdbuf));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
-               return DRM_ERR(EINVAL);
+       if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) {
+               return -EINVAL;
        }
 
        /* Allocate an in-kernel area and copy in the cmdbuf.  Do this to avoid
         * races between checking values and using those values in other code,
         * and simply to avoid a lot of function calls to copy in data.
         */
-       orig_bufsz = cmdbuf.bufsz;
+       orig_bufsz = cmdbuf->bufsz;
        if (orig_bufsz != 0) {
-               kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
+               kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER);
                if (kbuf == NULL)
-                       return DRM_ERR(ENOMEM);
-               if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
-                                      cmdbuf.bufsz)) {
+                       return -ENOMEM;
+               if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf,
+                                      cmdbuf->bufsz)) {
                        drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
                }
-               cmdbuf.buf = kbuf;
+               cmdbuf->buf = kbuf;
        }
 
-       orig_nbox = cmdbuf.nbox;
+       orig_nbox = cmdbuf->nbox;
 
        if (dev_priv->microcode_version == UCODE_R300) {
                int temp;
-               temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
+               temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
 
                if (orig_bufsz != 0)
                        drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
@@ -2903,17 +2853,17 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
        }
 
        /* microcode_version != r300 */
-       while (cmdbuf.bufsz >= sizeof(header)) {
+       while (cmdbuf->bufsz >= sizeof(header)) {
 
-               header.i = *(int *)cmdbuf.buf;
-               cmdbuf.buf += sizeof(header);
-               cmdbuf.bufsz -= sizeof(header);
+               header.i = *(int *)cmdbuf->buf;
+               cmdbuf->buf += sizeof(header);
+               cmdbuf->bufsz -= sizeof(header);
 
                switch (header.header.cmd_type) {
                case RADEON_CMD_PACKET:
                        DRM_DEBUG("RADEON_CMD_PACKET\n");
                        if (radeon_emit_packets
-                           (dev_priv, filp_priv, header, &cmdbuf)) {
+                           (dev_priv, file_priv, header, cmdbuf)) {
                                DRM_ERROR("radeon_emit_packets failed\n");
                                goto err;
                        }
@@ -2921,7 +2871,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
 
                case RADEON_CMD_SCALARS:
                        DRM_DEBUG("RADEON_CMD_SCALARS\n");
-                       if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
+                       if (radeon_emit_scalars(dev_priv, header, cmdbuf)) {
                                DRM_ERROR("radeon_emit_scalars failed\n");
                                goto err;
                        }
@@ -2929,7 +2879,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
 
                case RADEON_CMD_VECTORS:
                        DRM_DEBUG("RADEON_CMD_VECTORS\n");
-                       if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
+                       if (radeon_emit_vectors(dev_priv, header, cmdbuf)) {
                                DRM_ERROR("radeon_emit_vectors failed\n");
                                goto err;
                        }
@@ -2945,9 +2895,10 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
                        }
 
                        buf = dma->buflist[idx];
-                       if (buf->filp != filp || buf->pending) {
+                       if (buf->file_priv != file_priv || buf->pending) {
                                DRM_ERROR("bad buffer %p %p %d\n",
-                                         buf->filp, filp, buf->pending);
+                                         buf->file_priv, file_priv,
+                                         buf->pending);
                                goto err;
                        }
 
@@ -2956,7 +2907,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
 
                case RADEON_CMD_PACKET3:
                        DRM_DEBUG("RADEON_CMD_PACKET3\n");
-                       if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
+                       if (radeon_emit_packet3(dev, file_priv, cmdbuf)) {
                                DRM_ERROR("radeon_emit_packet3 failed\n");
                                goto err;
                        }
@@ -2965,7 +2916,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
                case RADEON_CMD_PACKET3_CLIP:
                        DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
                        if (radeon_emit_packet3_cliprect
-                           (dev, filp_priv, &cmdbuf, orig_nbox)) {
+                           (dev, file_priv, cmdbuf, orig_nbox)) {
                                DRM_ERROR("radeon_emit_packet3_clip failed\n");
                                goto err;
                        }
@@ -2973,7 +2924,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
 
                case RADEON_CMD_SCALARS2:
                        DRM_DEBUG("RADEON_CMD_SCALARS2\n");
-                       if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
+                       if (radeon_emit_scalars2(dev_priv, header, cmdbuf)) {
                                DRM_ERROR("radeon_emit_scalars2 failed\n");
                                goto err;
                        }
@@ -2988,7 +2939,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
                        break;
                case RADEON_CMD_VECLINEAR:
                        DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
-                       if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
+                       if (radeon_emit_veclinear(dev_priv, header, cmdbuf)) {
                                DRM_ERROR("radeon_emit_veclinear failed\n");
                                goto err;
                        }
@@ -2997,7 +2948,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
                default:
                        DRM_ERROR("bad cmd_type %d at %p\n",
                                  header.header.cmd_type,
-                                 cmdbuf.buf - sizeof(header));
+                                 cmdbuf->buf - sizeof(header));
                        goto err;
                }
        }
@@ -3012,22 +2963,18 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
       err:
        if (orig_bufsz != 0)
                drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
-       return DRM_ERR(EINVAL);
+       return -EINVAL;
 }
 
-static int radeon_cp_getparam(DRM_IOCTL_ARGS)
+static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_getparam_t param;
+       drm_radeon_getparam_t *param = data;
        int value;
 
-       DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
-                                sizeof(param));
-
        DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
 
-       switch (param.param) {
+       switch (param->param) {
        case RADEON_PARAM_GART_BUFFER_OFFSET:
                value = dev_priv->gart_buffers_offset;
                break;
@@ -3074,7 +3021,7 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
                break;
        case RADEON_PARAM_SCRATCH_OFFSET:
                if (!dev_priv->writeback_works)
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                value = RADEON_SCRATCH_REG_OFFSET;
                break;
        case RADEON_PARAM_CARD_TYPE:
@@ -3089,43 +3036,37 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
                value = radeon_vblank_crtc_get(dev);
                break;
        default:
-               DRM_DEBUG("Invalid parameter %d\n", param.param);
-               return DRM_ERR(EINVAL);
+               DRM_DEBUG("Invalid parameter %d\n", param->param);
+               return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        return 0;
 }
 
-static int radeon_cp_setparam(DRM_IOCTL_ARGS)
+static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       struct drm_file *filp_priv;
-       drm_radeon_setparam_t sp;
+       drm_radeon_setparam_t *sp = data;
        struct drm_radeon_driver_file_fields *radeon_priv;
 
-       DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
-                                sizeof(sp));
-
-       switch (sp.param) {
+       switch (sp->param) {
        case RADEON_SETPARAM_FB_LOCATION:
-               radeon_priv = filp_priv->driver_priv;
-               radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
+               radeon_priv = file_priv->driver_priv;
+               radeon_priv->radeon_fb_delta = dev_priv->fb_location -
+                   sp->value;
                break;
        case RADEON_SETPARAM_SWITCH_TILING:
-               if (sp.value == 0) {
+               if (sp->value == 0) {
                        DRM_DEBUG("color tiling disabled\n");
                        dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
                        dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
                        dev_priv->sarea_priv->tiling_enabled = 0;
-               } else if (sp.value == 1) {
+               } else if (sp->value == 1) {
                        DRM_DEBUG("color tiling enabled\n");
                        dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
                        dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
@@ -3133,23 +3074,23 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
                }
                break;
        case RADEON_SETPARAM_PCIGART_LOCATION:
-               dev_priv->pcigart_offset = sp.value;
+               dev_priv->pcigart_offset = sp->value;
                dev_priv->pcigart_offset_set = 1;
                break;
        case RADEON_SETPARAM_NEW_MEMMAP:
-               dev_priv->new_memmap = sp.value;
+               dev_priv->new_memmap = sp->value;
                break;
        case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
-               dev_priv->gart_info.table_size = sp.value;
+               dev_priv->gart_info.table_size = sp->value;
                if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
                        dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
                break;
        case RADEON_SETPARAM_VBLANK_CRTC:
-               return radeon_vblank_crtc_set(dev, sp.value);
+               return radeon_vblank_crtc_set(dev, sp->value);
                break;
        default:
-               DRM_DEBUG("Invalid parameter %d\n", sp.param);
-               return DRM_ERR(EINVAL);
+               DRM_DEBUG("Invalid parameter %d\n", sp->param);
+               return -EINVAL;
        }
 
        return 0;
@@ -3162,14 +3103,14 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
  *
  * DRM infrastructure takes care of reclaiming dma buffers.
  */
-void radeon_driver_preclose(struct drm_device *dev, DRMFILE filp)
+void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
 {
        if (dev->dev_private) {
                drm_radeon_private_t *dev_priv = dev->dev_private;
                dev_priv->page_flipping = 0;
-               radeon_mem_release(filp, dev_priv->gart_heap);
-               radeon_mem_release(filp, dev_priv->fb_heap);
-               radeon_surfaces_release(filp, dev_priv);
+               radeon_mem_release(file_priv, dev_priv->gart_heap);
+               radeon_mem_release(file_priv, dev_priv->fb_heap);
+               radeon_surfaces_release(file_priv, dev_priv);
        }
 }
 
@@ -3186,7 +3127,7 @@ void radeon_driver_lastclose(struct drm_device *dev)
        radeon_do_release(dev);
 }
 
-int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
+int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
        struct drm_radeon_driver_file_fields *radeon_priv;
@@ -3199,7 +3140,7 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
        if (!radeon_priv)
                return -ENOMEM;
 
-       filp_priv->driver_priv = radeon_priv;
+       file_priv->driver_priv = radeon_priv;
 
        if (dev_priv)
                radeon_priv->radeon_fb_delta = dev_priv->fb_location;
@@ -3208,42 +3149,42 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
        return 0;
 }
 
-void radeon_driver_postclose(struct drm_device *dev, struct drm_file *filp_priv)
+void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
 {
        struct drm_radeon_driver_file_fields *radeon_priv =
-           filp_priv->driver_priv;
+           file_priv->driver_priv;
 
        drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
 }
 
-drm_ioctl_desc_t radeon_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH}
+struct drm_ioctl_desc radeon_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH)
 };
 
 int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
index 18c7235f6b73a4661ef4ab9eff27b766e0062e37..59484d56b3338e1e8533cf4c5c04f013785ddccd 100644 (file)
@@ -60,7 +60,7 @@ savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
        DRM_ERROR("failed!\n");
        DRM_INFO("   status=0x%08x, threshold=0x%08x\n", status, threshold);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int
@@ -81,7 +81,7 @@ savage_bci_wait_fifo_s3d(drm_savage_private_t * dev_priv, unsigned int n)
        DRM_ERROR("failed!\n");
        DRM_INFO("   status=0x%08x\n", status);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int
@@ -102,7 +102,7 @@ savage_bci_wait_fifo_s4(drm_savage_private_t * dev_priv, unsigned int n)
        DRM_ERROR("failed!\n");
        DRM_INFO("   status=0x%08x\n", status);
 #endif
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 /*
@@ -136,7 +136,7 @@ savage_bci_wait_event_shadow(drm_savage_private_t * dev_priv, uint16_t e)
        DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);
 #endif
 
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 static int
@@ -158,7 +158,7 @@ savage_bci_wait_event_reg(drm_savage_private_t * dev_priv, uint16_t e)
        DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);
 #endif
 
-       return DRM_ERR(EBUSY);
+       return -EBUSY;
 }
 
 uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
@@ -301,7 +301,7 @@ static int savage_dma_init(drm_savage_private_t * dev_priv)
        dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) *
                                        dev_priv->nr_dma_pages, DRM_MEM_DRIVER);
        if (dev_priv->dma_pages == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
                SET_AGE(&dev_priv->dma_pages[i].age, 0, 0);
@@ -541,7 +541,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset)
 
        dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER);
        if (dev_priv == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        memset(dev_priv, 0, sizeof(drm_savage_private_t));
        dev->dev_private = (void *)dev_priv;
@@ -682,16 +682,16 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
 
        if (init->fb_bpp != 16 && init->fb_bpp != 32) {
                DRM_ERROR("invalid frame buffer bpp %d!\n", init->fb_bpp);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        if (init->depth_bpp != 16 && init->depth_bpp != 32) {
                DRM_ERROR("invalid depth buffer bpp %d!\n", init->fb_bpp);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        if (init->dma_type != SAVAGE_DMA_AGP &&
            init->dma_type != SAVAGE_DMA_PCI) {
                DRM_ERROR("invalid dma memory type %d!\n", init->dma_type);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->cob_size = init->cob_size;
@@ -715,14 +715,14 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
        if (!dev_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                savage_do_cleanup_bci(dev);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        if (init->status_offset != 0) {
                dev_priv->status = drm_core_findmap(dev, init->status_offset);
                if (!dev_priv->status) {
                        DRM_ERROR("could not find shadow status region!\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        } else {
                dev_priv->status = NULL;
@@ -734,13 +734,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
                if (!dev->agp_buffer_map) {
                        DRM_ERROR("could not find DMA buffer region!\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                drm_core_ioremap(dev->agp_buffer_map, dev);
                if (!dev->agp_buffer_map) {
                        DRM_ERROR("failed to ioremap DMA buffer region!\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
        }
        if (init->agp_textures_offset) {
@@ -749,7 +749,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
                if (!dev_priv->agp_textures) {
                        DRM_ERROR("could not find agp texture region!\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        } else {
                dev_priv->agp_textures = NULL;
@@ -760,39 +760,39 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
                        DRM_ERROR("command DMA not supported on "
                                  "Savage3D/MX/IX.\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                if (dev->dma && dev->dma->buflist) {
                        DRM_ERROR("command and vertex DMA not supported "
                                  "at the same time.\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                dev_priv->cmd_dma = drm_core_findmap(dev, init->cmd_dma_offset);
                if (!dev_priv->cmd_dma) {
                        DRM_ERROR("could not find command DMA region!\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                if (dev_priv->dma_type == SAVAGE_DMA_AGP) {
                        if (dev_priv->cmd_dma->type != _DRM_AGP) {
                                DRM_ERROR("AGP command DMA region is not a "
                                          "_DRM_AGP map!\n");
                                savage_do_cleanup_bci(dev);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        drm_core_ioremap(dev_priv->cmd_dma, dev);
                        if (!dev_priv->cmd_dma->handle) {
                                DRM_ERROR("failed to ioremap command "
                                          "DMA region!\n");
                                savage_do_cleanup_bci(dev);
-                               return DRM_ERR(ENOMEM);
+                               return -ENOMEM;
                        }
                } else if (dev_priv->cmd_dma->type != _DRM_CONSISTENT) {
                        DRM_ERROR("PCI command DMA region is not a "
                                  "_DRM_CONSISTENT map!\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        } else {
                dev_priv->cmd_dma = NULL;
@@ -809,7 +809,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
                if (!dev_priv->fake_dma.handle) {
                        DRM_ERROR("could not allocate faked DMA buffer!\n");
                        savage_do_cleanup_bci(dev);
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
                }
                dev_priv->cmd_dma = &dev_priv->fake_dma;
                dev_priv->dma_flush = savage_fake_dma_flush;
@@ -886,13 +886,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
        if (savage_freelist_init(dev) < 0) {
                DRM_ERROR("could not initialize freelist\n");
                savage_do_cleanup_bci(dev);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        if (savage_dma_init(dev_priv) < 0) {
                DRM_ERROR("could not initialize command DMA\n");
                savage_do_cleanup_bci(dev);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        return 0;
@@ -928,51 +928,41 @@ static int savage_do_cleanup_bci(struct drm_device * dev)
        return 0;
 }
 
-static int savage_bci_init(DRM_IOCTL_ARGS)
+static int savage_bci_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_savage_init_t init;
+       drm_savage_init_t *init = data;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_COPY_FROM_USER_IOCTL(init, (drm_savage_init_t __user *) data,
-                                sizeof(init));
-
-       switch (init.func) {
+       switch (init->func) {
        case SAVAGE_INIT_BCI:
-               return savage_do_init_bci(dev, &init);
+               return savage_do_init_bci(dev, init);
        case SAVAGE_CLEANUP_BCI:
                return savage_do_cleanup_bci(dev);
        }
 
-       return DRM_ERR(EINVAL);
+       return -EINVAL;
 }
 
-static int savage_bci_event_emit(DRM_IOCTL_ARGS)
+static int savage_bci_event_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_savage_private_t *dev_priv = dev->dev_private;
-       drm_savage_event_emit_t event;
+       drm_savage_event_emit_t *event = data;
 
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_emit_t __user *) data,
-                                sizeof(event));
+       event->count = savage_bci_emit_event(dev_priv, event->flags);
+       event->count |= dev_priv->event_wrap << 16;
 
-       event.count = savage_bci_emit_event(dev_priv, event.flags);
-       event.count |= dev_priv->event_wrap << 16;
-       DRM_COPY_TO_USER_IOCTL((drm_savage_event_emit_t __user *) data,
-                              event, sizeof(event));
        return 0;
 }
 
-static int savage_bci_event_wait(DRM_IOCTL_ARGS)
+static int savage_bci_event_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_savage_private_t *dev_priv = dev->dev_private;
-       drm_savage_event_wait_t event;
+       drm_savage_event_wait_t *event = data;
        unsigned int event_e, hw_e;
        unsigned int event_w, hw_w;
 
@@ -990,8 +980,8 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS)
        if (hw_e > dev_priv->event_counter)
                hw_w--;         /* hardware hasn't passed the last wrap yet */
 
-       event_e = event.count & 0xffff;
-       event_w = event.count >> 16;
+       event_e = event->count & 0xffff;
+       event_w = event->count >> 16;
 
        /* Don't need to wait if
         * - event counter wrapped since the event was emitted or
@@ -1007,7 +997,9 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS)
  * DMA buffer management
  */
 
-static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct drm_dma *d)
+static int savage_bci_get_buffers(struct drm_device *dev,
+                                 struct drm_file *file_priv,
+                                 struct drm_dma *d)
 {
        struct drm_buf *buf;
        int i;
@@ -1015,61 +1007,56 @@ static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct d
        for (i = d->granted_count; i < d->request_count; i++) {
                buf = savage_freelist_get(dev);
                if (!buf)
-                       return DRM_ERR(EAGAIN);
+                       return -EAGAIN;
 
-               buf->filp = filp;
+               buf->file_priv = file_priv;
 
                if (DRM_COPY_TO_USER(&d->request_indices[i],
                                     &buf->idx, sizeof(buf->idx)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
                if (DRM_COPY_TO_USER(&d->request_sizes[i],
                                     &buf->total, sizeof(buf->total)))
-                       return DRM_ERR(EFAULT);
+                       return -EFAULT;
 
                d->granted_count++;
        }
        return 0;
 }
 
-int savage_bci_buffers(DRM_IOCTL_ARGS)
+int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        struct drm_device_dma *dma = dev->dma;
-       struct drm_dma d;
+       struct drm_dma *d = data;
        int ret = 0;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(d, (struct drm_dma __user *) data, sizeof(d));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        /* Please don't send us buffers.
         */
-       if (d.send_count != 0) {
+       if (d->send_count != 0) {
                DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
-                         DRM_CURRENTPID, d.send_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->send_count);
+               return -EINVAL;
        }
 
        /* We'll send you buffers.
         */
-       if (d.request_count < 0 || d.request_count > dma->buf_count) {
+       if (d->request_count < 0 || d->request_count > dma->buf_count) {
                DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
-                         DRM_CURRENTPID, d.request_count, dma->buf_count);
-               return DRM_ERR(EINVAL);
+                         DRM_CURRENTPID, d->request_count, dma->buf_count);
+               return -EINVAL;
        }
 
-       d.granted_count = 0;
+       d->granted_count = 0;
 
-       if (d.request_count) {
-               ret = savage_bci_get_buffers(filp, dev, &d);
+       if (d->request_count) {
+               ret = savage_bci_get_buffers(dev, file_priv, d);
        }
 
-       DRM_COPY_TO_USER_IOCTL((struct drm_dma __user *) data, d, sizeof(d));
-
        return ret;
 }
 
-void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
+void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        drm_savage_private_t *dev_priv = dev->dev_private;
@@ -1088,7 +1075,7 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
                struct drm_buf *buf = dma->buflist[i];
                drm_savage_buf_priv_t *buf_priv = buf->dev_private;
 
-               if (buf->filp == filp && buf_priv &&
+               if (buf->file_priv == file_priv && buf_priv &&
                    buf_priv->next == NULL && buf_priv->prev == NULL) {
                        uint16_t event;
                        DRM_DEBUG("reclaimed from client\n");
@@ -1098,14 +1085,14 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
                }
        }
 
-       drm_core_reclaim_buffers(dev, filp);
+       drm_core_reclaim_buffers(dev, file_priv);
 }
 
-drm_ioctl_desc_t savage_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, DRM_AUTH},
+struct drm_ioctl_desc savage_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH),
 };
 
 int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls);
index 5fd54de4280e3f9fe249e5ae5098886839b5320e..df2aac6636f72fe956b77b14e14c2d9f91746754 100644 (file)
@@ -104,7 +104,7 @@ enum savage_family {
        S3_LAST
 };
 
-extern drm_ioctl_desc_t savage_ioctls[];
+extern struct drm_ioctl_desc savage_ioctls[];
 extern int savage_max_ioctl;
 
 #define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
@@ -197,8 +197,8 @@ typedef struct drm_savage_private {
 } drm_savage_private_t;
 
 /* ioctls */
-extern int savage_bci_cmdbuf(DRM_IOCTL_ARGS);
-extern int savage_bci_buffers(DRM_IOCTL_ARGS);
+extern int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
 
 /* BCI functions */
 extern uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
@@ -212,7 +212,8 @@ extern int savage_driver_load(struct drm_device *dev, unsigned long chipset);
 extern int savage_driver_firstopen(struct drm_device *dev);
 extern void savage_driver_lastclose(struct drm_device *dev);
 extern int savage_driver_unload(struct drm_device *dev);
-extern void savage_reclaim_buffers(struct drm_device * dev, DRMFILE filp);
+extern void savage_reclaim_buffers(struct drm_device *dev,
+                                  struct drm_file *file_priv);
 
 /* state functions */
 extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
index 77497841478a65fcccb38d9edd2bc1b9ef46daf1..bf8e0e10fe21140daf89b42232846c71df4b8405 100644 (file)
@@ -83,7 +83,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
 {
        if ((addr & 6) != 2) {  /* reserved bits */
                DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        if (!(addr & 1)) {      /* local */
                addr &= ~7;
@@ -92,13 +92,13 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
                        DRM_ERROR
                            ("bad texAddr%d %08x (local addr out of range)\n",
                             unit, addr);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        } else {                /* AGP */
                if (!dev_priv->agp_textures) {
                        DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
                                  unit, addr);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                addr &= ~7;
                if (addr < dev_priv->agp_textures->offset ||
@@ -107,7 +107,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
                        DRM_ERROR
                            ("bad texAddr%d %08x (AGP addr out of range)\n",
                             unit, addr);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
        return 0;
@@ -133,7 +133,7 @@ static int savage_verify_state_s3d(drm_savage_private_t * dev_priv,
            start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
                DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
                          start, start + count - 1);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
@@ -165,7 +165,7 @@ static int savage_verify_state_s4(drm_savage_private_t * dev_priv,
            start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) {
                DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
                          start, start + count - 1);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
@@ -289,7 +289,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
 
        if (!dmabuf) {
                DRM_ERROR("called without dma buffers!\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (!n)
@@ -303,7 +303,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of vertices %u in TRILIST\n",
                                  n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        case SAVAGE_PRIM_TRISTRIP:
@@ -312,18 +312,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
                        DRM_ERROR
                            ("wrong number of vertices %u in TRIFAN/STRIP\n",
                             n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        default:
                DRM_ERROR("invalid primitive type %u\n", prim);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
                if (skip != 0) {
                        DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        } else {
                unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
@@ -331,18 +331,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
                    (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
                if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
                        DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                if (reorder) {
                        DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
 
        if (start + n > dmabuf->total / 32) {
                DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
                          start, start + n - 1, dmabuf->total / 32);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        /* Vertex DMA doesn't work with command DMA at the same time,
@@ -440,7 +440,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of vertices %u in TRILIST\n",
                                  n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        case SAVAGE_PRIM_TRISTRIP:
@@ -449,24 +449,24 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
                        DRM_ERROR
                            ("wrong number of vertices %u in TRIFAN/STRIP\n",
                             n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        default:
                DRM_ERROR("invalid primitive type %u\n", prim);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
                if (skip > SAVAGE_SKIP_ALL_S3D) {
                        DRM_ERROR("invalid skip flags 0x%04x\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                vtx_size = 8;   /* full vertex */
        } else {
                if (skip > SAVAGE_SKIP_ALL_S4) {
                        DRM_ERROR("invalid skip flags 0x%04x\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                vtx_size = 10;  /* full vertex */
        }
@@ -478,13 +478,13 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
        if (vtx_size > vb_stride) {
                DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
                          vtx_size, vb_stride);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (start + n > vb_size / (vb_stride * 4)) {
                DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
                          start, start + n - 1, vb_size / (vb_stride * 4));
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        prim <<= 25;
@@ -547,7 +547,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
 
        if (!dmabuf) {
                DRM_ERROR("called without dma buffers!\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (!n)
@@ -560,7 +560,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
        case SAVAGE_PRIM_TRILIST:
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        case SAVAGE_PRIM_TRISTRIP:
@@ -568,18 +568,18 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
                if (n < 3) {
                        DRM_ERROR
                            ("wrong number of indices %u in TRIFAN/STRIP\n", n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        default:
                DRM_ERROR("invalid primitive type %u\n", prim);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
                if (skip != 0) {
                        DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        } else {
                unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
@@ -587,11 +587,11 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
                    (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
                if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
                        DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                if (reorder) {
                        DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
 
@@ -628,7 +628,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
                        if (idx[i] > dmabuf->total / 32) {
                                DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
                                          i, idx[i], dmabuf->total / 32);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                }
 
@@ -698,7 +698,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
        case SAVAGE_PRIM_TRILIST:
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        case SAVAGE_PRIM_TRISTRIP:
@@ -706,24 +706,24 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
                if (n < 3) {
                        DRM_ERROR
                            ("wrong number of indices %u in TRIFAN/STRIP\n", n);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                break;
        default:
                DRM_ERROR("invalid primitive type %u\n", prim);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
                if (skip > SAVAGE_SKIP_ALL_S3D) {
                        DRM_ERROR("invalid skip flags 0x%04x\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                vtx_size = 8;   /* full vertex */
        } else {
                if (skip > SAVAGE_SKIP_ALL_S4) {
                        DRM_ERROR("invalid skip flags 0x%04x\n", skip);
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
                vtx_size = 10;  /* full vertex */
        }
@@ -735,7 +735,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
        if (vtx_size > vb_stride) {
                DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
                          vtx_size, vb_stride);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        prim <<= 25;
@@ -748,7 +748,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
                        if (idx[i] > vb_size / (vb_stride * 4)) {
                                DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
                                          i, idx[i], vb_size / (vb_stride * 4));
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                }
 
@@ -942,7 +942,7 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
                                DRM_ERROR("IMPLEMENTATION ERROR: "
                                          "non-drawing-command %d\n",
                                          cmd_header.cmd.cmd);
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
 
                        if (ret != 0)
@@ -953,13 +953,12 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
        return 0;
 }
 
-int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
+int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_savage_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *dmabuf;
-       drm_savage_cmdbuf_t cmdbuf;
+       drm_savage_cmdbuf_t *cmdbuf = data;
        drm_savage_cmd_header_t *kcmd_addr = NULL;
        drm_savage_cmd_header_t *first_draw_cmd;
        unsigned int *kvb_addr = NULL;
@@ -969,19 +968,16 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
 
        DRM_DEBUG("\n");
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *) data,
-                                sizeof(cmdbuf));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (dma && dma->buflist) {
-               if (cmdbuf.dma_idx > dma->buf_count) {
+               if (cmdbuf->dma_idx > dma->buf_count) {
                        DRM_ERROR
                            ("vertex buffer index %u out of range (0-%u)\n",
-                            cmdbuf.dma_idx, dma->buf_count - 1);
-                       return DRM_ERR(EINVAL);
+                            cmdbuf->dma_idx, dma->buf_count - 1);
+                       return -EINVAL;
                }
-               dmabuf = dma->buflist[cmdbuf.dma_idx];
+               dmabuf = dma->buflist[cmdbuf->dma_idx];
        } else {
                dmabuf = NULL;
        }
@@ -991,47 +987,47 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
         * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct
         * for locking on FreeBSD.
         */
-       if (cmdbuf.size) {
-               kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER);
+       if (cmdbuf->size) {
+               kcmd_addr = drm_alloc(cmdbuf->size * 8, DRM_MEM_DRIVER);
                if (kcmd_addr == NULL)
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
 
-               if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr,
-                                      cmdbuf.size * 8))
+               if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr,
+                                      cmdbuf->size * 8))
                {
-                       drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
-                       return DRM_ERR(EFAULT);
+                       drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER);
+                       return -EFAULT;
                }
-               cmdbuf.cmd_addr = kcmd_addr;
+               cmdbuf->cmd_addr = kcmd_addr;
        }
-       if (cmdbuf.vb_size) {
-               kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER);
+       if (cmdbuf->vb_size) {
+               kvb_addr = drm_alloc(cmdbuf->vb_size, DRM_MEM_DRIVER);
                if (kvb_addr == NULL) {
-                       ret = DRM_ERR(ENOMEM);
+                       ret = -ENOMEM;
                        goto done;
                }
 
-               if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr,
-                                      cmdbuf.vb_size)) {
-                       ret = DRM_ERR(EFAULT);
+               if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf->vb_addr,
+                                      cmdbuf->vb_size)) {
+                       ret = -EFAULT;
                        goto done;
                }
-               cmdbuf.vb_addr = kvb_addr;
+               cmdbuf->vb_addr = kvb_addr;
        }
-       if (cmdbuf.nbox) {
-               kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(struct drm_clip_rect),
+       if (cmdbuf->nbox) {
+               kbox_addr = drm_alloc(cmdbuf->nbox * sizeof(struct drm_clip_rect),
                                       DRM_MEM_DRIVER);
                if (kbox_addr == NULL) {
-                       ret = DRM_ERR(ENOMEM);
+                       ret = -ENOMEM;
                        goto done;
                }
 
-               if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr,
-                                      cmdbuf.nbox * sizeof(struct drm_clip_rect))) {
-                       ret = DRM_ERR(EFAULT);
+               if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf->box_addr,
+                                      cmdbuf->nbox * sizeof(struct drm_clip_rect))) {
+                       ret = -EFAULT;
                        goto done;
                }
-       cmdbuf.box_addr = kbox_addr;
+       cmdbuf->box_addr = kbox_addr;
        }
 
        /* Make sure writes to DMA buffers are finished before sending
@@ -1044,10 +1040,10 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
 
        i = 0;
        first_draw_cmd = NULL;
-       while (i < cmdbuf.size) {
+       while (i < cmdbuf->size) {
                drm_savage_cmd_header_t cmd_header;
-               cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr;
-               cmdbuf.cmd_addr++;
+               cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr;
+               cmdbuf->cmd_addr++;
                i++;
 
                /* Group drawing commands with same state to minimize
@@ -1057,28 +1053,28 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
                case SAVAGE_CMD_DMA_IDX:
                case SAVAGE_CMD_VB_IDX:
                        j = (cmd_header.idx.count + 3) / 4;
-                       if (i + j > cmdbuf.size) {
+                       if (i + j > cmdbuf->size) {
                                DRM_ERROR("indexed drawing command extends "
                                          "beyond end of command buffer\n");
                                DMA_FLUSH();
-                               return DRM_ERR(EINVAL);
+                               return -EINVAL;
                        }
                        /* fall through */
                case SAVAGE_CMD_DMA_PRIM:
                case SAVAGE_CMD_VB_PRIM:
                        if (!first_draw_cmd)
-                               first_draw_cmd = cmdbuf.cmd_addr - 1;
-                       cmdbuf.cmd_addr += j;
+                               first_draw_cmd = cmdbuf->cmd_addr - 1;
+                       cmdbuf->cmd_addr += j;
                        i += j;
                        break;
                default:
                        if (first_draw_cmd) {
                                ret = savage_dispatch_draw(
                                      dev_priv, first_draw_cmd,
-                                     cmdbuf.cmd_addr - 1,
-                                     dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size,
-                                     cmdbuf.vb_stride,
-                                     cmdbuf.nbox, cmdbuf.box_addr);
+                                     cmdbuf->cmd_addr - 1,
+                                     dmabuf, cmdbuf->vb_addr, cmdbuf->vb_size,
+                                     cmdbuf->vb_stride,
+                                     cmdbuf->nbox, cmdbuf->box_addr);
                                if (ret != 0)
                                        return ret;
                                first_draw_cmd = NULL;
@@ -1090,40 +1086,42 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
                switch (cmd_header.cmd.cmd) {
                case SAVAGE_CMD_STATE:
                        j = (cmd_header.state.count + 1) / 2;
-                       if (i + j > cmdbuf.size) {
+                       if (i + j > cmdbuf->size) {
                                DRM_ERROR("command SAVAGE_CMD_STATE extends "
                                          "beyond end of command buffer\n");
                                DMA_FLUSH();
-                               ret = DRM_ERR(EINVAL);
+                               ret = -EINVAL;
                                goto done;
                        }
                        ret = savage_dispatch_state(dev_priv, &cmd_header,
-                               (const uint32_t *)cmdbuf.cmd_addr);
-                       cmdbuf.cmd_addr += j;
+                               (const uint32_t *)cmdbuf->cmd_addr);
+                       cmdbuf->cmd_addr += j;
                        i += j;
                        break;
                case SAVAGE_CMD_CLEAR:
-                       if (i + 1 > cmdbuf.size) {
+                       if (i + 1 > cmdbuf->size) {
                                DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
                                          "beyond end of command buffer\n");
                                DMA_FLUSH();
-                               ret = DRM_ERR(EINVAL);
+                               ret = -EINVAL;
                                goto done;
                        }
                        ret = savage_dispatch_clear(dev_priv, &cmd_header,
-                                                   cmdbuf.cmd_addr,
-                                                   cmdbuf.nbox, cmdbuf.box_addr);
-                       cmdbuf.cmd_addr++;
+                                                   cmdbuf->cmd_addr,
+                                                   cmdbuf->nbox,
+                                                   cmdbuf->box_addr);
+                       cmdbuf->cmd_addr++;
                        i++;
                        break;
                case SAVAGE_CMD_SWAP:
-                       ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox,
-                                                  cmdbuf.box_addr);
+                       ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox,
+                                                  cmdbuf->box_addr);
                        break;
                default:
-                       DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);
+                       DRM_ERROR("invalid command 0x%x\n",
+                                 cmd_header.cmd.cmd);
                        DMA_FLUSH();
-                       ret = DRM_ERR(EINVAL);
+                       ret = -EINVAL;
                        goto done;
                }
 
@@ -1135,9 +1133,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
 
        if (first_draw_cmd) {
                ret = savage_dispatch_draw (
-                       dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf,
-                       cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride,
-                       cmdbuf.nbox, cmdbuf.box_addr);
+                       dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf,
+                       cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride,
+                       cmdbuf->nbox, cmdbuf->box_addr);
                if (ret != 0) {
                        DMA_FLUSH();
                        goto done;
@@ -1146,7 +1144,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
 
        DMA_FLUSH();
 
-       if (dmabuf && cmdbuf.discard) {
+       if (dmabuf && cmdbuf->discard) {
                drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
                uint16_t event;
                event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
@@ -1156,9 +1154,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
 
 done:
        /* If we didn't need to allocate them, these'll be NULL */
-       drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
-       drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER);
-       drm_free(kbox_addr, cmdbuf.nbox * sizeof(struct drm_clip_rect),
+       drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER);
+       drm_free(kvb_addr, cmdbuf->vb_size, DRM_MEM_DRIVER);
+       drm_free(kbox_addr, cmdbuf->nbox * sizeof(struct drm_clip_rect),
                 DRM_MEM_DRIVER);
 
        return ret;
index 1912f585705139bacd4b738e683deea48dcaf23f..7dacc64e9b5685ca242936df97f71b50b287ca4c 100644 (file)
@@ -42,7 +42,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset)
 
        dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
        if (dev_priv == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        dev->dev_private = (void *)dev_priv;
        dev_priv->chipset = chipset;
index 5630df8743539c86377007d588b6932933e5cc4f..ef940bad63f7516703f2402859c973386753754c 100644 (file)
@@ -63,10 +63,11 @@ typedef struct drm_sis_private {
 } drm_sis_private_t;
 
 extern int sis_idle(struct drm_device *dev);
-extern void sis_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void sis_reclaim_buffers_locked(struct drm_device *dev,
+                                      struct drm_file *file_priv);
 extern void sis_lastclose(struct drm_device *dev);
 
-extern drm_ioctl_desc_t sis_ioctls[];
+extern struct drm_ioctl_desc sis_ioctls[];
 extern int sis_max_ioctl;
 
 #endif
index 441bbdbf1510989061149b53c365a26ac7a3b62a..8c66838ff515cf3904832ed070b988312f58fd92 100644 (file)
@@ -82,15 +82,12 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref)
 
 #endif /* CONFIG_FB_SIS */
 
-static int sis_fb_init(DRM_IOCTL_ARGS)
+static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_sis_private_t *dev_priv = dev->dev_private;
-       drm_sis_fb_t fb;
+       drm_sis_fb_t *fb = data;
        int ret;
 
-       DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
-
        mutex_lock(&dev->struct_mutex);
 #if defined(CONFIG_FB_SIS)
        {
@@ -105,7 +102,7 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
        }
 #else
        ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
-                                fb.size >> SIS_MM_ALIGN_SHIFT);
+                                fb->size >> SIS_MM_ALIGN_SHIFT);
 #endif
 
        if (ret) {
@@ -115,98 +112,87 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
        }
 
        dev_priv->vram_initialized = 1;
-       dev_priv->vram_offset = fb.offset;
+       dev_priv->vram_offset = fb->offset;
 
        mutex_unlock(&dev->struct_mutex);
-       DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+       DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
 
        return 0;
 }
 
-static int sis_drm_alloc(struct drm_device *dev, struct drm_file * priv,
-                        unsigned long data, int pool)
+static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file_priv,
+                        void *data, int pool)
 {
        drm_sis_private_t *dev_priv = dev->dev_private;
-       drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
-       drm_sis_mem_t mem;
+       drm_sis_mem_t *mem = data;
        int retval = 0;
        struct drm_memblock_item *item;
 
-       DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
-
        mutex_lock(&dev->struct_mutex);
 
        if (0 == ((pool == 0) ? dev_priv->vram_initialized :
                      dev_priv->agp_initialized)) {
                DRM_ERROR
                    ("Attempt to allocate from uninitialized memory manager.\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
-       item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
-                             (unsigned long)priv);
+       mem->size = (mem->size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
+       item = drm_sman_alloc(&dev_priv->sman, pool, mem->size, 0,
+                             (unsigned long)file_priv);
 
        mutex_unlock(&dev->struct_mutex);
        if (item) {
-               mem.offset = ((pool == 0) ?
+               mem->offset = ((pool == 0) ?
                              dev_priv->vram_offset : dev_priv->agp_offset) +
                    (item->mm->
                     offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
-               mem.free = item->user_hash.key;
-               mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
+               mem->free = item->user_hash.key;
+               mem->size = mem->size << SIS_MM_ALIGN_SHIFT;
        } else {
-               mem.offset = 0;
-               mem.size = 0;
-               mem.free = 0;
-               retval = DRM_ERR(ENOMEM);
+               mem->offset = 0;
+               mem->size = 0;
+               mem->free = 0;
+               retval = -ENOMEM;
        }
 
-       DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
-
-       DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
-                 mem.offset);
+       DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem->size,
+                 mem->offset);
 
        return retval;
 }
 
-static int sis_drm_free(DRM_IOCTL_ARGS)
+static int sis_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_sis_private_t *dev_priv = dev->dev_private;
-       drm_sis_mem_t mem;
+       drm_sis_mem_t *mem = data;
        int ret;
 
-       DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
-                                sizeof(mem));
-
        mutex_lock(&dev->struct_mutex);
-       ret = drm_sman_free_key(&dev_priv->sman, mem.free);
+       ret = drm_sman_free_key(&dev_priv->sman, mem->free);
        mutex_unlock(&dev->struct_mutex);
-       DRM_DEBUG("free = 0x%lx\n", mem.free);
+       DRM_DEBUG("free = 0x%lx\n", mem->free);
 
        return ret;
 }
 
-static int sis_fb_alloc(DRM_IOCTL_ARGS)
+static int sis_fb_alloc(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
+       return sis_drm_alloc(dev, file_priv, data, VIDEO_TYPE);
 }
 
-static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
+static int sis_ioctl_agp_init(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_sis_private_t *dev_priv = dev->dev_private;
-       drm_sis_agp_t agp;
+       drm_sis_agp_t *agp = data;
        int ret;
        dev_priv = dev->dev_private;
 
-       DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
-                                sizeof(agp));
        mutex_lock(&dev->struct_mutex);
        ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
-                                agp.size >> SIS_MM_ALIGN_SHIFT);
+                                agp->size >> SIS_MM_ALIGN_SHIFT);
 
        if (ret) {
                DRM_ERROR("AGP memory manager initialisation error\n");
@@ -215,18 +201,18 @@ static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
        }
 
        dev_priv->agp_initialized = 1;
-       dev_priv->agp_offset = agp.offset;
+       dev_priv->agp_offset = agp->offset;
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+       DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
        return 0;
 }
 
-static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
+static int sis_ioctl_agp_alloc(struct drm_device *dev, void *data,
+                              struct drm_file *file_priv)
 {
-       DRM_DEVICE;
 
-       return sis_drm_alloc(dev, priv, data, AGP_TYPE);
+       return sis_drm_alloc(dev, file_priv, data, AGP_TYPE);
 }
 
 static drm_local_map_t *sis_reg_init(struct drm_device *dev)
@@ -314,13 +300,13 @@ void sis_lastclose(struct drm_device *dev)
        mutex_unlock(&dev->struct_mutex);
 }
 
-void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void sis_reclaim_buffers_locked(struct drm_device * dev,
+                               struct drm_file *file_priv)
 {
        drm_sis_private_t *dev_priv = dev->dev_private;
-       struct drm_file *priv = filp->private_data;
 
        mutex_lock(&dev->struct_mutex);
-       if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+       if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
                mutex_unlock(&dev->struct_mutex);
                return;
        }
@@ -329,20 +315,18 @@ void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
                dev->driver->dma_quiescent(dev);
        }
 
-       drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+       drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
        mutex_unlock(&dev->struct_mutex);
        return;
 }
 
-drm_ioctl_desc_t sis_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
-           {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
-       [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
-           {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
+struct drm_ioctl_desc sis_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_drm_free, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_drm_free, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
 };
 
 int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
index 7ff2b623c2d4d30a0fbf062f01c14add74dbf20e..75d6b748c2c0dec1e2634082820681e5f5b3e288 100644 (file)
@@ -175,24 +175,24 @@ static int via_initialize(struct drm_device * dev,
 {
        if (!dev_priv || !dev_priv->mmio) {
                DRM_ERROR("via_dma_init called before via_map_init\n");
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        if (dev_priv->ring.virtual_start != NULL) {
                DRM_ERROR("%s called again without calling cleanup\n",
                          __FUNCTION__);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        if (!dev->agp || !dev->agp->base) {
                DRM_ERROR("%s called with no agp memory available\n",
                          __FUNCTION__);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        if (dev_priv->chipset == VIA_DX9_0) {
                DRM_ERROR("AGP DMA is not supported on this chip\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        dev_priv->ring.map.offset = dev->agp->base + init->offset;
@@ -207,7 +207,7 @@ static int via_initialize(struct drm_device * dev,
                via_dma_cleanup(dev);
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -227,35 +227,31 @@ static int via_initialize(struct drm_device * dev,
        return 0;
 }
 
-static int via_dma_init(DRM_IOCTL_ARGS)
+static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
-       drm_via_dma_init_t init;
+       drm_via_dma_init_t *init = data;
        int retcode = 0;
 
-       DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t __user *) data,
-                                sizeof(init));
-
-       switch (init.func) {
+       switch (init->func) {
        case VIA_INIT_DMA:
                if (!DRM_SUSER(DRM_CURPROC))
-                       retcode = DRM_ERR(EPERM);
+                       retcode = -EPERM;
                else
-                       retcode = via_initialize(dev, dev_priv, &init);
+                       retcode = via_initialize(dev, dev_priv, init);
                break;
        case VIA_CLEANUP_DMA:
                if (!DRM_SUSER(DRM_CURPROC))
-                       retcode = DRM_ERR(EPERM);
+                       retcode = -EPERM;
                else
                        retcode = via_dma_cleanup(dev);
                break;
        case VIA_DMA_INITIALIZED:
                retcode = (dev_priv->ring.virtual_start != NULL) ?
-                       0 : DRM_ERR(EFAULT);
+                       0 : -EFAULT;
                break;
        default:
-               retcode = DRM_ERR(EINVAL);
+               retcode = -EINVAL;
                break;
        }
 
@@ -273,15 +269,15 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
        if (dev_priv->ring.virtual_start == NULL) {
                DRM_ERROR("%s called without initializing AGP ring buffer.\n",
                          __FUNCTION__);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
        if (cmd->size > VIA_PCI_BUF_SIZE) {
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
 
        if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
        /*
         * Running this function on AGP memory is dead slow. Therefore
@@ -297,7 +293,7 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
 
        vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
        if (vb == NULL) {
-               return DRM_ERR(EAGAIN);
+               return -EAGAIN;
        }
 
        memcpy(vb, dev_priv->pci_buf, cmd->size);
@@ -321,34 +317,30 @@ int via_driver_dma_quiescent(struct drm_device * dev)
        drm_via_private_t *dev_priv = dev->dev_private;
 
        if (!via_wait_idle(dev_priv)) {
-               return DRM_ERR(EBUSY);
+               return -EBUSY;
        }
        return 0;
 }
 
-static int via_flush_ioctl(DRM_IOCTL_ARGS)
+static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        return via_driver_dma_quiescent(dev);
 }
 
-static int via_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_cmdbuffer_t cmdbuf;
+       drm_via_cmdbuffer_t *cmdbuf = data;
        int ret;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
-
-       DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
-                                sizeof(cmdbuf));
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
+       DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
+                 cmdbuf->size);
 
-       ret = via_dispatch_cmdbuffer(dev, &cmdbuf);
+       ret = via_dispatch_cmdbuffer(dev, cmdbuf);
        if (ret) {
                return ret;
        }
@@ -363,10 +355,10 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
        int ret;
 
        if (cmd->size > VIA_PCI_BUF_SIZE) {
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
 
        if ((ret =
             via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
@@ -380,21 +372,17 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
        return ret;
 }
 
-static int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_cmdbuffer_t cmdbuf;
+       drm_via_cmdbuffer_t *cmdbuf = data;
        int ret;
 
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
-                                sizeof(cmdbuf));
+       DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
+                 cmdbuf->size);
 
-       DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,
-                 cmdbuf.size);
-
-       ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);
+       ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
        if (ret) {
                return ret;
        }
@@ -653,80 +641,74 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
  * User interface to the space and lag functions.
  */
 
-static int via_cmdbuf_size(DRM_IOCTL_ARGS)
+static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_cmdbuf_size_t d_siz;
+       drm_via_cmdbuf_size_t *d_siz = data;
        int ret = 0;
        uint32_t tmp_size, count;
        drm_via_private_t *dev_priv;
 
        DRM_DEBUG("via cmdbuf_size\n");
-       LOCK_TEST_WITH_RETURN(dev, filp);
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        dev_priv = (drm_via_private_t *) dev->dev_private;
 
        if (dev_priv->ring.virtual_start == NULL) {
                DRM_ERROR("%s called without initializing AGP ring buffer.\n",
                          __FUNCTION__);
-               return DRM_ERR(EFAULT);
+               return -EFAULT;
        }
 
-       DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t __user *) data,
-                                sizeof(d_siz));
-
        count = 1000000;
-       tmp_size = d_siz.size;
-       switch (d_siz.func) {
+       tmp_size = d_siz->size;
+       switch (d_siz->func) {
        case VIA_CMDBUF_SPACE:
-               while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size)
+               while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size)
                       && count--) {
-                       if (!d_siz.wait) {
+                       if (!d_siz->wait) {
                                break;
                        }
                }
                if (!count) {
                        DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
-                       ret = DRM_ERR(EAGAIN);
+                       ret = -EAGAIN;
                }
                break;
        case VIA_CMDBUF_LAG:
-               while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size)
+               while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size)
                       && count--) {
-                       if (!d_siz.wait) {
+                       if (!d_siz->wait) {
                                break;
                        }
                }
                if (!count) {
                        DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
-                       ret = DRM_ERR(EAGAIN);
+                       ret = -EAGAIN;
                }
                break;
        default:
-               ret = DRM_ERR(EFAULT);
+               ret = -EFAULT;
        }
-       d_siz.size = tmp_size;
+       d_siz->size = tmp_size;
 
-       DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t __user *) data, d_siz,
-                              sizeof(d_siz));
        return ret;
 }
 
-drm_ioctl_desc_t via_ioctls[] = {
-       [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, DRM_AUTH|DRM_MASTER},
-       [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, DRM_AUTH|DRM_MASTER},
-       [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, DRM_AUTH|DRM_MASTER},
-       [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_DMA_BLIT)] = {via_dma_blit, DRM_AUTH},
-       [DRM_IOCTL_NR(DRM_VIA_BLIT_SYNC)] = {via_dma_blit_sync, DRM_AUTH}
+struct drm_ioctl_desc via_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER),
+       DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER),
+       DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER),
+       DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH)
 };
 
 int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls);
index 3dd1ed3d1bf5c859c388979a25a6c05f7c17c113..c6fd16f3cb434594fb52fc1f1fc2f28309445132 100644 (file)
@@ -237,7 +237,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
                first_pfn + 1;
        
        if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
        down_read(&current->mm->mmap_sem);
        ret = get_user_pages(current, current->mm,
@@ -251,7 +251,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
                if (ret < 0) 
                        return ret;
                vsg->state = dr_via_pages_locked;
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        vsg->state = dr_via_pages_locked;
        DRM_DEBUG("DMA pages locked\n");
@@ -274,13 +274,13 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
                vsg->descriptors_per_page;
 
        if (NULL ==  (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        
        vsg->state = dr_via_desc_pages_alloc;
        for (i=0; i<vsg->num_desc_pages; ++i) {
                if (NULL == (vsg->desc_pages[i] = 
                             (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL)))
-                       return DRM_ERR(ENOMEM);
+                       return -ENOMEM;
        }
        DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages,
                  vsg->num_desc);
@@ -593,7 +593,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
 
        if (xfer->num_lines <= 0 || xfer->line_length <= 0) {
                DRM_ERROR("Zero size bitblt.\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        /*
@@ -606,7 +606,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
        if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
                DRM_ERROR("Too large system memory stride. Stride: %d, "
                          "Length: %d\n", xfer->mem_stride, xfer->line_length);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if ((xfer->mem_stride == xfer->line_length) &&
@@ -624,7 +624,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
 
        if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
                DRM_ERROR("Too large PCI DMA bitblt.\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }               
 
        /* 
@@ -635,7 +635,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
        if (xfer->mem_stride < xfer->line_length ||
                abs(xfer->fb_stride) < xfer->line_length) {
                DRM_ERROR("Invalid frame-buffer / memory stride.\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        /*
@@ -648,7 +648,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
        if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
            ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
                DRM_ERROR("Invalid DRM bitblt alignment.\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 #else
        if ((((unsigned long)xfer->mem_addr & 15) ||
@@ -656,7 +656,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
           ((xfer->num_lines > 1) && 
           ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
                DRM_ERROR("Invalid DRM bitblt alignment.\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }       
 #endif
 
@@ -696,7 +696,7 @@ via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
 
                DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0);
                if (ret) {
-                       return (DRM_ERR(EINTR) == ret) ? DRM_ERR(EAGAIN) : ret;
+                       return (-EINTR == ret) ? -EAGAIN : ret;
                }
                
                spin_lock_irqsave(&blitq->blit_lock, irqsave);
@@ -740,7 +740,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
 
        if (dev_priv == NULL) {
                DRM_ERROR("Called without initialization.\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        engine = (xfer->to_fb) ? 0 : 1;
@@ -750,7 +750,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
        }
        if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) {
                via_dmablit_release_slot(blitq);
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
        }
        if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) {
                via_dmablit_release_slot(blitq);
@@ -781,21 +781,18 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
  */
 
 int
-via_dma_blit_sync( DRM_IOCTL_ARGS )
+via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv )
 {
-       drm_via_blitsync_t sync;
+       drm_via_blitsync_t *sync = data;
        int err;
-       DRM_DEVICE;
 
-       DRM_COPY_FROM_USER_IOCTL(sync, (drm_via_blitsync_t *)data, sizeof(sync));
-       
-       if (sync.engine >= VIA_NUM_BLIT_ENGINES) 
-               return DRM_ERR(EINVAL);
+       if (sync->engine >= VIA_NUM_BLIT_ENGINES) 
+               return -EINVAL;
 
-       err = via_dmablit_sync(dev, sync.sync_handle, sync.engine);
+       err = via_dmablit_sync(dev, sync->sync_handle, sync->engine);
 
-       if (DRM_ERR(EINTR) == err)
-               err = DRM_ERR(EAGAIN);
+       if (-EINTR == err)
+               err = -EAGAIN;
 
        return err;
 }
@@ -808,17 +805,12 @@ via_dma_blit_sync( DRM_IOCTL_ARGS )
  */
 
 int 
-via_dma_blit( DRM_IOCTL_ARGS )
+via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv )
 {
-       drm_via_dmablit_t xfer;
+       drm_via_dmablit_t *xfer = data;
        int err;
-       DRM_DEVICE;
-
-       DRM_COPY_FROM_USER_IOCTL(xfer, (drm_via_dmablit_t __user *)data, sizeof(xfer));
-
-       err = via_dmablit(dev, &xfer);
 
-       DRM_COPY_TO_USER_IOCTL((void __user *)data, xfer, sizeof(xfer));
+       err = via_dmablit(dev, xfer);
 
        return err;
 }
index 576711564a11d9d6668eb57da75b962e82e41252..2daae81874cdd049fdcd2ff9f0783eb15994fb53 100644 (file)
@@ -110,18 +110,18 @@ enum via_family {
 #define VIA_READ8(reg)         DRM_READ8(VIA_BASE, reg)
 #define VIA_WRITE8(reg,val)    DRM_WRITE8(VIA_BASE, reg, val)
 
-extern drm_ioctl_desc_t via_ioctls[];
+extern struct drm_ioctl_desc via_ioctls[];
 extern int via_max_ioctl;
 
-extern int via_fb_init(DRM_IOCTL_ARGS);
-extern int via_mem_alloc(DRM_IOCTL_ARGS);
-extern int via_mem_free(DRM_IOCTL_ARGS);
-extern int via_agp_init(DRM_IOCTL_ARGS);
-extern int via_map_init(DRM_IOCTL_ARGS);
-extern int via_decoder_futex(DRM_IOCTL_ARGS);
-extern int via_wait_irq(DRM_IOCTL_ARGS);
-extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
-extern int via_dma_blit( DRM_IOCTL_ARGS );
+extern int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv );
+extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv );
 
 extern int via_driver_load(struct drm_device *dev, unsigned long chipset);
 extern int via_driver_unload(struct drm_device *dev);
@@ -144,7 +144,7 @@ extern void via_init_futex(drm_via_private_t * dev_priv);
 extern void via_cleanup_futex(drm_via_private_t * dev_priv);
 extern void via_release_futex(drm_via_private_t * dev_priv, int context);
 
-extern void via_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv);
 extern void via_lastclose(struct drm_device *dev);
 
 extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
index 8dc99b5fbab6f4ba372304a6cc96fd8daf0f560c..9c1d52bc92d764dc3c58169dcc5b391c5bfba290 100644 (file)
@@ -205,13 +205,13 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
 
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        if (irq >= drm_via_irq_num) {
                DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
                          irq);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        real_irq = dev_priv->irq_map[irq];
@@ -219,7 +219,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
        if (real_irq < 0) {
                DRM_ERROR("%s Video IRQ %d not available on this hardware.\n",
                          __FUNCTION__, irq);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
        masks = dev_priv->irq_masks;
@@ -331,11 +331,9 @@ void via_driver_irq_uninstall(struct drm_device * dev)
        }
 }
 
-int via_wait_irq(DRM_IOCTL_ARGS)
+int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_irqwait_t __user *argp = (void __user *)data;
-       drm_via_irqwait_t irqwait;
+       drm_via_irqwait_t *irqwait = data;
        struct timeval now;
        int ret = 0;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -343,42 +341,39 @@ int via_wait_irq(DRM_IOCTL_ARGS)
        int force_sequence;
 
        if (!dev->irq)
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
 
-       DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
-       if (irqwait.request.irq >= dev_priv->num_irqs) {
+       if (irqwait->request.irq >= dev_priv->num_irqs) {
                DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
-                         irqwait.request.irq);
-               return DRM_ERR(EINVAL);
+                         irqwait->request.irq);
+               return -EINVAL;
        }
 
-       cur_irq += irqwait.request.irq;
+       cur_irq += irqwait->request.irq;
 
-       switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
+       switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
        case VIA_IRQ_RELATIVE:
-               irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
-               irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+               irqwait->request.sequence += atomic_read(&cur_irq->irq_received);
+               irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
        case VIA_IRQ_ABSOLUTE:
                break;
        default:
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       if (irqwait.request.type & VIA_IRQ_SIGNAL) {
+       if (irqwait->request.type & VIA_IRQ_SIGNAL) {
                DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
                          __FUNCTION__);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
+       force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE);
 
-       ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
-                                 &irqwait.request.sequence);
+       ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence,
+                                 &irqwait->request.sequence);
        do_gettimeofday(&now);
-       irqwait.reply.tval_sec = now.tv_sec;
-       irqwait.reply.tval_usec = now.tv_usec;
-
-       DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
+       irqwait->reply.tval_sec = now.tv_sec;
+       irqwait->reply.tval_usec = now.tv_usec;
 
        return ret;
 }
index 7fb9d2a2cce2e6f5bb5edb863c89bfd31b07554e..10091507a0dc12c35a289da36750230112d197a8 100644 (file)
@@ -75,19 +75,15 @@ int via_do_cleanup_map(struct drm_device * dev)
        return 0;
 }
 
-int via_map_init(DRM_IOCTL_ARGS)
+int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_init_t init;
+       drm_via_init_t *init = data;
 
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t __user *) data,
-                                sizeof(init));
-
-       switch (init.func) {
+       switch (init->func) {
        case VIA_INIT_MAP:
-               return via_do_init_map(dev, &init);
+               return via_do_init_map(dev, init);
        case VIA_CLEANUP_MAP:
                return via_do_cleanup_map(dev);
        }
@@ -102,7 +98,7 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset)
 
        dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
        if (dev_priv == NULL)
-               return DRM_ERR(ENOMEM);
+               return -ENOMEM;
 
        dev->dev_private = (void *)dev_priv;
 
index 85d56acd9d82e0755a2c837272c62a2931750088..9afc1684348d443d7cba58788484337776be6d93 100644 (file)
 #define VIA_MM_ALIGN_SHIFT 4
 #define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
 
-int via_agp_init(DRM_IOCTL_ARGS)
+int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_agp_t agp;
+       drm_via_agp_t *agp = data;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        int ret;
 
-       DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
-                                sizeof(agp));
        mutex_lock(&dev->struct_mutex);
        ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
-                                agp.size >> VIA_MM_ALIGN_SHIFT);
+                                agp->size >> VIA_MM_ALIGN_SHIFT);
 
        if (ret) {
                DRM_ERROR("AGP memory manager initialisation error\n");
@@ -53,25 +50,22 @@ int via_agp_init(DRM_IOCTL_ARGS)
        }
 
        dev_priv->agp_initialized = 1;
-       dev_priv->agp_offset = agp.offset;
+       dev_priv->agp_offset = agp->offset;
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+       DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
        return 0;
 }
 
-int via_fb_init(DRM_IOCTL_ARGS)
+int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_fb_t fb;
+       drm_via_fb_t *fb = data;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        int ret;
 
-       DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
-
        mutex_lock(&dev->struct_mutex);
        ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
-                                fb.size >> VIA_MM_ALIGN_SHIFT);
+                                fb->size >> VIA_MM_ALIGN_SHIFT);
 
        if (ret) {
                DRM_ERROR("VRAM memory manager initialisation error\n");
@@ -80,10 +74,10 @@ int via_fb_init(DRM_IOCTL_ARGS)
        }
 
        dev_priv->vram_initialized = 1;
-       dev_priv->vram_offset = fb.offset;
+       dev_priv->vram_offset = fb->offset;
 
        mutex_unlock(&dev->struct_mutex);
-       DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+       DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
 
        return 0;
 
@@ -121,80 +115,71 @@ void via_lastclose(struct drm_device *dev)
        mutex_unlock(&dev->struct_mutex);
 }      
 
-int via_mem_alloc(DRM_IOCTL_ARGS)
+int via_mem_alloc(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-
-       drm_via_mem_t mem;
+       drm_via_mem_t *mem = data;
        int retval = 0;
        struct drm_memblock_item *item;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        unsigned long tmpSize;
 
-       DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
-                                sizeof(mem));
-
-       if (mem.type > VIA_MEM_AGP) {
+       if (mem->type > VIA_MEM_AGP) {
                DRM_ERROR("Unknown memory type allocation\n");
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        mutex_lock(&dev->struct_mutex);
-       if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
+       if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
                      dev_priv->agp_initialized)) {
                DRM_ERROR
                    ("Attempt to allocate from uninitialized memory manager.\n");
                mutex_unlock(&dev->struct_mutex);
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
 
-       tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
-       item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
-                             (unsigned long)priv);
+       tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
+       item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, 0,
+                             (unsigned long)file_priv);
        mutex_unlock(&dev->struct_mutex);
        if (item) {
-               mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
+               mem->offset = ((mem->type == VIA_MEM_VIDEO) ?
                              dev_priv->vram_offset : dev_priv->agp_offset) +
                    (item->mm->
                     offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
-               mem.index = item->user_hash.key;
+               mem->index = item->user_hash.key;
        } else {
-               mem.offset = 0;
-               mem.size = 0;
-               mem.index = 0;
+               mem->offset = 0;
+               mem->size = 0;
+               mem->index = 0;
                DRM_DEBUG("Video memory allocation failed\n");
-               retval = DRM_ERR(ENOMEM);
+               retval = -ENOMEM;
        }
-       DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
 
        return retval;
 }
 
-int via_mem_free(DRM_IOCTL_ARGS)
+int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
        drm_via_private_t *dev_priv = dev->dev_private;
-       drm_via_mem_t mem;
+       drm_via_mem_t *mem = data;
        int ret;
 
-       DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
-                                sizeof(mem));
-
        mutex_lock(&dev->struct_mutex);
-       ret = drm_sman_free_key(&dev_priv->sman, mem.index);
+       ret = drm_sman_free_key(&dev_priv->sman, mem->index);
        mutex_unlock(&dev->struct_mutex);
-       DRM_DEBUG("free = 0x%lx\n", mem.index);
+       DRM_DEBUG("free = 0x%lx\n", mem->index);
 
        return ret;
 }
 
 
-void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void via_reclaim_buffers_locked(struct drm_device * dev,
+                               struct drm_file *file_priv)
 {
        drm_via_private_t *dev_priv = dev->dev_private;
-       struct drm_file *priv = filp->private_data;
 
        mutex_lock(&dev->struct_mutex);
-       if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+       if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
                mutex_unlock(&dev->struct_mutex);
                return;
        }
@@ -203,7 +188,7 @@ void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
                dev->driver->dma_quiescent(dev);
        }
 
-       drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+       drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
        mutex_unlock(&dev->struct_mutex);
        return;
 }
index 832d48356e91993a4aeddf98a135890ed7f3583e..46a57919874797b3b41d694b1ab70159a6f3e13e 100644 (file)
@@ -1026,12 +1026,12 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
                case state_error:
                default:
                        *hc_state = saved_state;
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
        if (state == state_error) {
                *hc_state = saved_state;
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        return 0;
 }
@@ -1082,11 +1082,11 @@ via_parse_command_stream(struct drm_device * dev, const uint32_t * buf,
                        break;
                case state_error:
                default:
-                       return DRM_ERR(EINVAL);
+                       return -EINVAL;
                }
        }
        if (state == state_error) {
-               return DRM_ERR(EINVAL);
+               return -EINVAL;
        }
        return 0;
 }
index 300ac61b09edbacd68b92f7446b97a133349d203..c15e75b54cb17783bcf2a627e85e1c82e6c5374b 100644 (file)
@@ -65,10 +65,9 @@ void via_release_futex(drm_via_private_t * dev_priv, int context)
        }
 }
 
-int via_decoder_futex(DRM_IOCTL_ARGS)
+int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       DRM_DEVICE;
-       drm_via_futex_t fx;
+       drm_via_futex_t *fx = data;
        volatile int *lock;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
@@ -76,21 +75,18 @@ int via_decoder_futex(DRM_IOCTL_ARGS)
 
        DRM_DEBUG("%s\n", __FUNCTION__);
 
-       DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t __user *) data,
-                                sizeof(fx));
-
-       if (fx.lock > VIA_NR_XVMC_LOCKS)
+       if (fx->lock > VIA_NR_XVMC_LOCKS)
                return -EFAULT;
 
-       lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx.lock);
+       lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx->lock);
 
-       switch (fx.func) {
+       switch (fx->func) {
        case VIA_FUTEX_WAIT:
-               DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],
-                           (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);
+               DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock],
+                           (fx->ms / 10) * (DRM_HZ / 100), *lock != fx->val);
                return ret;
        case VIA_FUTEX_WAKE:
-               DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));
+               DRM_WAKEUP(&(dev_priv->decoder_queue[fx->lock]));
                return 0;
        }
        return 0;
index acbfe1c49b4dc9148c48d788ccd4f8c2111961c6..a69c6528326005694809005a546436a1af5cd5d1 100644 (file)
@@ -136,7 +136,7 @@ static int sizeof_bootstrap = 375;
 
 
 static struct dsp56k_device {
-       long in_use;
+       unsigned long in_use;
        long maxio, timeout;
        int tx_wsize, rx_wsize;
 } dsp56k;
index a2894d42515344b5e2951d96d8b0a3849a1b8b37..c1222e98525dad9c19b9ac78c02255ea0f0579a3 100644 (file)
@@ -1072,19 +1072,19 @@ static char          *si_type[SI_MAX_PARMS];
 #define MAX_SI_TYPE_STR 30
 static char          si_type_str[MAX_SI_TYPE_STR];
 static unsigned long addrs[SI_MAX_PARMS];
-static int num_addrs;
+static unsigned int num_addrs;
 static unsigned int  ports[SI_MAX_PARMS];
-static int num_ports;
+static unsigned int num_ports;
 static int           irqs[SI_MAX_PARMS];
-static int num_irqs;
+static unsigned int num_irqs;
 static int           regspacings[SI_MAX_PARMS];
-static int num_regspacings;
+static unsigned int num_regspacings;
 static int           regsizes[SI_MAX_PARMS];
-static int num_regsizes;
+static unsigned int num_regsizes;
 static int           regshifts[SI_MAX_PARMS];
-static int num_regshifts;
+static unsigned int num_regshifts;
 static int slave_addrs[SI_MAX_PARMS];
-static int num_slave_addrs;
+static unsigned int num_slave_addrs;
 
 #define IPMI_IO_ADDR_SPACE  0
 #define IPMI_MEM_ADDR_SPACE 1
@@ -1106,12 +1106,12 @@ MODULE_PARM_DESC(type, "Defines the type of each interface, each"
                 " interface separated by commas.  The types are 'kcs',"
                 " 'smic', and 'bt'.  For example si_type=kcs,bt will set"
                 " the first interface to kcs and the second to bt");
-module_param_array(addrs, long, &num_addrs, 0);
+module_param_array(addrs, ulong, &num_addrs, 0);
 MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the"
                 " addresses separated by commas.  Only use if an interface"
                 " is in memory.  Otherwise, set it to zero or leave"
                 " it blank.");
-module_param_array(ports, int, &num_ports, 0);
+module_param_array(ports, uint, &num_ports, 0);
 MODULE_PARM_DESC(ports, "Sets the port address of each interface, the"
                 " addresses separated by commas.  Only use if an interface"
                 " is a port.  Otherwise, set it to zero or leave"
index 23d0681fe491abffeb08795f4028cc017c297b16..78f24540c224583deae9d7ccec68ed49dcdb7025 100644 (file)
@@ -99,7 +99,7 @@ struct Host {
        struct UnixRup UnixRups[MAX_RUP + LINKS_PER_UNIT];
        int timeout_id;                         /* For calling 100 ms delays */
        int timeout_sem;                        /* For calling 100 ms delays */
-       long locks;                             /* long req'd for set_bit --RR */
+       unsigned long locks;                    /* long req'd for set_bit --RR */
        char ____end_marker____;
 };
 #define Control      CardP->DpControl
index 6317aade201a697dd7f484b1c2d49e17f78aa172..9cc1313d5e67934deb7819d31d8a26bf3ff71bdb 100644 (file)
@@ -71,7 +71,7 @@ struct riscom_port {
        struct tty_struct       * tty;
        int                     count;
        int                     blocked_open;
-       long                    event; /* long req'd for set_bit --RR */
+       unsigned long           event; /* long req'd for set_bit --RR */
        int                     timeout;
        int                     close_delay;
        unsigned char           * xmit_buf;
index 432aad0a2dddfd7a2d3d2d6e51c4fb10944c6c8e..70d9783c732391e593eeb8457302aa4fd8016d64 100644 (file)
@@ -27,7 +27,7 @@ struct sx_port {
   int                     c_dcd;
   struct sx_board         *board;
   int                     line;
-  long                    locks;
+  unsigned long           locks;
 };
 
 struct sx_board {
@@ -45,7 +45,7 @@ struct sx_board {
   int poll;
   int ta_type;
   struct timer_list       timer;
-  long                    locks;
+  unsigned long           locks;
 };
 
 struct vpd_prom {
index 2f97d2f8f916fbd3b003e717e16e9d021632a1bc..64e835f62438d3bb6b629224355403c14681927a 100644 (file)
@@ -206,10 +206,10 @@ static void flush_cond_wait(struct cond_wait **head);
  */
 struct slgt_desc
 {
-       unsigned short count;
-       unsigned short status;
-       unsigned int pbuf;  /* physical address of data buffer */
-       unsigned int next;  /* physical address of next descriptor */
+       __le16 count;
+       __le16 status;
+       __le32 pbuf;  /* physical address of data buffer */
+       __le32 next;  /* physical address of next descriptor */
 
        /* driver book keeping */
        char *buf;          /* virtual  address of data buffer */
index 564143d406105dfc5bce3bee89f6cd539ead4b20..9cfb9757662361cb64b770764aa1fa66a4be29f8 100644 (file)
@@ -81,7 +81,7 @@ static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
 
 
 /* file operations */
-static ssize_t mpc5200_wdt_write(struct file *file, const char *data,
+static ssize_t mpc5200_wdt_write(struct file *file, const char __user *data,
                size_t len, loff_t *ppos)
 {
        struct mpc5200_wdt *wdt = file->private_data;
index 4d4a4739390901424df31d7ac19e780d91848144..65dcf0432653b51b1593f94a4ae237584fe3a907 100644 (file)
@@ -35,9 +35,9 @@ static struct eisa_device_info __initdata eisa_table[] = {
 #define EISA_MAX_FORCED_DEV 16
 
 static int enable_dev[EISA_MAX_FORCED_DEV];
-static int enable_dev_count;
+static unsigned int enable_dev_count;
 static int disable_dev[EISA_MAX_FORCED_DEV];
-static int disable_dev_count;
+static unsigned int disable_dev_count;
 
 static int is_forced_dev (int *forced_tab,
                          int forced_count,
index 22b62b3cd14e5538f3b8e273c525c5586154b784..82de9e1adb1eaf80f4ece0410baafc0755dae519 100644 (file)
@@ -427,15 +427,10 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
                        memcpy(SCpnt->sense_buffer, ((char *)(rsp+1)), sense_len);
                }
                
-               if (fcmd->data) {
-                       if (SCpnt->use_sg)
-                               dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->request_buffer,
-                                               SCpnt->use_sg,
-                                               SCpnt->sc_data_direction);
-                       else
-                               dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen,
-                                                SCpnt->sc_data_direction);
-               }
+               if (fcmd->data)
+                       dma_unmap_sg(fc->dev, scsi_sglist(SCpnt),
+                                    scsi_sg_count(SCpnt),
+                                    SCpnt->sc_data_direction);
                break;
        default:
                host_status=DID_ERROR; /* FIXME */
@@ -793,10 +788,14 @@ static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt,
                                fcp_cntl = FCP_CNTL_QTYPE_SIMPLE;
                } else
                        fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED;
-               if (!SCpnt->request_bufflen && !SCpnt->use_sg) {
+
+               if (!scsi_bufflen(SCpnt)) {
                        cmd->fcp_cntl = fcp_cntl;
                        fcmd->data = (dma_addr_t)NULL;
                } else {
+                       struct scatterlist *sg;
+                       int nents;
+
                        switch (SCpnt->cmnd[0]) {
                        case WRITE_6:
                        case WRITE_10:
@@ -805,22 +804,12 @@ static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt,
                        default:
                                cmd->fcp_cntl = (FCP_CNTL_READ | fcp_cntl); break;
                        }
-                       if (!SCpnt->use_sg) {
-                               cmd->fcp_data_len = SCpnt->request_bufflen;
-                               fcmd->data = dma_map_single (fc->dev, (char *)SCpnt->request_buffer,
-                                                            SCpnt->request_bufflen,
-                                                            SCpnt->sc_data_direction);
-                       } else {
-                               struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
-                               int nents;
-
-                               FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length))
-                               nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg,
-                                                   SCpnt->sc_data_direction);
-                               if (nents > 1) printk ("%s: SG for nents %d (use_sg %d) not handled yet\n", fc->name, nents, SCpnt->use_sg);
-                               fcmd->data = sg_dma_address(sg);
-                               cmd->fcp_data_len = sg_dma_len(sg);
-                       }
+
+                       sg = scsi_sglist(SCpnt);
+                       nents = dma_map_sg(fc->dev, sg, scsi_sg_count(SCpnt),
+                                          SCpnt->sc_data_direction);
+                       fcmd->data = sg_dma_address(sg);
+                       cmd->fcp_data_len = sg_dma_len(sg);
                }
                memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len);
                memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len);
index 1ac61330592e7ff162fba2b4f46898659df0b02e..506338a461ba86be0662b1ed6e3776e916ef05c6 100644 (file)
@@ -91,7 +91,7 @@ typedef struct _fc_channel {
        fcp_cmd                 *scsi_cmd_pool;
        char                    *scsi_rsp_pool;
        dma_addr_t              dma_scsi_cmd, dma_scsi_rsp;
-       long                    *scsi_bitmap;
+       unsigned long           *scsi_bitmap;
        long                    scsi_bitmap_end;
        int                     scsi_free;
        int                     (*encode_addr)(struct scsi_cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *);
index 75388641a7d34619f1a1ec1c11aa856e5d13fe6f..06471302200f4dd6459ce33479d4e1ab98bf0dfd 100644 (file)
@@ -722,10 +722,11 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
                buffer_end = 0;
        }
 
-       if (!access_ok(VERIFY_READ, request->packets, request->size))
+       p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
+
+       if (!access_ok(VERIFY_READ, p, request->size))
                return -EFAULT;
 
-       p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
        end = (void __user *)p + request->size;
        count = 0;
        while (p < end) {
index 19667fcc722a774337a3ee29c760c7ad8bec6c33..cacf89e65af4d9f96b1785c873b6f76b384775c3 100644 (file)
@@ -46,6 +46,25 @@ config HID_DEBUG
 
        If unsure, say N
 
+config HIDRAW
+       bool "/dev/hidraw raw HID device support"
+       depends on HID
+       ---help---
+       Say Y here if you want to support HID devices (from the USB
+       specification standpoint) that aren't strictly user interface
+       devices, like monitor controls and Uninterruptable Power Supplies.
+
+       This module supports these devices separately using a separate
+       event interface on /dev/hidraw.
+
+       There is also a /dev/hiddev configuration option in the USB HID
+       configuration menu. In comparison to hiddev, this device does not process
+       the hid events at all (no parsing, no lookups). This lets applications
+       to work on raw hid events when they want to, and avoid using transport-specific
+       userspace libhid/libusb libraries.
+
+       If unsure, say Y.
+
 source "drivers/hid/usbhid/Kconfig"
 
 endif # HID_SUPPORT
index 68d1376a53fbe3b80da6cde1f0089c4e664261db..1ac5103f7c93b151e47aca38a5431ce16234b8dc 100644 (file)
@@ -4,7 +4,9 @@
 hid-objs                       := hid-core.o hid-input.o
 
 obj-$(CONFIG_HID)              += hid.o
+
 hid-$(CONFIG_HID_DEBUG)                += hid-debug.o
+hid-$(CONFIG_HIDRAW)           += hidraw.o
 
 obj-$(CONFIG_USB_HID)          += usbhid/
 obj-$(CONFIG_USB_MOUSE)                += usbhid/
index 317cf8a7b63c11ed03e76772c8c8710a3ec5505c..2884b036495a0713f0389b09ceee5a9c1a4476f0 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/hid.h>
 #include <linux/hiddev.h>
 #include <linux/hid-debug.h>
+#include <linux/hidraw.h>
 
 /*
  * Version Information
@@ -979,6 +980,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
 
        if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
                hid->hiddev_report_event(hid, report);
+       if (hid->claimed & HID_CLAIMED_HIDRAW)
+               hidraw_report_event(hid, data, size);
 
        for (n = 0; n < report->maxfield; n++)
                hid_input_field(hid, report->field[n], data, interrupt);
@@ -990,5 +993,18 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
 }
 EXPORT_SYMBOL_GPL(hid_input_report);
 
+static int __init hid_init(void)
+{
+       return hidraw_init();
+}
+
+static void __exit hid_exit(void)
+{
+       hidraw_exit();
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
 MODULE_LICENSE(DRIVER_LICENSE);
 
index a13757b7898028986f98739eecfb3649be96bdfd..5c24fe46d8eb9c423637888f163e70dedb2281c2 100644 (file)
@@ -34,7 +34,7 @@
 struct hid_usage_entry {
        unsigned  page;
        unsigned  usage;
-       char     *description;
+       const char     *description;
 };
 
 static const struct hid_usage_entry hid_usage_table[] = {
@@ -365,8 +365,8 @@ void hid_resolv_usage(unsigned usage) {
 }
 EXPORT_SYMBOL_GPL(hid_resolv_usage);
 
-__inline__ static void tab(int n) {
-       while (n--) printk(" ");
+static void tab(int n) {
+       printk(KERN_DEBUG "%*s", n, "");
 }
 
 void hid_dump_field(struct hid_field *field, int n) {
@@ -401,8 +401,8 @@ void hid_dump_field(struct hid_field *field, int n) {
                tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
        }
        if (field->unit) {
-               char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
-               char *units[5][8] = {
+               static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+               static const char *units[5][8] = {
                        { "None", "None", "None", "None", "None", "None", "None", "None" },
                        { "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
                        { "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
@@ -457,7 +457,7 @@ void hid_dump_field(struct hid_field *field, int n) {
        printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
        printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
        printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
-       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : "");
        printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
        printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
        printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
@@ -470,7 +470,7 @@ void hid_dump_device(struct hid_device *device) {
        struct hid_report *report;
        struct list_head *list;
        unsigned i,k;
-       static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+       static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
 
        if (!hid_debug)
                return;
@@ -501,13 +501,13 @@ void hid_dump_input(struct hid_usage *usage, __s32 value) {
        if (!hid_debug)
                return;
 
-       printk("hid-debug: input ");
+       printk(KERN_DEBUG "hid-debug: input ");
        hid_resolv_usage(usage->hid);
        printk(" = %d\n", value);
 }
 EXPORT_SYMBOL_GPL(hid_dump_input);
 
-static char *events[EV_MAX + 1] = {
+static const char *events[EV_MAX + 1] = {
        [EV_SYN] = "Sync",                      [EV_KEY] = "Key",
        [EV_REL] = "Relative",                  [EV_ABS] = "Absolute",
        [EV_MSC] = "Misc",                      [EV_LED] = "LED",
@@ -516,10 +516,10 @@ static char *events[EV_MAX + 1] = {
        [EV_FF_STATUS] = "ForceFeedbackStatus",
 };
 
-static char *syncs[2] = {
+static const char *syncs[2] = {
        [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
 };
-static char *keys[KEY_MAX + 1] = {
+static const char *keys[KEY_MAX + 1] = {
        [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
        [KEY_1] = "1",                          [KEY_2] = "2",
        [KEY_3] = "3",                          [KEY_4] = "4",
@@ -697,7 +697,8 @@ static char *keys[KEY_MAX + 1] = {
        [KEY_DEL_LINE] = "DeleteLine",
        [KEY_SEND] = "Send",                    [KEY_REPLY] = "Reply",
        [KEY_FORWARDMAIL] = "ForwardMail",      [KEY_SAVE] = "Save",
-       [KEY_DOCUMENTS] = "Documents",
+       [KEY_DOCUMENTS] = "Documents",          [KEY_SPELLCHECK] = "SpellCheck",
+       [KEY_LOGOFF] = "Logoff",
        [KEY_FN] = "Fn",                        [KEY_FN_ESC] = "Fn+ESC",
        [KEY_FN_1] = "Fn+1",                    [KEY_FN_2] = "Fn+2",
        [KEY_FN_B] = "Fn+B",                    [KEY_FN_D] = "Fn+D",
@@ -715,7 +716,7 @@ static char *keys[KEY_MAX + 1] = {
        [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
 };
 
-static char *relatives[REL_MAX + 1] = {
+static const char *relatives[REL_MAX + 1] = {
        [REL_X] = "X",                  [REL_Y] = "Y",
        [REL_Z] = "Z",                  [REL_RX] = "Rx",
        [REL_RY] = "Ry",                [REL_RZ] = "Rz",
@@ -723,7 +724,7 @@ static char *relatives[REL_MAX + 1] = {
        [REL_WHEEL] = "Wheel",          [REL_MISC] = "Misc",
 };
 
-static char *absolutes[ABS_MAX + 1] = {
+static const char *absolutes[ABS_MAX + 1] = {
        [ABS_X] = "X",                  [ABS_Y] = "Y",
        [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
        [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
@@ -739,12 +740,12 @@ static char *absolutes[ABS_MAX + 1] = {
        [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
 };
 
-static char *misc[MSC_MAX + 1] = {
+static const char *misc[MSC_MAX + 1] = {
        [MSC_SERIAL] = "Serial",        [MSC_PULSELED] = "Pulseled",
        [MSC_GESTURE] = "Gesture",      [MSC_RAW] = "RawData"
 };
 
-static char *leds[LED_MAX + 1] = {
+static const char *leds[LED_MAX + 1] = {
        [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock",
        [LED_SCROLLL] = "ScrollLock",   [LED_COMPOSE] = "Compose",
        [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep",
@@ -752,16 +753,16 @@ static char *leds[LED_MAX + 1] = {
        [LED_MISC] = "Misc",
 };
 
-static char *repeats[REP_MAX + 1] = {
+static const char *repeats[REP_MAX + 1] = {
        [REP_DELAY] = "Delay",          [REP_PERIOD] = "Period"
 };
 
-static char *sounds[SND_MAX + 1] = {
+static const char *sounds[SND_MAX + 1] = {
        [SND_CLICK] = "Click",          [SND_BELL] = "Bell",
        [SND_TONE] = "Tone"
 };
 
-static char **names[EV_MAX + 1] = {
+static const char **names[EV_MAX + 1] = {
        [EV_SYN] = syncs,                       [EV_KEY] = keys,
        [EV_REL] = relatives,                   [EV_ABS] = absolutes,
        [EV_MSC] = misc,                        [EV_LED] = leds,
@@ -777,4 +778,3 @@ void hid_resolv_event(__u8 type, __u16 code) {
                names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
 }
 EXPORT_SYMBOL_GPL(hid_resolv_event);
-
index 8edbd30cf7955bcb54e80d2ce42fe6f2f545b8e2..dd332f28e08cb31106c6aa1598f6824fca69298d 100644 (file)
@@ -53,7 +53,7 @@ static const unsigned char hid_keyboard[256] = {
        115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
        122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
        unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+       unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
        unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
        unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
         29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
@@ -86,6 +86,10 @@ static const struct {
 #define map_abs_clear(c)       do { map_abs(c); clear_bit(c, bit); } while (0)
 #define map_key_clear(c)       do { map_key(c); clear_bit(c, bit); } while (0)
 
+/* hardware needing special handling due to colliding MSVENDOR page usages */
+#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418)
+#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9))
+
 #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
 
 struct hidinput_key_translation {
@@ -295,7 +299,7 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode,
 {
        struct hid_device *hid = dev->private;
        struct hid_usage *usage;
-       
+
        usage = hidinput_find_key(hid, scancode, 0);
        if (usage) {
                *keycode = usage->code;
@@ -310,15 +314,15 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
        struct hid_device *hid = dev->private;
        struct hid_usage *usage;
        int old_keycode;
-       
+
        if (keycode < 0 || keycode > KEY_MAX)
                return -EINVAL;
-       
+
        usage = hidinput_find_key(hid, scancode, 0);
        if (usage) {
                old_keycode = usage->code;
                usage->code = keycode;
-               
+
                clear_bit(old_keycode, dev->keybit);
                set_bit(usage->code, dev->keybit);
                dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
@@ -326,10 +330,10 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
                 * by another key */
                if (hidinput_find_key (hid, 0, old_keycode))
                        set_bit(old_keycode, dev->keybit);
-               
+
                return 0;
        }
-       
+
        return -EINVAL;
 }
 
@@ -351,6 +355,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
        if (field->flags & HID_MAIN_ITEM_CONSTANT)
                goto ignore;
 
+       /* only LED usages are supported in output fields */
+       if (field->report_type == HID_OUTPUT_REPORT &&
+                       (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
+               dbg_hid_line(" [non-LED output field] ");
+               goto ignore;
+       }
+
        switch (usage->hid & HID_USAGE_PAGE) {
 
                case HID_UP_UNDEFINED:
@@ -595,6 +606,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x0f6: map_key_clear(KEY_NEXT);            break;
                                case 0x0fa: map_key_clear(KEY_BACK);            break;
 
+                               case 0x182: map_key_clear(KEY_BOOKMARKS);       break;
                                case 0x183: map_key_clear(KEY_CONFIG);          break;
                                case 0x184: map_key_clear(KEY_WORDPROCESSOR);   break;
                                case 0x185: map_key_clear(KEY_EDITOR);          break;
@@ -611,9 +623,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x192: map_key_clear(KEY_CALC);            break;
                                case 0x194: map_key_clear(KEY_FILE);            break;
                                case 0x196: map_key_clear(KEY_WWW);             break;
+                               case 0x19c: map_key_clear(KEY_LOGOFF);          break;
                                case 0x19e: map_key_clear(KEY_COFFEE);          break;
                                case 0x1a6: map_key_clear(KEY_HELP);            break;
                                case 0x1a7: map_key_clear(KEY_DOCUMENTS);       break;
+                               case 0x1ab: map_key_clear(KEY_SPELLCHECK);      break;
+                               case 0x1b6: map_key_clear(KEY_MEDIA);           break;
+                               case 0x1b7: map_key_clear(KEY_SOUND);           break;
                                case 0x1bc: map_key_clear(KEY_MESSENGER);       break;
                                case 0x1bd: map_key_clear(KEY_INFO);            break;
                                case 0x201: map_key_clear(KEY_NEW);             break;
@@ -720,8 +736,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
                case HID_UP_MSVENDOR:
 
-                       /* special case - Chicony Chicony KU-0418 tactical pad */
-                       if (device->vendor == 0x04f2 && device->product == 0x0418) {
+                       /* Unfortunately, there are multiple devices which
+                        * emit usages from MSVENDOR page that require different
+                        * handling. If this list grows too much in the future,
+                        * more general handling will have to be introduced here
+                        * (i.e. another blacklist).
+                        */
+
+                       /* Chicony Chicony KU-0418 tactical pad */
+                       if (IS_CHICONY_TACTICAL_PAD(device)) {
                                set_bit(EV_REP, input->evbit);
                                switch(usage->hid & HID_USAGE) {
                                        case 0xff01: map_key_clear(BTN_1);              break;
@@ -737,6 +760,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                        case 0xff0b: map_key_clear(BTN_B);              break;
                                        default:    goto ignore;
                                }
+
+                       /* Microsoft Natural Ergonomic Keyboard 4000 */
+                       } else if (IS_MS_KB(device)) {
+                               switch(usage->hid & HID_USAGE) {
+                                       case 0xfd06:
+                                               map_key_clear(KEY_CHAT);
+                                               break;
+                                       case 0xfd07:
+                                               map_key_clear(KEY_PHONE);
+                                               break;
+                                       case 0xff05:
+                                               set_bit(EV_REP, input->evbit);
+                                               map_key_clear(KEY_F13);
+                                               set_bit(KEY_F14, input->keybit);
+                                               set_bit(KEY_F15, input->keybit);
+                                               set_bit(KEY_F16, input->keybit);
+                                               set_bit(KEY_F17, input->keybit);
+                                               set_bit(KEY_F18, input->keybit);
+                                       default:        goto ignore;
+                               }
                        } else {
                                goto ignore;
                        }
@@ -888,6 +931,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                set_bit(KEY_VOLUMEDOWN, input->keybit);
        }
 
+       if (usage->type == EV_KEY) {
+               set_bit(EV_MSC, input->evbit);
+               set_bit(MSC_SCAN, input->mscbit);
+       }
+
        hid_resolv_event(usage->type, usage->code);
 
        dbg_hid_line("\n");
@@ -902,7 +950,7 @@ ignore:
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
 {
        struct input_dev *input;
-       int *quirks = &hid->quirks;
+       unsigned *quirks = &hid->quirks;
 
        if (!field->hidinput)
                return;
@@ -991,6 +1039,29 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
+       /* Handling MS keyboards special buttons */
+       if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+               int key = 0;
+               static int last_key = 0;
+               switch (value) {
+                       case 0x01: key = KEY_F14; break;
+                       case 0x02: key = KEY_F15; break;
+                       case 0x04: key = KEY_F16; break;
+                       case 0x08: key = KEY_F17; break;
+                       case 0x10: key = KEY_F18; break;
+                       default: break;
+               }
+               if (key) {
+                       input_event(input, usage->type, key, 1);
+                       last_key = key;
+               } else {
+                       input_event(input, usage->type, last_key, 0);
+               }
+       }
+       /* report the usage code as scancode if the key status has changed */
+       if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
+               input_event(input, EV_MSC, MSC_SCAN, usage->hid);
+
        input_event(input, usage->type, usage->code, value);
 
        if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
@@ -1051,6 +1122,9 @@ int hidinput_connect(struct hid_device *hid)
        int i, j, k;
        int max_report_type = HID_OUTPUT_REPORT;
 
+       if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
+               return -1;
+
        INIT_LIST_HEAD(&hid->inputs);
 
        for (i = 0; i < hid->maxcollection; i++)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
new file mode 100644 (file)
index 0000000..a702e2f
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * HID raw devices, giving access to raw HID events.
+ *
+ * In comparison to hiddev, this device does not process the
+ * hid events at all (no parsing, no lookups). This lets applications
+ * to work on raw hid events as they want to, and avoids a need to
+ * use a transport-specific userspace libhid/libusb libraries.
+ *
+ *  Copyright (c) 2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/major.h>
+#include <linux/hid.h>
+#include <linux/mutex.h>
+
+#include <linux/hidraw.h>
+
+static int hidraw_major;
+static struct cdev hidraw_cdev;
+static struct class *hidraw_class;
+static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
+static DEFINE_SPINLOCK(minors_lock);
+
+static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+       struct hidraw_list *list = file->private_data;
+       int ret = 0, len;
+       char *report;
+       DECLARE_WAITQUEUE(wait, current);
+
+       while (ret == 0) {
+
+               mutex_lock(&list->read_mutex);
+
+               if (list->head == list->tail) {
+                       add_wait_queue(&list->hidraw->wait, &wait);
+                       set_current_state(TASK_INTERRUPTIBLE);
+
+                       while (list->head == list->tail) {
+                               if (file->f_flags & O_NONBLOCK) {
+                                       ret = -EAGAIN;
+                                       break;
+                               }
+                               if (signal_pending(current)) {
+                                       ret = -ERESTARTSYS;
+                                       break;
+                               }
+                               if (!list->hidraw->exist) {
+                                       ret = -EIO;
+                                       break;
+                               }
+
+                               /* allow O_NONBLOCK to work well from other threads */
+                               mutex_unlock(&list->read_mutex);
+                               schedule();
+                               mutex_lock(&list->read_mutex);
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+
+                       set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&list->hidraw->wait, &wait);
+               }
+
+               if (ret)
+                       goto out;
+
+               report = list->buffer[list->tail].value;
+               len = list->buffer[list->tail].len > count ?
+                       count : list->buffer[list->tail].len;
+
+               if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               ret += len;
+
+               kfree(list->buffer[list->tail].value);
+               list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
+       }
+out:
+       mutex_unlock(&list->read_mutex);
+       return ret;
+}
+
+/* the first byte is expected to be a report number */
+static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+       unsigned int minor = iminor(file->f_path.dentry->d_inode);
+       struct hid_device *dev = hidraw_table[minor]->hid;
+       __u8 *buf;
+       int ret = 0;
+
+       if (!dev->hid_output_raw_report)
+               return -ENODEV;
+
+       if (count > HID_MIN_BUFFER_SIZE) {
+               printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
+                               current->pid);
+               return -EINVAL;
+       }
+
+       if (count < 2) {
+               printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
+                               current->pid);
+               return -EINVAL;
+       }
+
+       buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, buffer, count)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       ret = dev->hid_output_raw_report(dev, buf, count);
+out:
+       kfree(buf);
+       return ret;
+}
+
+static unsigned int hidraw_poll(struct file *file, poll_table *wait)
+{
+       struct hidraw_list *list = file->private_data;
+
+       poll_wait(file, &list->hidraw->wait, wait);
+       if (list->head != list->tail)
+               return POLLIN | POLLRDNORM;
+       if (!list->hidraw->exist)
+               return POLLERR | POLLHUP;
+       return 0;
+}
+
+static int hidraw_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor = iminor(inode);
+       struct hidraw *dev;
+       struct hidraw_list *list;
+       int err = 0;
+
+       if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       spin_lock(&minors_lock);
+       if (!hidraw_table[minor]) {
+               printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
+                               minor);
+               kfree(list);
+               err = -ENODEV;
+               goto out_unlock;
+       }
+
+       list->hidraw = hidraw_table[minor];
+       mutex_init(&list->read_mutex);
+       list_add_tail(&list->node, &hidraw_table[minor]->list);
+       file->private_data = list;
+
+       dev = hidraw_table[minor];
+       if (!dev->open++)
+               dev->hid->hid_open(dev->hid);
+
+out_unlock:
+       spin_unlock(&minors_lock);
+out:
+       return err;
+
+}
+
+static int hidraw_release(struct inode * inode, struct file * file)
+{
+       unsigned int minor = iminor(inode);
+       struct hidraw *dev;
+       struct hidraw_list *list = file->private_data;
+
+       if (!hidraw_table[minor]) {
+               printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
+                               minor);
+               return -ENODEV;
+       }
+
+       list_del(&list->node);
+       dev = hidraw_table[minor];
+       if (!dev->open--) {
+               if (list->hidraw->exist)
+                       dev->hid->hid_close(dev->hid);
+               else
+                       kfree(list->hidraw);
+       }
+
+       return 0;
+}
+
+static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       unsigned int minor = iminor(inode);
+       struct hidraw *dev = hidraw_table[minor];
+       void __user *user_arg = (void __user*) arg;
+
+       switch (cmd) {
+               case HIDIOCGRDESCSIZE:
+                       if (put_user(dev->hid->rsize, (int __user *)arg))
+                               return -EFAULT;
+                       return 0;
+
+               case HIDIOCGRDESC:
+                       {
+                               __u32 len;
+
+                               if (get_user(len, (int __user *)arg))
+                                       return -EFAULT;
+
+                               if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
+                                       return -EINVAL;
+
+                               if (copy_to_user(user_arg + offsetof(
+                                                               struct hidraw_report_descriptor,
+                                                               value[0]),
+                                                       dev->hid->rdesc,
+                                                       min(dev->hid->rsize, len)))
+                                               return -EFAULT;
+                               return 0;
+                       }
+               case HIDIOCGRAWINFO:
+                       {
+                               struct hidraw_devinfo dinfo;
+
+                               dinfo.bustype = dev->hid->bus;
+                               dinfo.vendor = dev->hid->vendor;
+                               dinfo.product = dev->hid->product;
+                               if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
+                                       return -EFAULT;
+
+                               return 0;
+                       }
+               default:
+                       printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n",
+                                       cmd);
+       }
+       return -EINVAL;
+}
+
+static const struct file_operations hidraw_ops = {
+       .owner =        THIS_MODULE,
+       .read =         hidraw_read,
+       .write =        hidraw_write,
+       .poll =         hidraw_poll,
+       .open =         hidraw_open,
+       .release =      hidraw_release,
+       .ioctl =        hidraw_ioctl,
+};
+
+void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+{
+       struct hidraw *dev = hid->hidraw;
+       struct hidraw_list *list;
+
+       list_for_each_entry(list, &dev->list, node) {
+               list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
+               list->buffer[list->head].len = len;
+               list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
+               kill_fasync(&list->fasync, SIGIO, POLL_IN);
+       }
+
+       wake_up_interruptible(&dev->wait);
+}
+EXPORT_SYMBOL_GPL(hidraw_report_event);
+
+int hidraw_connect(struct hid_device *hid)
+{
+       int minor, result;
+       struct hidraw *dev;
+
+       /* TODO currently we accept any HID device. This should later
+        * probably be fixed to accept only those devices which provide
+        * non-input applications
+        */
+
+       dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       result = -EINVAL;
+
+       spin_lock(&minors_lock);
+
+       for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
+               if (hidraw_table[minor])
+                       continue;
+               hidraw_table[minor] = dev;
+               result = 0;
+               break;
+       }
+
+       spin_unlock(&minors_lock);
+
+       if (result) {
+               kfree(dev);
+               goto out;
+       }
+
+       dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor),
+                               "%s%d", "hidraw", minor);
+
+       if (IS_ERR(dev->dev)) {
+               spin_lock(&minors_lock);
+               hidraw_table[minor] = NULL;
+               spin_unlock(&minors_lock);
+               result = PTR_ERR(dev->dev);
+               kfree(dev);
+               goto out;
+       }
+
+       init_waitqueue_head(&dev->wait);
+       INIT_LIST_HEAD(&dev->list);
+
+       dev->hid = hid;
+       dev->minor = minor;
+
+       dev->exist = 1;
+       hid->hidraw = dev;
+
+out:
+       return result;
+
+}
+EXPORT_SYMBOL_GPL(hidraw_connect);
+
+void hidraw_disconnect(struct hid_device *hid)
+{
+       struct hidraw *hidraw = hid->hidraw;
+
+       hidraw->exist = 0;
+
+       spin_lock(&minors_lock);
+       hidraw_table[hidraw->minor] = NULL;
+       spin_unlock(&minors_lock);
+
+       device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+
+       if (hidraw->open) {
+               hid->hid_close(hid);
+               wake_up_interruptible(&hidraw->wait);
+       } else {
+               kfree(hidraw);
+       }
+}
+EXPORT_SYMBOL_GPL(hidraw_disconnect);
+
+int __init hidraw_init(void)
+{
+       int result;
+       dev_t dev_id;
+
+       result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
+                       HIDRAW_MAX_DEVICES, "hidraw");
+
+       hidraw_major = MAJOR(dev_id);
+
+       if (result < 0) {
+               printk(KERN_WARNING "hidraw: can't get major number\n");
+               result = 0;
+               goto out;
+       }
+
+       hidraw_class = class_create(THIS_MODULE, "hidraw");
+       if (IS_ERR(hidraw_class)) {
+               result = PTR_ERR(hidraw_class);
+               unregister_chrdev(hidraw_major, "hidraw");
+               goto out;
+       }
+
+        cdev_init(&hidraw_cdev, &hidraw_ops);
+        cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+out:
+       return result;
+}
+
+void __exit hidraw_exit(void)
+{
+       dev_t dev_id = MKDEV(hidraw_major, 0);
+
+       cdev_del(&hidraw_cdev);
+       class_destroy(hidraw_class);
+       unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
+
+}
index 1b4b572f899ba6c1f23fbb6c9685687fddfb4a99..c557d7040a69a946ea91458ef8724dab85247c2a 100644 (file)
@@ -71,19 +71,20 @@ config LOGITECH_FF
          force feedback.
 
 config PANTHERLORD_FF
-       bool "PantherLord USB/PS2 2in1 Adapter support"
+       bool "PantherLord/GreenAsia based device support"
        depends on HID_FF
        select INPUT_FF_MEMLESS if USB_HID
        help
-         Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
-         to enable force feedback support for it.
+         Say Y here if you have a PantherLord/GreenAsia based game controller
+         or adapter and want to enable force feedback support for it.
 
 config THRUSTMASTER_FF
-       bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+       bool "ThrustMaster devices support (EXPERIMENTAL)"
        depends on HID_FF && EXPERIMENTAL
        select INPUT_FF_MEMLESS if USB_HID
        help
-         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
+         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
          and want to enable force feedback support for it.
          Note: if you say N here, this device will still be supported, but without
          force feedback.
index 0a1f2b52a12fa4bab847f905e8f5069e87cb5944..b38e559b7a46073dab466375200002828f7602ab 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/hid.h>
 #include <linux/hiddev.h>
 #include <linux/hid-debug.h>
+#include <linux/hidraw.h>
 #include "usbhid.h"
 
 /*
@@ -512,7 +513,16 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 
 int usbhid_open(struct hid_device *hid)
 {
-       ++hid->open;
+       struct usbhid_device *usbhid = hid->driver_data;
+       int res;
+
+       if (!hid->open++) {
+               res = usb_autopm_get_interface(usbhid->intf);
+               if (res < 0) {
+                       hid->open--;
+                       return -EIO;
+               }
+       }
        if (hid_start_in(hid))
                hid_io_error(hid);
        return 0;
@@ -522,8 +532,10 @@ void usbhid_close(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
-       if (!--hid->open)
+       if (!--hid->open) {
                usb_kill_urb(usbhid->urbin);
+               usb_autopm_put_interface(usbhid->intf);
+       }
 }
 
 /*
@@ -628,6 +640,28 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
        return 0;
 }
 
+static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+       struct usb_device *dev = hid_to_usb_dev(hid);
+       struct usb_interface *intf = usbhid->intf;
+       struct usb_host_interface *interface = intf->cur_altsetting;
+       int ret;
+
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               HID_REQ_SET_REPORT,
+               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf),
+               interface->desc.bInterfaceNumber, buf + 1, count - 1,
+               USB_CTRL_SET_TIMEOUT);
+
+       /* count also the report id */
+       if (ret > 0)
+               ret++;
+
+       return ret;
+}
+
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
@@ -871,6 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        hid->hiddev_hid_event = hiddev_hid_event;
        hid->hiddev_report_event = hiddev_report_event;
 #endif
+       hid->hid_output_raw_report = usbhid_output_raw_report;
        return hid;
 
 fail:
@@ -909,6 +944,8 @@ static void hid_disconnect(struct usb_interface *intf)
                hidinput_disconnect(hid);
        if (hid->claimed & HID_CLAIMED_HIDDEV)
                hiddev_disconnect(hid);
+       if (hid->claimed & HID_CLAIMED_HIDRAW)
+               hidraw_disconnect(hid);
 
        usb_free_urb(usbhid->urbin);
        usb_free_urb(usbhid->urbctrl);
@@ -941,11 +978,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
                hid->claimed |= HID_CLAIMED_INPUT;
        if (!hiddev_connect(hid))
                hid->claimed |= HID_CLAIMED_HIDDEV;
+       if (!hidraw_connect(hid))
+               hid->claimed |= HID_CLAIMED_HIDRAW;
 
        usb_set_intfdata(intf, hid);
 
        if (!hid->claimed) {
-               printk ("HID device not claimed by input or hiddev\n");
+               printk ("HID device claimed by neither input, hiddev nor hidraw\n");
                hid_disconnect(intf);
                return -ENODEV;
        }
@@ -961,10 +1000,16 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        if (hid->claimed & HID_CLAIMED_INPUT)
                printk("input");
-       if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
+       if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
+                               hid->claimed & HID_CLAIMED_HIDRAW))
                printk(",");
        if (hid->claimed & HID_CLAIMED_HIDDEV)
                printk("hiddev%d", hid->minor);
+       if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
+                       (hid->claimed & HID_CLAIMED_HIDRAW))
+               printk(",");
+       if (hid->claimed & HID_CLAIMED_HIDRAW)
+               printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
 
        c = "Device";
        for (i = 0; i < hid->maxcollection; i++) {
@@ -1048,6 +1093,7 @@ static struct usb_driver hid_driver = {
        .pre_reset =    hid_pre_reset,
        .post_reset =   hid_post_reset,
        .id_table =     hid_usb_ids,
+       .supports_autosuspend = 1,
 };
 
 static int __init hid_init(void)
index 23431fbbc3d7e7030976357721785c9f0dcb1e6d..22329feb3b5ae63d7b65a3e561f263da7935342d 100644 (file)
@@ -62,11 +62,14 @@ static struct hid_ff_initializer inits[] = {
        { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
 #endif
 #ifdef CONFIG_PANTHERLORD_FF
-       { 0x810, 0x0001, hid_plff_init },
+       { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
+       { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc.    USB Joystick     " */
 #endif
 #ifdef CONFIG_THRUSTMASTER_FF
        { 0x44f, 0xb300, hid_tmff_init },
        { 0x44f, 0xb304, hid_tmff_init },
+       { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
+       { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
 #endif
 #ifdef CONFIG_ZEROPLUS_FF
        { 0xc12, 0x0005, hid_zpff_init },
index d6a8f2b49bd242c3b6875320cfe32f4c5ba099a8..9eb83cf9d22b98021d540b61f08be3a690f45466 100644 (file)
@@ -1,5 +1,15 @@
 /*
- *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *  Force feedback support for PantherLord/GreenAsia based devices
+ *
+ *  The devices are distributed under various names and the same USB device ID
+ *  can be used in both adapters and actual game controllers.
+ *
+ *  0810:0001 "Twin USB Joystick"
+ *   - tested with PantherLord USB/PS2 2in1 Adapter
+ *   - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
+ *
+ *  0e8f:0003 "GreenAsia Inc.    USB Joystick     "
+ *   - tested with Köng Gaming gamepad
  *
  *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
  */
@@ -67,11 +77,11 @@ int hid_plff_init(struct hid_device *hid)
        struct input_dev *dev;
        int error;
 
-       /* The device contains 2 output reports (one for each
-          HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
-          contains 4 ff00.0002 usages and 4 16bit absolute values.
+       /* The device contains one output report per physical device, all
+          containing 1 field, which contains 4 ff00.0002 usages and 4 16bit
+          absolute values.
 
-          The input reports also contain a field which contains
+          The input reports also contain a field which contains
           8 ff00.0001 usages and 8 boolean values. Their meaning is
           currently unknown. */
 
@@ -122,8 +132,8 @@ int hid_plff_init(struct hid_device *hid)
                usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
        }
 
-       printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
-              "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+       printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia "
+              "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 }
index 6b21a214f419028f212f238374d92687f1e3a556..41a59a80e7edff34299d0a0d3f93225eedc9381a 100644 (file)
@@ -61,6 +61,7 @@
 #define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
 
 #define USB_VENDOR_ID_ASUS             0x0b05
 #define USB_DEVICE_ID_ASUS_LCM         0x1726
@@ -86,6 +87,9 @@
 
 #define USB_VENDOR_ID_CIDC             0x1677
 
+#define USB_VENDOR_ID_CMEDIA           0x0d8c
+#define USB_DEVICE_ID_CM109            0x000e
+
 #define USB_VENDOR_ID_CODEMERCS                0x07c0
 #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST      0x1500
 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST       0x15ff
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
 
+#define USB_VENDOR_ID_ELO              0x04E7
+#define USB_DEVICE_ID_ELO_TS2700       0x0020
+
 #define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
 #define USB_VENDOR_ID_GAMERON          0x0810
 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
 
+#define USB_VENDOR_ID_GENERAL_TOUCH    0x0dfc
+
 #define USB_VENDOR_ID_GLAB             0x06c2
 #define USB_DEVICE_ID_4_PHIDGETSERVO_30        0x0038
 #define USB_DEVICE_ID_1_PHIDGETSERVO_30        0x0039
@@ -373,6 +382,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
 
        { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
 
        { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
@@ -387,11 +397,16 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
        { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
@@ -507,6 +522,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
@@ -614,6 +630,8 @@ static const struct hid_rdesc_blacklist {
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
 
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
+
        { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
 
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
@@ -927,6 +945,18 @@ static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
                printk(KERN_INFO "Fixing up Cypress report descriptor\n");
 }
 
+/*
+ * MacBook JIS keyboard has wrong logical maximum
+ */
+static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
+{
+       if (rsize >= 60 && rdesc[53] == 0x65
+                       && rdesc[59] == 0x65) {
+               printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n");
+               rdesc[53] = rdesc[59] = 0xe7;
+       }
+}
+
 
 static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
 {
@@ -941,6 +971,9 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
 
        if (quirks & HID_QUIRK_RDESC_PETALYNX)
                usbhid_fixup_petalynx_descriptor(rdesc, rsize);
+
+       if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
+               usbhid_fixup_macbook_descriptor(rdesc, rsize);
 }
 
 /**
index 555bb48b4295d0d7ea167702ea125bcb4cbd1088..69882a726e99d8cc19b6fda183e2b0f9ca8de240 100644 (file)
 #include "usbhid.h"
 
 /* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_RUMBLE_LR   (HID_UP_GENDESK | 0xbb)
+#define THRUSTMASTER_USAGE_FF  (HID_UP_GENDESK | 0xbb)
 
+struct dev_type {
+       u16 idVendor;
+       u16 idProduct;
+       const signed short *ff;
+};
+
+static const signed short ff_rumble[] = {
+       FF_RUMBLE,
+       -1
+};
+
+static const signed short ff_joystick[] = {
+       FF_CONSTANT,
+       -1
+};
+
+static const struct dev_type devices[] = {
+       { 0x44f, 0xb300, ff_rumble },
+       { 0x44f, 0xb304, ff_rumble },
+       { 0x44f, 0xb651, ff_rumble },   /* FGT Rumble Force Wheel */
+       { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
+};
 
 struct tmff_device {
        struct hid_report *report;
-       struct hid_field *rumble;
+       struct hid_field *ff_field;
 };
 
 /* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
+static inline int hid_tmff_scale_u16(unsigned int in,
+                               int minimum, int maximum)
 {
        int ret;
 
@@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
        return ret;
 }
 
+/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
+static inline int hid_tmff_scale_s8(int in,
+                                   int minimum, int maximum)
+{
+       int ret;
+
+       ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
+       if (ret < minimum)
+               return minimum;
+       if (ret > maximum)
+               return maximum;
+       return ret;
+}
+
 static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
        struct hid_device *hid = input_get_drvdata(dev);
        struct tmff_device *tmff = data;
+       struct hid_field *ff_field = tmff->ff_field;
+       int x, y;
        int left, right;        /* Rumbling */
 
-       left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
-               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-       right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
-               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-
-       tmff->rumble->value[0] = left;
-       tmff->rumble->value[1] = right;
-       dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
-       usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-
+       switch (effect->type) {
+       case FF_CONSTANT:
+               x = hid_tmff_scale_s8(effect->u.ramp.start_level,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+               y = hid_tmff_scale_s8(effect->u.ramp.end_level,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+
+               dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
+               ff_field->value[0] = x;
+               ff_field->value[1] = y;
+               usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+               break;
+
+       case FF_RUMBLE:
+               left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+               right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+
+               dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
+               ff_field->value[0] = left;
+               ff_field->value[1] = right;
+               usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+               break;
+       }
        return 0;
 }
 
@@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid)
        struct list_head *pos;
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
        struct input_dev *input_dev = hidinput->input;
+       const signed short *ff_bits = ff_joystick;
        int error;
+       int i;
 
        tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
        if (!tmff)
                return -ENOMEM;
 
        /* Find the report to use */
-       __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
+       list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
                struct hid_report *report = (struct hid_report *)pos;
                int fieldnum;
 
@@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid)
                                continue;
 
                        switch (field->usage[0].hid) {
-                               case THRUSTMASTER_USAGE_RUMBLE_LR:
-                                       if (field->report_count < 2) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
-                                               continue;
-                                       }
+                       case THRUSTMASTER_USAGE_FF:
+                               if (field->report_count < 2) {
+                                       warn("ignoring FF field with report_count < 2");
+                                       continue;
+                               }
 
-                                       if (field->logical_maximum == field->logical_minimum) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
-                                               continue;
-                                       }
+                               if (field->logical_maximum == field->logical_minimum) {
+                                       warn("ignoring FF field with logical_maximum == logical_minimum");
+                                       continue;
+                               }
 
-                                       if (tmff->report && tmff->report != report) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
-                                               continue;
-                                       }
+                               if (tmff->report && tmff->report != report) {
+                                       warn("ignoring FF field in other report");
+                                       continue;
+                               }
 
-                                       if (tmff->rumble && tmff->rumble != field) {
-                                               warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
-                                               continue;
+                               if (tmff->ff_field && tmff->ff_field != field) {
+                                       warn("ignoring duplicate FF field");
+                                       continue;
+                               }
+
+                               tmff->report = report;
+                               tmff->ff_field = field;
+
+                               for (i = 0; i < ARRAY_SIZE(devices); i++) {
+                                       if (input_dev->id.vendor == devices[i].idVendor &&
+                                           input_dev->id.product == devices[i].idProduct) {
+                                               ff_bits = devices[i].ff;
+                                               break;
                                        }
+                               }
 
-                                       tmff->report = report;
-                                       tmff->rumble = field;
+                               for (i = 0; ff_bits[i] >= 0; i++)
+                                       set_bit(ff_bits[i], input_dev->ffbit);
 
-                                       set_bit(FF_RUMBLE, input_dev->ffbit);
-                                       break;
+                               break;
 
-                               default:
-                                       warn("ignoring unknown output usage %08x", field->usage[0].hid);
-                                       continue;
+                       default:
+                               warn("ignoring unknown output usage %08x", field->usage[0].hid);
+                               continue;
                        }
                }
        }
 
-       error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
-       if (error) {
-               kfree(tmff);
-               return error;
+       if (!tmff->report) {
+               err("cant find FF field in output reports\n");
+               error = -ENODEV;
+               goto fail;
        }
 
-       info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
+       error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+       if (error)
+               goto fail;
 
+       info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
        return 0;
+
+ fail:
+       kfree(tmff);
+       return error;
 }
 
index e793127f971eae29903298b7cb6d3ec64a156325..9837adcb17e940478568fa33e89e194508c1cad1 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/usb.h>
 #include <linux/hid.h>
 #include <linux/hiddev.h>
+#include <linux/compat.h>
 #include "usbhid.h"
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -738,6 +739,14 @@ inval:
        return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       return hiddev_ioctl(inode, file, cmd, compat_ptr(arg));
+}
+#endif
+
 static const struct file_operations hiddev_fops = {
        .owner =        THIS_MODULE,
        .read =         hiddev_read,
@@ -747,6 +756,9 @@ static const struct file_operations hiddev_fops = {
        .release =      hiddev_release,
        .ioctl =        hiddev_ioctl,
        .fasync =       hiddev_fasync,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = hiddev_compat_ioctl,
+#endif
 };
 
 static struct usb_class_driver hiddev_class = {
index dd9dc47ee84e92ea3a69cd3b4743bcb294419917..700a1657554f4b3b5f4910268343790ddb33c1eb 100644 (file)
@@ -30,7 +30,7 @@ config HWMON_VID
 
 config SENSORS_ABITUGURU
        tristate "Abit uGuru (rev 1 & 2)"
-       depends on EXPERIMENTAL
+       depends on X86 && EXPERIMENTAL
        help
          If you say yes here you get support for the sensor part of the first
          and second revision of the Abit uGuru chip. The voltage and frequency
@@ -45,7 +45,7 @@ config SENSORS_ABITUGURU
 
 config SENSORS_ABITUGURU3
        tristate "Abit uGuru (rev 3)"
-       depends on HWMON && EXPERIMENTAL
+       depends on X86 && EXPERIMENTAL
        help
          If you say yes here you get support for the sensor part of the
          third revision of the Abit uGuru chip. Only reading the sensors
@@ -133,6 +133,16 @@ config SENSORS_ADM9240
          This driver can also be built as a module.  If so, the module
          will be called adm9240.
 
+config SENSORS_ADT7470
+       tristate "Analog Devices ADT7470"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for the Analog Devices
+         ADT7470 temperature monitoring chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called adt7470.
+
 config SENSORS_K8TEMP
        tristate "AMD Athlon64/FX or Opteron temperature sensor"
        depends on X86 && PCI && EXPERIMENTAL
@@ -173,7 +183,7 @@ config SENSORS_AMS_I2C
 
 config SENSORS_ASB100
        tristate "Asus ASB100 Bach"
-       depends on I2C && EXPERIMENTAL
+       depends on X86 && I2C && EXPERIMENTAL
        select HWMON_VID
        help
          If you say yes here you get support for the ASB100 Bach sensor
@@ -207,19 +217,39 @@ config SENSORS_DS1621
          will be called ds1621.
 
 config SENSORS_F71805F
-       tristate "Fintek F71805F/FG and F71872F/FG"
+       tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
        depends on EXPERIMENTAL
        help
          If you say yes here you get support for hardware monitoring
-         features of the Fintek F71805F/FG and F71872F/FG Super-I/O
-         chips.
+         features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG
+         Super-I/O chips.
 
          This driver can also be built as a module.  If so, the module
          will be called f71805f.
 
+config SENSORS_F71882FG
+       tristate "Fintek F71882FG and F71883FG"
+       depends on EXPERIMENTAL
+       help
+         If you say yes here you get support for hardware monitoring
+         features of the Fintek F71882FG and F71883FG Super-I/O chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called f71882fg.
+
+config SENSORS_F75375S
+       tristate "Fintek F75375S/SP and F75373";
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for hardware monitoring
+         features of the Fintek F75375S/SP and F75373
+
+         This driver can also be built as a module.  If so, the module
+         will be called f75375s.
+
 config SENSORS_FSCHER
        tristate "FSC Hermes"
-       depends on I2C
+       depends on X86 && I2C
        help
          If you say yes here you get support for Fujitsu Siemens
          Computers Hermes sensor chips.
@@ -229,7 +259,7 @@ config SENSORS_FSCHER
 
 config SENSORS_FSCPOS
        tristate "FSC Poseidon"
-       depends on I2C
+       depends on X86 && I2C
        help
          If you say yes here you get support for Fujitsu Siemens
          Computers Poseidon sensor chips.
@@ -237,6 +267,20 @@ config SENSORS_FSCPOS
          This driver can also be built as a module.  If so, the module
          will be called fscpos.
 
+config SENSORS_FSCHMD
+       tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
+       depends on X86 && I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for various Fujitsu Siemens
+         Computers sensor chips.
+
+         This is a new merged driver for FSC sensor chips which is intended
+         as a replacment for the fscpos, fscscy and fscher drivers and adds
+         support for several other FCS sensor chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called fschmd.
+
 config SENSORS_GL518SM
        tristate "Genesys Logic GL518SM"
        depends on I2C
@@ -266,6 +310,19 @@ config SENSORS_CORETEMP
          sensor inside your CPU. Supported all are all known variants
          of Intel Core family.
 
+config SENSORS_IBMPEX
+       tristate "IBM PowerExecutive temperature/power sensors"
+       select IPMI_SI
+       depends on IPMI_HANDLER
+       help
+         If you say yes here you get support for the temperature and
+         power sensors in various IBM System X servers that support
+         PowerExecutive.  So far this includes the x3550, x3650, x3655,
+         x3755, and certain HS20 blades.
+
+         This driver can also be built as a module.  If so, the module
+         will be called ibmpex.
+
 config SENSORS_IT87
        tristate "ITE IT87xx and compatibles"
        select HWMON_VID
@@ -402,7 +459,7 @@ config SENSORS_LM92
 
 config SENSORS_LM93
        tristate "National Semiconductor LM93 and compatibles"
-       depends on HWMON && I2C
+       depends on I2C
        select HWMON_VID
        help
          If you say yes here you get support for National Semiconductor LM93
@@ -467,13 +524,13 @@ config SENSORS_SIS5595
          will be called sis5595.
 
 config SENSORS_DME1737
-       tristate "SMSC DME1737 and compatibles"
+       tristate "SMSC DME1737, SCH311x and compatibles"
        depends on I2C && EXPERIMENTAL
        select HWMON_VID
        help
          If you say yes here you get support for the hardware monitoring
          and fan control features of the SMSC DME1737 (and compatibles
-         like the Asus A8000) Super-I/O chip.
+         like the Asus A8000) and SCH311x Super-I/O chips.
 
          This driver can also be built as a module.  If so, the module
          will be called dme1737.
index d04f90031ebfbce2f22aa63dba2fa9d061497d7f..6da3eef943064a82302fda6ae75b68dc6f5f2e64 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
 obj-$(CONFIG_SENSORS_ADM1029)  += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
+obj-$(CONFIG_SENSORS_ADT7470)  += adt7470.o
 obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
 obj-$(CONFIG_SENSORS_AMS)      += ams/
 obj-$(CONFIG_SENSORS_ATXP1)    += atxp1.o
@@ -29,11 +30,15 @@ obj-$(CONFIG_SENSORS_CORETEMP)      += coretemp.o
 obj-$(CONFIG_SENSORS_DME1737)  += dme1737.o
 obj-$(CONFIG_SENSORS_DS1621)   += ds1621.o
 obj-$(CONFIG_SENSORS_F71805F)  += f71805f.o
+obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
+obj-$(CONFIG_SENSORS_F75375S)  += f75375s.o
 obj-$(CONFIG_SENSORS_FSCHER)   += fscher.o
+obj-$(CONFIG_SENSORS_FSCHMD)   += fschmd.o
 obj-$(CONFIG_SENSORS_FSCPOS)   += fscpos.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
 obj-$(CONFIG_SENSORS_HDAPS)    += hdaps.o
+obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
index 2317f4bb9c92163b93d0dae550904a34b071d3a0..4dbdb81ea3b1bfffce5d016746409ef7a3fe7f1d 100644 (file)
@@ -176,7 +176,7 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
    The structure is dynamically allocated, at the same time when a new
    abituguru device is allocated. */
 struct abituguru_data {
-       struct class_device *class_dev; /* hwmon registered device */
+       struct device *hwmon_dev;       /* hwmon registered device */
        struct mutex update_lock;       /* protect access to data and uGuru */
        unsigned long last_updated;     /* In jiffies */
        unsigned short addr;            /* uguru base address */
@@ -1287,11 +1287,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
                                &abituguru_sysfs_attr[i].dev_attr))
                        goto abituguru_probe_error;
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (!IS_ERR(data->class_dev))
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (!IS_ERR(data->hwmon_dev))
                return 0; /* success */
 
-       res = PTR_ERR(data->class_dev);
+       res = PTR_ERR(data->hwmon_dev);
 abituguru_probe_error:
        for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
                device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
@@ -1308,7 +1308,7 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
        int i;
        struct abituguru_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
                device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
        for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
index cdd8b6dea16ddb4d851fef2ea030fe1f47a6a6cf..cb2331bfd9d5a0f040c49e61fdba8fe0daca7111 100644 (file)
@@ -124,7 +124,7 @@ struct abituguru3_motherboard_info {
    The structure is dynamically allocated, at the same time when a new
    abituguru3 device is allocated. */
 struct abituguru3_data {
-       struct class_device *class_dev; /* hwmon registered device */
+       struct device *hwmon_dev;       /* hwmon registered device */
        struct mutex update_lock;       /* protect access to data and uGuru */
        unsigned short addr;            /* uguru base address */
        char valid;                     /* !=0 if following fields are valid */
@@ -933,9 +933,9 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
                                &abituguru3_sysfs_attr[i].dev_attr))
                        goto abituguru3_probe_error;
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               res = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               res = PTR_ERR(data->hwmon_dev);
                goto abituguru3_probe_error;
        }
 
@@ -957,7 +957,7 @@ static int __devexit abituguru3_remove(struct platform_device *pdev)
        struct abituguru3_data *data = platform_get_drvdata(pdev);
 
        platform_set_drvdata(pdev, NULL);
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
                device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
        for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
index cc8b624a1e51539f25df6dc06b01cb78ef1e90f2..fcd7fe78f3f9838b891635a2186d3170dc5a1ba4 100644 (file)
@@ -47,7 +47,7 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
 
 struct ad7418_data {
        struct i2c_client       client;
-       struct class_device     *class_dev;
+       struct device           *hwmon_dev;
        struct attribute_group  attrs;
        enum chips              type;
        struct mutex            lock;
@@ -172,7 +172,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct ad7418_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->lock);
        data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
@@ -326,9 +326,9 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -347,7 +347,7 @@ exit:
 static int ad7418_detach_client(struct i2c_client *client)
 {
        struct ad7418_data *data = i2c_get_clientdata(client);
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
        i2c_detach_client(client);
        kfree(data);
index c466329b2ef4745100f00346c4f989958f42828e..ebdc6d7db2318c295a84deca0db123b04091bd11 100644 (file)
@@ -1,6 +1,6 @@
 /*
     adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
-             monitoring
+               monitoring
     Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
     Philip Edelbrock <phil@netroedge.com>
 
@@ -25,6 +25,7 @@
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
                                        0x29, 0x2a, 0x2b,
-                                       0x4c, 0x4d, 0x4e, 
+                                       0x4c, 0x4d, 0x4e,
                                        I2C_CLIENT_END };
 
 /* Insmod parameters */
-I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
+I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm,
+                       mc1066);
 
 /* adm1021 constants specified below */
 
 /* The adm1021 registers */
 /* Read-only */
-#define ADM1021_REG_TEMP               0x00
-#define ADM1021_REG_REMOTE_TEMP                0x01
+/* For nr in 0-1 */
+#define ADM1021_REG_TEMP(nr)           (nr)
 #define ADM1021_REG_STATUS             0x02
-#define ADM1021_REG_MAN_ID             0x0FE   /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/
-#define ADM1021_REG_DEV_ID             0x0FF   /* ADM1021 = 0x0X, ADM1023 = 0x3X */
-#define ADM1021_REG_DIE_CODE           0x0FF   /* MAX1617A */
+/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
+#define ADM1021_REG_MAN_ID             0xFE
+/* ADM1021 = 0x0X, ADM1023 = 0x3X */
+#define ADM1021_REG_DEV_ID             0xFF
 /* These use different addresses for reading/writing */
 #define ADM1021_REG_CONFIG_R           0x03
 #define ADM1021_REG_CONFIG_W           0x09
 #define ADM1021_REG_CONV_RATE_R                0x04
 #define ADM1021_REG_CONV_RATE_W                0x0A
 /* These are for the ADM1023's additional precision on the remote temp sensor */
-#define ADM1021_REG_REM_TEMP_PREC      0x010
-#define ADM1021_REG_REM_OFFSET         0x011
-#define ADM1021_REG_REM_OFFSET_PREC    0x012
-#define ADM1021_REG_REM_TOS_PREC       0x013
-#define ADM1021_REG_REM_THYST_PREC     0x014
+#define ADM1023_REG_REM_TEMP_PREC      0x10
+#define ADM1023_REG_REM_OFFSET         0x11
+#define ADM1023_REG_REM_OFFSET_PREC    0x12
+#define ADM1023_REG_REM_TOS_PREC       0x13
+#define ADM1023_REG_REM_THYST_PREC     0x14
 /* limits */
-#define ADM1021_REG_TOS_R              0x05
-#define ADM1021_REG_TOS_W              0x0B
-#define ADM1021_REG_REMOTE_TOS_R       0x07
-#define ADM1021_REG_REMOTE_TOS_W       0x0D
-#define ADM1021_REG_THYST_R            0x06
-#define ADM1021_REG_THYST_W            0x0C
-#define ADM1021_REG_REMOTE_THYST_R     0x08
-#define ADM1021_REG_REMOTE_THYST_W     0x0E
+/* For nr in 0-1 */
+#define ADM1021_REG_TOS_R(nr)          (0x05 + 2 * (nr))
+#define ADM1021_REG_TOS_W(nr)          (0x0B + 2 * (nr))
+#define ADM1021_REG_THYST_R(nr)                (0x06 + 2 * (nr))
+#define ADM1021_REG_THYST_W(nr)                (0x0C + 2 * (nr))
 /* write-only */
 #define ADM1021_REG_ONESHOT            0x0F
 
-
-/* Conversions. Rounding and limit checking is only done on the TO_REG
-   variants. Note that you should be a bit careful with which arguments
-   these macros are called: arguments may be evaluated more than once.
-   Fixing this is just not worth it. */
-/* Conversions  note: 1021 uses normal integer signed-byte format*/
-#define TEMP_FROM_REG(val)     (val > 127 ? (val-256)*1000 : val*1000)
-#define TEMP_TO_REG(val)       (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255))
-
 /* Initial values */
 
-/* Note: Even though I left the low and high limits named os and hyst, 
-they don't quite work like a thermostat the way the LM75 does.  I.e., 
-a lower temp than THYST actually triggers an alarm instead of 
+/* Note: Even though I left the low and high limits named os and hyst,
+they don't quite work like a thermostat the way the LM75 does.  I.e.,
+a lower temp than THYST actually triggers an alarm instead of
 clearing it.  Weird, ey?   --Phil  */
 
 /* Each client has this additional data */
 struct adm1021_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        enum chips type;
 
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
 
-       u8      temp_max;       /* Register values */
-       u8      temp_hyst;
-       u8      temp_input;
-       u8      remote_temp_max;
-       u8      remote_temp_hyst;
-       u8      remote_temp_input;
-       u8      alarms;
-        /* Special values for ADM1023 only */
-       u8      remote_temp_prec;
-       u8      remote_temp_os_prec;
-       u8      remote_temp_hyst_prec;
-       u8      remote_temp_offset;
-       u8      remote_temp_offset_prec;
+       s8 temp_max[2];         /* Register values */
+       s8 temp_min[2];
+       s8 temp[2];
+       u8 alarms;
+       /* Special values for ADM1023 only */
+       u8 remote_temp_prec;
+       u8 remote_temp_os_prec;
+       u8 remote_temp_hyst_prec;
+       u8 remote_temp_offset;
+       u8 remote_temp_offset_prec;
 };
 
 static int adm1021_attach_adapter(struct i2c_adapter *adapter);
 static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind);
 static void adm1021_init_client(struct i2c_client *client);
 static int adm1021_detach_client(struct i2c_client *client);
-static int adm1021_read_value(struct i2c_client *client, u8 reg);
-static int adm1021_write_value(struct i2c_client *client, u8 reg,
-                              u16 value);
 static struct adm1021_data *adm1021_update_device(struct device *dev);
 
 /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
@@ -135,53 +120,104 @@ static struct i2c_driver adm1021_driver = {
        .detach_client  = adm1021_detach_client,
 };
 
-#define show(value)    \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)              \
-{                                                                      \
-       struct adm1021_data *data = adm1021_update_device(dev);         \
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value));        \
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct adm1021_data *data = adm1021_update_device(dev);
+
+       return sprintf(buf, "%d\n", 1000 * data->temp[index]);
 }
-show(temp_max);
-show(temp_hyst);
-show(temp_input);
-show(remote_temp_max);
-show(remote_temp_hyst);
-show(remote_temp_input);
-
-#define show2(value)   \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)              \
-{                                                                      \
-       struct adm1021_data *data = adm1021_update_device(dev);         \
-       return sprintf(buf, "%d\n", data->value);                       \
+
+static ssize_t show_temp_max(struct device *dev,
+                            struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct adm1021_data *data = adm1021_update_device(dev);
+
+       return sprintf(buf, "%d\n", 1000 * data->temp_max[index]);
 }
-show2(alarms);
-
-#define set(value, reg)        \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)   \
-{                                                              \
-       struct i2c_client *client = to_i2c_client(dev);         \
-       struct adm1021_data *data = i2c_get_clientdata(client); \
-       int temp = simple_strtoul(buf, NULL, 10);               \
-                                                               \
-       mutex_lock(&data->update_lock);                         \
-       data->value = TEMP_TO_REG(temp);                        \
-       adm1021_write_value(client, reg, data->value);          \
-       mutex_unlock(&data->update_lock);                       \
-       return count;                                           \
+
+static ssize_t show_temp_min(struct device *dev,
+                            struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct adm1021_data *data = adm1021_update_device(dev);
+
+       return sprintf(buf, "%d\n", 1000 * data->temp_min[index]);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int index = to_sensor_dev_attr(attr)->index;
+       struct adm1021_data *data = adm1021_update_device(dev);
+       return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
+static ssize_t show_alarms(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct adm1021_data *data = adm1021_update_device(dev);
+       return sprintf(buf, "%u\n", data->alarms);
 }
-set(temp_max, ADM1021_REG_TOS_W);
-set(temp_hyst, ADM1021_REG_THYST_W);
-set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W);
-set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W);
-
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL);
-static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t set_temp_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1021_data *data = i2c_get_clientdata(client);
+       long temp = simple_strtol(buf, NULL, 10) / 1000;
+
+       mutex_lock(&data->update_lock);
+       data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
+       if (!read_only)
+               i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
+                                         data->temp_max[index]);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t set_temp_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1021_data *data = i2c_get_clientdata(client);
+       long temp = simple_strtol(buf, NULL, 10) / 1000;
+
+       mutex_lock(&data->update_lock);
+       data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
+       if (!read_only)
+               i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
+                                         data->temp_min[index]);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+                         set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+                         set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+                         set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+                         set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
 static int adm1021_attach_adapter(struct i2c_adapter *adapter)
 {
@@ -191,12 +227,17 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
 }
 
 static struct attribute *adm1021_attributes[] = {
-       &dev_attr_temp1_max.attr,
-       &dev_attr_temp1_min.attr,
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp2_max.attr,
-       &dev_attr_temp2_min.attr,
-       &dev_attr_temp2_input.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &dev_attr_alarms.attr,
        NULL
 };
@@ -208,35 +249,44 @@ static const struct attribute_group adm1021_group = {
 static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
 {
        int i;
-       struct i2c_client *new_client;
+       struct i2c_client *client;
        struct adm1021_data *data;
        int err = 0;
        const char *type_name = "";
+       int conv_rate, status, config;
 
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               pr_debug("adm1021: detect failed, "
+                        "smbus byte data not supported!\n");
                goto error0;
+       }
 
        /* OK. For now, we presume we have a valid client. We now create the
           client structure, even though we cannot fill it completely yet.
-          But it allows us to access adm1021_{read,write}_value. */
+          But it allows us to access adm1021 register values. */
 
        if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) {
+               pr_debug("adm1021: detect failed, kzalloc failed!\n");
                err = -ENOMEM;
                goto error0;
        }
 
-       new_client = &data->client;
-       i2c_set_clientdata(new_client, data);
-       new_client->addr = address;
-       new_client->adapter = adapter;
-       new_client->driver = &adm1021_driver;
-       new_client->flags = 0;
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &adm1021_driver;
+       status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
+       conv_rate = i2c_smbus_read_byte_data(client,
+                                            ADM1021_REG_CONV_RATE_R);
+       config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
 
        /* Now, we do the remaining detection. */
        if (kind < 0) {
-               if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00
-                || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00
-                || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) {
+               if ((status & 0x03) != 0x00 || (config & 0x3F) != 0x00
+                   || (conv_rate & 0xF8) != 0x00) {
+                       pr_debug("adm1021: detect failed, "
+                                "chip not detected!\n");
                        err = -ENODEV;
                        goto error1;
                }
@@ -244,9 +294,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
 
        /* Determine the chip type. */
        if (kind <= 0) {
-               i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID);
+               i = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
                if (i == 0x41)
-                       if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030)
+                       if ((i2c_smbus_read_byte_data(client,
+                                       ADM1021_REG_DEV_ID) & 0xF0) == 0x30)
                                kind = adm1023;
                        else
                                kind = adm1021;
@@ -255,15 +306,16 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
                else if (i == 0x23)
                        kind = gl523sm;
                else if ((i == 0x4d) &&
-                        (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01))
+                        (i2c_smbus_read_byte_data(client,
+                                                  ADM1021_REG_DEV_ID) == 0x01))
                        kind = max1617a;
                else if (i == 0x54)
                        kind = mc1066;
                /* LM84 Mfr ID in a different place, and it has more unused bits */
-               else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00
-                     && (kind == 0 /* skip extra detection */
-                      || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00
-                       && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00)))
+               else if (conv_rate == 0x00
+                        && (kind == 0 /* skip extra detection */
+                            || ((config & 0x7F) == 0x00
+                                && (status & 0xAB) == 0x00)))
                        kind = lm84;
                else
                        kind = max1617;
@@ -286,37 +338,38 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
        } else if (kind == mc1066) {
                type_name = "mc1066";
        }
+       pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
+                type_name, i2c_adapter_id(adapter), address);
 
-       /* Fill in the remaining client fields and put it into the global list */
-       strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
+       /* Fill in the remaining client fields */
+       strlcpy(client->name, type_name, I2C_NAME_SIZE);
        data->type = kind;
-       data->valid = 0;
        mutex_init(&data->update_lock);
 
        /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(new_client)))
+       if ((err = i2c_attach_client(client)))
                goto error1;
 
        /* Initialize the ADM1021 chip */
-       if (kind != lm84)
-               adm1021_init_client(new_client);
+       if (kind != lm84 && !read_only)
+               adm1021_init_client(client);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
+       if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
                goto error2;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto error3;
        }
 
        return 0;
 
 error3:
-       sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
+       sysfs_remove_group(&client->dev.kobj, &adm1021_group);
 error2:
-       i2c_detach_client(new_client);
+       i2c_detach_client(client);
 error1:
        kfree(data);
 error0:
@@ -326,10 +379,10 @@ error0:
 static void adm1021_init_client(struct i2c_client *client)
 {
        /* Enable ADC and disable suspend mode */
-       adm1021_write_value(client, ADM1021_REG_CONFIG_W,
-               adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF);
+       i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
+               i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
        /* Set Conversion rate to 1/sec (this can be tinkered with) */
-       adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04);
+       i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
 }
 
 static int adm1021_detach_client(struct i2c_client *client)
@@ -337,7 +390,7 @@ static int adm1021_detach_client(struct i2c_client *client)
        struct adm1021_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adm1021_group);
 
        if ((err = i2c_detach_client(client)))
@@ -347,19 +400,6 @@ static int adm1021_detach_client(struct i2c_client *client)
        return 0;
 }
 
-/* All registers are byte-sized */
-static int adm1021_read_value(struct i2c_client *client, u8 reg)
-{
-       return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value)
-{
-       if (!read_only)
-               return i2c_smbus_write_byte_data(client, reg, value);
-       return 0;
-}
-
 static struct adm1021_data *adm1021_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -369,21 +409,36 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
 
        if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
            || !data->valid) {
+               int i;
+
                dev_dbg(&client->dev, "Starting adm1021 update\n");
 
-               data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP);
-               data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R);
-               data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R);
-               data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP);
-               data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
-               data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
-               data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
+               for (i = 0; i < 2; i++) {
+                       data->temp[i] = i2c_smbus_read_byte_data(client,
+                                               ADM1021_REG_TEMP(i));
+                       data->temp_max[i] = i2c_smbus_read_byte_data(client,
+                                               ADM1021_REG_TOS_R(i));
+                       data->temp_min[i] = i2c_smbus_read_byte_data(client,
+                                               ADM1021_REG_THYST_R(i));
+               }
+               data->alarms = i2c_smbus_read_byte_data(client,
+                                               ADM1021_REG_STATUS) & 0x7c;
                if (data->type == adm1023) {
-                       data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC);
-                       data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC);
-                       data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC);
-                       data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET);
-                       data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC);
+                       data->remote_temp_prec =
+                               i2c_smbus_read_byte_data(client,
+                                               ADM1023_REG_REM_TEMP_PREC);
+                       data->remote_temp_os_prec =
+                               i2c_smbus_read_byte_data(client,
+                                               ADM1023_REG_REM_TOS_PREC);
+                       data->remote_temp_hyst_prec =
+                               i2c_smbus_read_byte_data(client,
+                                               ADM1023_REG_REM_THYST_PREC);
+                       data->remote_temp_offset =
+                               i2c_smbus_read_byte_data(client,
+                                               ADM1023_REG_REM_OFFSET);
+                       data->remote_temp_offset_prec =
+                               i2c_smbus_read_byte_data(client,
+                                               ADM1023_REG_REM_OFFSET_PREC);
                }
                data->last_updated = jiffies;
                data->valid = 1;
index 8c562885b54b031fe03746322b188a5566366d12..041ecb0bdf484d08b4accbfe26e8df8050a95f4d 100644 (file)
@@ -133,7 +133,7 @@ static struct i2c_driver adm1025_driver = {
 
 struct adm1025_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -292,7 +292,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 
 static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct adm1025_data *data = adm1025_update_device(dev);
+       struct adm1025_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%u\n", data->vrm);
 }
 static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -472,9 +472,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
                        goto exit_remove;
        }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -538,7 +538,7 @@ static int adm1025_detach_client(struct i2c_client *client)
        struct adm1025_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adm1025_group);
        sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
 
index ba80cd3258c69fe63f0277726cf37bec2f653f0f..aa875ca50d9bc1282771fe180907d6555d424c6b 100644 (file)
@@ -260,7 +260,7 @@ struct pwm_data {
 
 struct adm1026_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        enum chips type;
 
        struct mutex update_lock;
@@ -1221,7 +1221,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 
 static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct adm1026_data *data = adm1026_update_device(dev);
+       struct adm1026_data *data = dev_get_drvdata(dev);
        return sprintf(buf,"%d\n", data->vrm);
 }
 static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
@@ -1676,9 +1676,9 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
        if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
                goto exitdetach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exitremove;
        }
 
@@ -1698,7 +1698,7 @@ exit:
 static int adm1026_detach_client(struct i2c_client *client)
 {
        struct adm1026_data *data = i2c_get_clientdata(client);
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adm1026_group);
        i2c_detach_client(client);
        kfree(data);
index 73ce31b31511690855d4110d9bf0a5835324b34e..0bc897dffa2790af7d6e606ece8c125ac7ca838f 100644 (file)
@@ -141,7 +141,7 @@ static struct i2c_driver adm1029_driver = {
 
 struct adm1029_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;             /* zero until following fields are valid */
        unsigned long last_updated;     /* in jiffies */
@@ -391,9 +391,9 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -431,7 +431,7 @@ static int adm1029_detach_client(struct i2c_client *client)
        struct adm1029_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adm1029_group);
 
        if ((err = i2c_detach_client(client)))
index 122683fc91d096f271e3a372f17b5c8d51bfd2cb..37cfc101da5e9e10532173b0ea1a3fb2cee5625d 100644 (file)
@@ -70,7 +70,7 @@ typedef u8 auto_chan_table_t[8][2];
 /* Each client has this additional data */
 struct adm1031_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        int chip_type;
        char valid;             /* !=0 if following fields are valid */
@@ -853,9 +853,9 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
                        goto exit_remove;
        }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -877,7 +877,7 @@ static int adm1031_detach_client(struct i2c_client *client)
        struct adm1031_data *data = i2c_get_clientdata(client);
        int ret;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adm1031_group);
        sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
        if ((ret = i2c_detach_client(client)) != 0) {
index aad594adf0c726ab220967562ae89d99e5c0937d..c17d0b6b3283f306677b9107c711b2e02574ce69 100644 (file)
@@ -150,7 +150,7 @@ static struct i2c_driver adm9240_driver = {
 struct adm9240_data {
        enum chips type;
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;
        unsigned long last_updated_measure;
@@ -590,9 +590,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -620,7 +620,7 @@ static int adm9240_detach_client(struct i2c_client *client)
        struct adm9240_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adm9240_group);
 
        if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
new file mode 100644 (file)
index 0000000..9810aaa
--- /dev/null
@@ -0,0 +1,1050 @@
+/*
+ * A hwmon driver for the Analog Devices ADT7470
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(adt7470);
+
+/* ADT7470 registers */
+#define ADT7470_REG_BASE_ADDR                  0x20
+#define ADT7470_REG_TEMP_BASE_ADDR             0x20
+#define ADT7470_REG_TEMP_MAX_ADDR              0x29
+#define ADT7470_REG_FAN_BASE_ADDR              0x2A
+#define ADT7470_REG_FAN_MAX_ADDR               0x31
+#define ADT7470_REG_PWM_BASE_ADDR              0x32
+#define ADT7470_REG_PWM_MAX_ADDR               0x35
+#define ADT7470_REG_PWM_MAX_BASE_ADDR          0x38
+#define ADT7470_REG_PWM_MAX_MAX_ADDR           0x3B
+#define ADT7470_REG_CFG                                0x40
+#define                ADT7470_FSPD_MASK               0x04
+#define ADT7470_REG_ALARM1                     0x41
+#define ADT7470_REG_ALARM2                     0x42
+#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR      0x44
+#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR       0x57
+#define ADT7470_REG_FAN_MIN_BASE_ADDR          0x58
+#define ADT7470_REG_FAN_MIN_MAX_ADDR           0x5F
+#define ADT7470_REG_FAN_MAX_BASE_ADDR          0x60
+#define ADT7470_REG_FAN_MAX_MAX_ADDR           0x67
+#define ADT7470_REG_PWM_CFG_BASE_ADDR          0x68
+#define ADT7470_REG_PWM12_CFG                  0x68
+#define                ADT7470_PWM2_AUTO_MASK          0x40
+#define                ADT7470_PWM1_AUTO_MASK          0x80
+#define ADT7470_REG_PWM34_CFG                  0x69
+#define                ADT7470_PWM3_AUTO_MASK          0x40
+#define                ADT7470_PWM4_AUTO_MASK          0x80
+#define        ADT7470_REG_PWM_MIN_BASE_ADDR           0x6A
+#define ADT7470_REG_PWM_MIN_MAX_ADDR           0x6D
+#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR     0x6E
+#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR      0x71
+#define ADT7470_REG_ACOUSTICS12                        0x75
+#define ADT7470_REG_ACOUSTICS34                        0x76
+#define ADT7470_REG_DEVICE                     0x3D
+#define ADT7470_REG_VENDOR                     0x3E
+#define ADT7470_REG_REVISION                   0x3F
+#define ADT7470_REG_ALARM1_MASK                        0x72
+#define ADT7470_REG_ALARM2_MASK                        0x73
+#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR    0x7C
+#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR     0x7D
+#define ADT7470_REG_MAX_ADDR                   0x81
+
+#define ADT7470_TEMP_COUNT     10
+#define ADT7470_TEMP_REG(x)    (ADT7470_REG_TEMP_BASE_ADDR + (x))
+#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
+#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \
+                               ((x) * 2) + 1)
+
+#define ADT7470_FAN_COUNT      4
+#define ADT7470_REG_FAN(x)     (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2))
+
+#define ADT7470_PWM_COUNT      4
+#define ADT7470_REG_PWM(x)     (ADT7470_REG_PWM_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_TMIN(x)        (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2))
+#define ADT7470_REG_PWM_AUTO_TEMP(x)   (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \
+                                       ((x) / 2))
+
+#define ADT7470_VENDOR         0x41
+#define ADT7470_DEVICE         0x70
+/* datasheet only mentions a revision 2 */
+#define ADT7470_REVISION       0x02
+
+/* "all temps" according to hwmon sysfs interface spec */
+#define ADT7470_PWM_ALL_TEMPS  0x3FF
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL        (5 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL (60 * HZ)
+
+/* sleep 1s while gathering temperature data */
+#define TEMP_COLLECTION_TIME   1000
+
+#define power_of_2(x)  (((x) & ((x) - 1)) == 0)
+
+/* datasheet says to divide this number by the fan reading to get fan rpm */
+#define FAN_PERIOD_TO_RPM(x)   ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD      FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID     65535
+#define FAN_DATA_VALID(x)      ((x) && (x) != FAN_PERIOD_INVALID)
+
+struct adt7470_data {
+       struct i2c_client       client;
+       struct device           *hwmon_dev;
+       struct attribute_group  attrs;
+       struct mutex            lock;
+       char                    sensors_valid;
+       char                    limits_valid;
+       unsigned long           sensors_last_updated;   /* In jiffies */
+       unsigned long           limits_last_updated;    /* In jiffies */
+
+       s8                      temp[ADT7470_TEMP_COUNT];
+       s8                      temp_min[ADT7470_TEMP_COUNT];
+       s8                      temp_max[ADT7470_TEMP_COUNT];
+       u16                     fan[ADT7470_FAN_COUNT];
+       u16                     fan_min[ADT7470_FAN_COUNT];
+       u16                     fan_max[ADT7470_FAN_COUNT];
+       u16                     alarms, alarms_mask;
+       u8                      force_pwm_max;
+       u8                      pwm[ADT7470_PWM_COUNT];
+       u8                      pwm_max[ADT7470_PWM_COUNT];
+       u8                      pwm_automatic[ADT7470_PWM_COUNT];
+       u8                      pwm_min[ADT7470_PWM_COUNT];
+       s8                      pwm_tmin[ADT7470_PWM_COUNT];
+       u8                      pwm_auto_temp[ADT7470_PWM_COUNT];
+};
+
+static int adt7470_attach_adapter(struct i2c_adapter *adapter);
+static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adt7470_detach_client(struct i2c_client *client);
+
+static struct i2c_driver adt7470_driver = {
+       .driver = {
+               .name   = "adt7470",
+       },
+       .attach_adapter = adt7470_attach_adapter,
+       .detach_client  = adt7470_detach_client,
+};
+
+/*
+ * 16-bit registers on the ADT7470 are low-byte first.  The data sheet says
+ * that the low byte must be read before the high byte.
+ */
+static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg)
+{
+       u16 foo;
+       foo = i2c_smbus_read_byte_data(client, reg);
+       foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
+       return foo;
+}
+
+static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
+                                         u16 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
+              && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+}
+
+static void adt7470_init_client(struct i2c_client *client)
+{
+       int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+
+       if (reg < 0) {
+               dev_err(&client->dev, "cannot read configuration register\n");
+       } else {
+               /* start monitoring (and do a self-test) */
+               i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3);
+       }
+}
+
+static struct adt7470_data *adt7470_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       unsigned long local_jiffies = jiffies;
+       u8 cfg;
+       int i;
+
+       mutex_lock(&data->lock);
+       if (time_before(local_jiffies, data->sensors_last_updated +
+               SENSOR_REFRESH_INTERVAL)
+               && data->sensors_valid)
+               goto no_sensor_update;
+
+       /* start reading temperature sensors */
+       cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+       cfg |= 0x80;
+       i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+       /*
+        * Delay is 200ms * number of tmp05 sensors.  Too bad
+        * there's no way to figure out how many are connected.
+        * For now, assume 1s will work.
+        */
+       msleep(TEMP_COLLECTION_TIME);
+
+       /* done reading temperature sensors */
+       cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+       cfg &= ~0x80;
+       i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+       for (i = 0; i < ADT7470_TEMP_COUNT; i++)
+               data->temp[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7470_TEMP_REG(i));
+
+       for (i = 0; i < ADT7470_FAN_COUNT; i++)
+               data->fan[i] = adt7470_read_word_data(client,
+                                               ADT7470_REG_FAN(i));
+
+       for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+               int reg;
+               int reg_mask;
+
+               data->pwm[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7470_REG_PWM(i));
+
+               if (i % 2)
+                       reg_mask = ADT7470_PWM2_AUTO_MASK;
+               else
+                       reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+               reg = ADT7470_REG_PWM_CFG(i);
+               if (i2c_smbus_read_byte_data(client, reg) & reg_mask)
+                       data->pwm_automatic[i] = 1;
+               else
+                       data->pwm_automatic[i] = 0;
+
+               reg = ADT7470_REG_PWM_AUTO_TEMP(i);
+               cfg = i2c_smbus_read_byte_data(client, reg);
+               if (!(i % 2))
+                       data->pwm_auto_temp[i] = cfg >> 4;
+               else
+                       data->pwm_auto_temp[i] = cfg & 0xF;
+       }
+
+       if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) &
+           ADT7470_FSPD_MASK)
+               data->force_pwm_max = 1;
+       else
+               data->force_pwm_max = 0;
+
+       data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1);
+       data->alarms_mask = adt7470_read_word_data(client,
+                                                  ADT7470_REG_ALARM1_MASK);
+
+       data->sensors_last_updated = local_jiffies;
+       data->sensors_valid = 1;
+
+no_sensor_update:
+       if (time_before(local_jiffies, data->limits_last_updated +
+               LIMIT_REFRESH_INTERVAL)
+               && data->limits_valid)
+               goto out;
+
+       for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
+               data->temp_min[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7470_TEMP_MIN_REG(i));
+               data->temp_max[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7470_TEMP_MAX_REG(i));
+       }
+
+       for (i = 0; i < ADT7470_FAN_COUNT; i++) {
+               data->fan_min[i] = adt7470_read_word_data(client,
+                                               ADT7470_REG_FAN_MIN(i));
+               data->fan_max[i] = adt7470_read_word_data(client,
+                                               ADT7470_REG_FAN_MAX(i));
+       }
+
+       for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+               data->pwm_max[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7470_REG_PWM_MAX(i));
+               data->pwm_min[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7470_REG_PWM_MIN(i));
+               data->pwm_tmin[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7470_REG_PWM_TMIN(i));
+       }
+
+       data->limits_last_updated = local_jiffies;
+       data->limits_valid = 1;
+
+out:
+       mutex_unlock(&data->lock);
+       return data;
+}
+
+static ssize_t show_temp_min(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
+}
+
+static ssize_t set_temp_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+       mutex_lock(&data->lock);
+       data->temp_min[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_temp_max(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+       mutex_lock(&data->lock);
+       data->temp_max[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
+}
+
+static ssize_t show_alarms(struct device *dev,
+                          struct device_attribute *devattr,
+                          char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+
+       if (attr->index)
+               return sprintf(buf, "%x\n", data->alarms);
+       else
+               return sprintf(buf, "%x\n", data->alarms_mask);
+}
+
+static ssize_t show_fan_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+
+       if (FAN_DATA_VALID(data->fan_max[attr->index]))
+               return sprintf(buf, "%d\n",
+                              FAN_PERIOD_TO_RPM(data->fan_max[attr->index]));
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_max(struct device *dev,
+                          struct device_attribute *devattr,
+                          const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10);
+
+       if (!temp)
+               return -EINVAL;
+       temp = FAN_RPM_TO_PERIOD(temp);
+
+       mutex_lock(&data->lock);
+       data->fan_max[attr->index] = temp;
+       adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_fan_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+
+       if (FAN_DATA_VALID(data->fan_min[attr->index]))
+               return sprintf(buf, "%d\n",
+                              FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_min(struct device *dev,
+                          struct device_attribute *devattr,
+                          const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10);
+
+       if (!temp)
+               return -EINVAL;
+       temp = FAN_RPM_TO_PERIOD(temp);
+
+       mutex_lock(&data->lock);
+       data->fan_min[attr->index] = temp;
+       adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+                       char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+
+       if (FAN_DATA_VALID(data->fan[attr->index]))
+               return sprintf(buf, "%d\n",
+                              FAN_PERIOD_TO_RPM(data->fan[attr->index]));
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_force_pwm_max(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", data->force_pwm_max);
+}
+
+static ssize_t set_force_pwm_max(struct device *dev,
+                                struct device_attribute *devattr,
+                                const char *buf,
+                                size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10);
+       u8 reg;
+
+       mutex_lock(&data->lock);
+       data->force_pwm_max = temp;
+       reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+       if (temp)
+               reg |= ADT7470_FSPD_MASK;
+       else
+               reg &= ~ADT7470_FSPD_MASK;
+       i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+                       char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm[attr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->lock);
+       data->pwm[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
+}
+
+static ssize_t set_pwm_max(struct device *dev,
+                          struct device_attribute *devattr,
+                          const char *buf,
+                          size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->lock);
+       data->pwm_max[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
+}
+
+static ssize_t set_pwm_min(struct device *dev,
+                          struct device_attribute *devattr,
+                          const char *buf,
+                          size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->lock);
+       data->pwm_min[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_tmax(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       /* the datasheet says that tmax = tmin + 20C */
+       return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
+}
+
+static ssize_t show_pwm_tmin(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
+}
+
+static ssize_t set_pwm_tmin(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+       mutex_lock(&data->lock);
+       data->pwm_tmin[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_auto(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
+}
+
+static ssize_t set_pwm_auto(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = simple_strtol(buf, NULL, 10);
+       int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
+       int pwm_auto_reg_mask;
+       u8 reg;
+
+       if (attr->index % 2)
+               pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
+       else
+               pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+       if (temp != 2 && temp != 1)
+               return -EINVAL;
+       temp--;
+
+       mutex_lock(&data->lock);
+       data->pwm_automatic[attr->index] = temp;
+       reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+       if (temp)
+               reg |= pwm_auto_reg_mask;
+       else
+               reg &= ~pwm_auto_reg_mask;
+       i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_auto_temp(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7470_data *data = adt7470_update_device(dev);
+       u8 ctrl = data->pwm_auto_temp[attr->index];
+
+       if (ctrl)
+               return sprintf(buf, "%d\n", 1 << (ctrl - 1));
+       else
+               return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS);
+}
+
+static int cvt_auto_temp(int input)
+{
+       if (input == ADT7470_PWM_ALL_TEMPS)
+               return 0;
+       if (input < 1 || !power_of_2(input))
+               return -EINVAL;
+       return ilog2(input) + 1;
+}
+
+static ssize_t set_pwm_auto_temp(struct device *dev,
+                                struct device_attribute *devattr,
+                                const char *buf,
+                                size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7470_data *data = i2c_get_clientdata(client);
+       int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10));
+       int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
+       u8 reg;
+
+       if (temp < 0)
+               return temp;
+
+       mutex_lock(&data->lock);
+       data->pwm_automatic[attr->index] = temp;
+       reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+
+       if (!(attr->index % 2)) {
+               reg &= 0xF;
+               reg |= (temp << 4) & 0xF0;
+       } else {
+               reg &= 0xF0;
+               reg |= temp & 0xF;
+       }
+
+       i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0);
+static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 4);
+static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 5);
+static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 6);
+static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 7);
+static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 8);
+static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 4);
+static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 5);
+static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 6);
+static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 7);
+static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 8);
+static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9);
+
+static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max,
+                   set_fan_max, 0);
+static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max,
+                   set_fan_max, 1);
+static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max,
+                   set_fan_max, 2);
+static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max,
+                   set_fan_max, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
+                   show_force_pwm_max, set_force_pwm_max, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+                   NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+                   NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+                   NULL, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+                   NULL, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 3);
+
+static struct attribute *adt7470_attr[] =
+{
+       &sensor_dev_attr_alarms.dev_attr.attr,
+       &sensor_dev_attr_alarm_mask.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp6_max.dev_attr.attr,
+       &sensor_dev_attr_temp7_max.dev_attr.attr,
+       &sensor_dev_attr_temp8_max.dev_attr.attr,
+       &sensor_dev_attr_temp9_max.dev_attr.attr,
+       &sensor_dev_attr_temp10_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp4_min.dev_attr.attr,
+       &sensor_dev_attr_temp5_min.dev_attr.attr,
+       &sensor_dev_attr_temp6_min.dev_attr.attr,
+       &sensor_dev_attr_temp7_min.dev_attr.attr,
+       &sensor_dev_attr_temp8_min.dev_attr.attr,
+       &sensor_dev_attr_temp9_min.dev_attr.attr,
+       &sensor_dev_attr_temp10_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+       &sensor_dev_attr_temp6_input.dev_attr.attr,
+       &sensor_dev_attr_temp7_input.dev_attr.attr,
+       &sensor_dev_attr_temp8_input.dev_attr.attr,
+       &sensor_dev_attr_temp9_input.dev_attr.attr,
+       &sensor_dev_attr_temp10_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_max.dev_attr.attr,
+       &sensor_dev_attr_fan2_max.dev_attr.attr,
+       &sensor_dev_attr_fan3_max.dev_attr.attr,
+       &sensor_dev_attr_fan4_max.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_force_pwm_max.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm3.dev_attr.attr,
+       &sensor_dev_attr_pwm4.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
+       NULL
+};
+
+static int adt7470_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_probe(adapter, &addr_data, adt7470_detect);
+}
+
+static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       struct adt7470_data *data;
+       int err = 0;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               goto exit;
+
+       if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       client = &data->client;
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &adt7470_driver;
+
+       i2c_set_clientdata(client, data);
+
+       mutex_init(&data->lock);
+
+       if (kind <= 0) {
+               int vendor, device, revision;
+
+               vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
+               if (vendor != ADT7470_VENDOR) {
+                       err = -ENODEV;
+                       goto exit_free;
+               }
+
+               device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
+               if (device != ADT7470_DEVICE) {
+                       err = -ENODEV;
+                       goto exit_free;
+               }
+
+               revision = i2c_smbus_read_byte_data(client,
+                                                   ADT7470_REG_REVISION);
+               if (revision != ADT7470_REVISION) {
+                       err = -ENODEV;
+                       goto exit_free;
+               }
+       } else
+               dev_dbg(&adapter->dev, "detection forced\n");
+
+       strlcpy(client->name, "adt7470", I2C_NAME_SIZE);
+
+       if ((err = i2c_attach_client(client)))
+               goto exit_free;
+
+       dev_info(&client->dev, "%s chip found\n", client->name);
+
+       /* Initialize the ADT7470 chip */
+       adt7470_init_client(client);
+
+       /* Register sysfs hooks */
+       data->attrs.attrs = adt7470_attr;
+       if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
+               goto exit_detach;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+exit_remove:
+       sysfs_remove_group(&client->dev.kobj, &data->attrs);
+exit_detach:
+       i2c_detach_client(client);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int adt7470_detach_client(struct i2c_client *client)
+{
+       struct adt7470_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &data->attrs);
+       i2c_detach_client(client);
+       kfree(data);
+       return 0;
+}
+
+static int __init adt7470_init(void)
+{
+       return i2c_add_driver(&adt7470_driver);
+}
+
+static void __exit adt7470_exit(void)
+{
+       i2c_del_driver(&adt7470_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("ADT7470 driver");
+MODULE_LICENSE("GPL");
+
+module_init(adt7470_init);
+module_exit(adt7470_exit);
index 571f49e80277326fd0f76c367bdb03f778399499..4879125b4cdc1963534928181aed8088a30f3900 100644 (file)
@@ -125,8 +125,8 @@ static const int debug;
 static struct platform_device *pdev;
 static s16 rest_x;
 static s16 rest_y;
+static struct device *hwmon_dev;
 static struct input_polled_dev *applesmc_idev;
-static struct class_device *hwmon_class_dev;
 
 /* Indicates whether this computer has an accelerometer. */
 static unsigned int applesmc_accelerometer;
@@ -1264,9 +1264,9 @@ static int __init applesmc_init(void)
                        goto out_light_wq;
        }
 
-       hwmon_class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(hwmon_class_dev)) {
-               ret = PTR_ERR(hwmon_class_dev);
+       hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(hwmon_dev)) {
+               ret = PTR_ERR(hwmon_dev);
                goto out_light_ledclass;
        }
 
@@ -1308,7 +1308,7 @@ out:
 
 static void __exit applesmc_exit(void)
 {
-       hwmon_device_unregister(hwmon_class_dev);
+       hwmon_device_unregister(hwmon_dev);
        if (applesmc_light) {
                led_classdev_unregister(&applesmc_backlight);
                destroy_workqueue(applesmc_led_wq);
index 57b1c7b7ac3f5d54601e799a3b0e5f3aaac50708..9460dba4cf74ff0bd0dbc1575f516d89d34c7d9d 100644 (file)
@@ -143,7 +143,7 @@ static int FAN_FROM_REG(u8 val, int div)
 
 /* TEMP: 0.001C/bit (-128C to +127C)
    REG: 1C/bit, two's complement */
-static u8 TEMP_TO_REG(int temp)
+static u8 TEMP_TO_REG(long temp)
 {
        int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
        ntemp += (ntemp<0 ? -500 : 500);
@@ -182,7 +182,7 @@ static u8 DIV_TO_REG(long val)
    dynamically allocated, at the same time the client itself is allocated. */
 struct asb100_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
        enum chips type;
 
@@ -448,7 +448,7 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \
 { \
        struct i2c_client *client = to_i2c_client(dev); \
        struct asb100_data *data = i2c_get_clientdata(client); \
-       unsigned long val = simple_strtoul(buf, NULL, 10); \
+       long val = simple_strtol(buf, NULL, 10); \
  \
        mutex_lock(&data->update_lock); \
        switch (nr) { \
@@ -514,7 +514,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 /* VRM */
 static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct asb100_data *data = asb100_update_device(dev);
+       struct asb100_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", data->vrm);
 }
 
@@ -844,9 +844,9 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
                goto ERROR3;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto ERROR4;
        }
 
@@ -874,7 +874,7 @@ static int asb100_detach_client(struct i2c_client *client)
 
        /* main client */
        if (data) {
-               hwmon_device_unregister(data->class_dev);
+               hwmon_device_unregister(data->hwmon_dev);
                sysfs_remove_group(&client->dev.kobj, &asb100_group);
        }
 
index 0ccdd0750c44c47968097b5422e6190c7317a2f8..cce3350e539ef68509410b246a1dd3b387698c76 100644 (file)
@@ -61,7 +61,7 @@ static struct i2c_driver atxp1_driver = {
 
 struct atxp1_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        unsigned long last_updated;
        u8 valid;
@@ -335,9 +335,9 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -361,7 +361,7 @@ static int atxp1_detach_client(struct i2c_client * client)
        struct atxp1_data * data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &atxp1_group);
 
        err = i2c_detach_client(client);
index 7c1795225b06587def9fae2bd370641ff29a5731..6f66551d9e51ab00f787dfe5c2d5d9182affd4bc 100644 (file)
@@ -47,7 +47,7 @@ typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
 static struct coretemp_data *coretemp_update_device(struct device *dev);
 
 struct coretemp_data {
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        const char *name;
        u32 id;
@@ -58,8 +58,6 @@ struct coretemp_data {
        u8 alarm;
 };
 
-static struct coretemp_data *coretemp_update_device(struct device *dev);
-
 /*
  * Sysfs stuff
  */
@@ -228,9 +226,9 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
        if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
                goto exit_free;
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                dev_err(&pdev->dev, "Class registration failed (%d)\n",
                        err);
                goto exit_class;
@@ -250,7 +248,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev)
 {
        struct coretemp_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
        platform_set_drvdata(pdev, NULL);
        kfree(data);
@@ -350,7 +348,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata coretemp_cpu_notifier = {
+static struct notifier_block coretemp_cpu_notifier = {
        .notifier_call = coretemp_cpu_callback,
 };
 #endif                         /* !CONFIG_HOTPLUG_CPU */
@@ -371,9 +369,10 @@ static int __init coretemp_init(void)
        for_each_online_cpu(i) {
                struct cpuinfo_x86 *c = &(cpu_data)[i];
 
-               /* check if family 6, models e, f */
+               /* check if family 6, models e, f, 16 */
                if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
-                   !((c->x86_model == 0xe) || (c->x86_model == 0xf))) {
+                   !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
+                       (c->x86_model == 0x16))) {
 
                        /* supported CPU not found, but report the unknown
                           family 6 CPU */
index e9cbc727664d4221422be223c3c8ca082231ce67..a878c98e252e5a13f5f87d4ec840eb8b40251f25 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips
- *             integrated hardware monitoring features.
+ * dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x
+ *             Super-I/O chips integrated hardware monitoring features.
  * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
  *
- * This driver is based on the LM85 driver. The hardware monitoring
- * capabilities of the DME1737 are very similar to the LM85 with some
- * additional features. Even though the DME1737 is a Super-I/O chip, the
- * hardware monitoring registers are only accessible via SMBus.
+ * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
+ * the chip registers if a DME1737 (or A8000) is found and the ISA bus if a
+ * SCH311x chip is found. Both types of chips have very similar hardware
+ * monitoring capabilities but differ in the way they can be accessed.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
@@ -35,6 +36,9 @@
 #include <linux/mutex.h>
 #include <asm/io.h>
 
+/* ISA device, if found */
+static struct platform_device *pdev;
+
 /* Module load parameters */
 static int force_start;
 module_param(force_start, bool, 0);
@@ -133,6 +137,7 @@ static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
 static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
 
 /* Miscellaneous registers */
+#define DME1737_REG_DEVICE             0x3d
 #define DME1737_REG_COMPANY            0x3e
 #define DME1737_REG_VERSTEP            0x3f
 #define DME1737_REG_CONFIG             0x40
@@ -148,14 +153,20 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
 #define DME1737_COMPANY_SMSC   0x5c
 #define DME1737_VERSTEP                0x88
 #define DME1737_VERSTEP_MASK   0xf8
+#define SCH311X_DEVICE         0x8c
+
+/* Length of ISA address segment */
+#define DME1737_EXTENT 2
 
 /* ---------------------------------------------------------------------
  * Data structures and manipulation thereof
  * --------------------------------------------------------------------- */
 
+/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
+   the driver field to differentiate between I2C and ISA chips. */
 struct dme1737_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
 
        struct mutex update_lock;
        int valid;                      /* !=0 if following fields are valid */
@@ -465,27 +476,48 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
 
 /* ---------------------------------------------------------------------
  * Device I/O access
+ *
+ * ISA access is performed through an index/data register pair and needs to
+ * be protected by a mutex during runtime (not required for initialization).
+ * We use data->update_lock for this and need to ensure that we acquire it
+ * before calling dme1737_read or dme1737_write.
  * --------------------------------------------------------------------- */
 
 static u8 dme1737_read(struct i2c_client *client, u8 reg)
 {
-       s32 val = i2c_smbus_read_byte_data(client, reg);
+       s32 val;
+
+       if (client->driver) { /* I2C device */
+               val = i2c_smbus_read_byte_data(client, reg);
 
-       if (val < 0) {
-               dev_warn(&client->dev, "Read from register 0x%02x failed! "
-                        "Please report to the driver maintainer.\n", reg);
+               if (val < 0) {
+                       dev_warn(&client->dev, "Read from register "
+                                "0x%02x failed! Please report to the driver "
+                                "maintainer.\n", reg);
+               }
+       } else { /* ISA device */
+               outb(reg, client->addr);
+               val = inb(client->addr + 1);
        }
 
        return val;
 }
 
-static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
+static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
 {
-       s32 res = i2c_smbus_write_byte_data(client, reg, value);
+       s32 res = 0;
+
+       if (client->driver) { /* I2C device */
+               res = i2c_smbus_write_byte_data(client, reg, val);
 
-       if (res < 0) {
-               dev_warn(&client->dev, "Write to register 0x%02x failed! "
-                        "Please report to the driver maintainer.\n", reg);
+               if (res < 0) {
+                       dev_warn(&client->dev, "Write to register "
+                                "0x%02x failed! Please report to the driver "
+                                "maintainer.\n", reg);
+               }
+       } else { /* ISA device */
+               outb(reg, client->addr);
+               outb(val, client->addr + 1);
        }
 
        return res;
@@ -493,8 +525,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
 
 static struct dme1737_data *dme1737_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = &data->client;
        int ix;
        u8 lsb[5];
 
@@ -630,6 +662,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                                                DME1737_REG_ALARM3) << 16;
                }
 
+               /* The ISA chips require explicit clearing of alarm bits.
+                * Don't worry, an alarm will come back if the condition
+                * that causes it still exists */
+               if (!client->driver) {
+                       if (data->alarms & 0xff0000) {
+                               dme1737_write(client, DME1737_REG_ALARM3,
+                                             0xff);
+                       }
+                       if (data->alarms & 0xff00) {
+                               dme1737_write(client, DME1737_REG_ALARM2,
+                                             0xff);
+                       }
+                       if (data->alarms & 0xff) {
+                               dme1737_write(client, DME1737_REG_ALARM1,
+                                             0xff);
+                       }
+               }
+
                data->last_update = jiffies;
                data->valid = 1;
        }
@@ -674,7 +724,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
                break;
        default:
                res = 0;
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
 
        return sprintf(buf, "%d\n", res);
@@ -683,8 +733,8 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
 static ssize_t set_in(struct device *dev, struct device_attribute *attr,
                      const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -704,7 +754,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
                              data->in_max[ix]);
                break;
        default:
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
        mutex_unlock(&data->update_lock);
 
@@ -754,7 +804,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
                break;
        default:
                res = 0;
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
 
        return sprintf(buf, "%d\n", res);
@@ -763,8 +813,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
 static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -789,7 +839,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
                              data->temp_offset[ix]);
                break;
        default:
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
        mutex_unlock(&data->update_lock);
 
@@ -843,7 +893,7 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
                break;
        default:
                res = 0;
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
 
        return sprintf(buf, "%d\n", res);
@@ -852,8 +902,8 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
 static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -898,7 +948,7 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
                              data->zone_abs[ix]);
                break;
        default:
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
        mutex_unlock(&data->update_lock);
 
@@ -950,7 +1000,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
                break;
        default:
                res = 0;
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
 
        return sprintf(buf, "%d\n", res);
@@ -959,8 +1009,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
 static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -995,7 +1045,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                /* Only valid for fan[1-4] */
                if (!(val == 1 || val == 2 || val == 4)) {
                        count = -EINVAL;
-                       dev_warn(&client->dev, "Fan type value %ld not "
+                       dev_warn(dev, "Fan type value %ld not "
                                 "supported. Choose one of 1, 2, or 4.\n",
                                 val);
                        goto exit;
@@ -1006,7 +1056,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                              data->fan_opt[ix]);
                break;
        default:
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
 exit:
        mutex_unlock(&data->update_lock);
@@ -1086,20 +1136,20 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
                break;
        default:
                res = 0;
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
 
        return sprintf(buf, "%d\n", res);
 }
 
 static struct attribute *dme1737_attr_pwm[];
-static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t);
+static void dme1737_chmod_file(struct device*, struct attribute*, mode_t);
 
 static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -1122,7 +1172,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                /* Only valid for pwm[1-3] */
                if (val < 0 || val > 2) {
                        count = -EINVAL;
-                       dev_warn(&client->dev, "PWM enable %ld not "
+                       dev_warn(dev, "PWM enable %ld not "
                                 "supported. Choose one of 0, 1, or 2.\n",
                                 val);
                        goto exit;
@@ -1156,7 +1206,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                switch (val) {
                case 0:
                        /* Change permissions of pwm[ix] to read-only */
-                       dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+                       dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
                                           S_IRUGO);
                        /* Turn fan fully on */
                        data->pwm_config[ix] = PWM_EN_TO_REG(0,
@@ -1171,12 +1221,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
                                      data->pwm_config[ix]);
                        /* Change permissions of pwm[ix] to read-writeable */
-                       dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+                       dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
                                           S_IRUGO | S_IWUSR);
                        break;
                case 2:
                        /* Change permissions of pwm[ix] to read-only */
-                       dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+                       dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
                                           S_IRUGO);
                        /* Turn on auto mode using the saved zone channel
                         * assignment */
@@ -1223,7 +1273,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                if (!(val == 1 || val == 2 || val == 4 ||
                      val == 6 || val == 7)) {
                        count = -EINVAL;
-                       dev_warn(&client->dev, "PWM auto channels zone %ld "
+                       dev_warn(dev, "PWM auto channels zone %ld "
                                 "not supported. Choose one of 1, 2, 4, 6, "
                                 "or 7.\n", val);
                        goto exit;
@@ -1257,12 +1307,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
                                                dme1737_read(client,
                                                DME1737_REG_PWM_RR(0)));
-
                } else {
                        data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
                                                dme1737_read(client,
                                                DME1737_REG_PWM_RR(0)));
-
                }
                dme1737_write(client, DME1737_REG_PWM_RR(0),
                              data->pwm_rr[0]);
@@ -1274,7 +1322,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                              data->pwm_min[ix]);
                break;
        default:
-               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+               dev_dbg(dev, "Unknown function %d.\n", fn);
        }
 exit:
        mutex_unlock(&data->update_lock);
@@ -1298,8 +1346,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
 static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        data->vrm = val;
@@ -1314,6 +1361,14 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
 }
 
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct dme1737_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->client.name);
+}
+
 /* ---------------------------------------------------------------------
  * Sysfs device attribute defines and structs
  * --------------------------------------------------------------------- */
@@ -1322,13 +1377,13 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
 
 #define SENSOR_DEVICE_ATTR_IN(ix) \
 static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
-        show_in, NULL, SYS_IN_INPUT, ix); \
+       show_in, NULL, SYS_IN_INPUT, ix); \
 static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
-        show_in, set_in, SYS_IN_MIN, ix); \
+       show_in, set_in, SYS_IN_MIN, ix); \
 static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
-        show_in, set_in, SYS_IN_MAX, ix); \
+       show_in, set_in, SYS_IN_MAX, ix); \
 static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
-        show_in, NULL, SYS_IN_ALARM, ix)
+       show_in, NULL, SYS_IN_ALARM, ix)
 
 SENSOR_DEVICE_ATTR_IN(0);
 SENSOR_DEVICE_ATTR_IN(1);
@@ -1342,17 +1397,17 @@ SENSOR_DEVICE_ATTR_IN(6);
 
 #define SENSOR_DEVICE_ATTR_TEMP(ix) \
 static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
-        show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+       show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
 static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
-        show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+       show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
 static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
-        show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+       show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
 static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
-        show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+       show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
 static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
-        show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+       show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
 static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
-        show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+       show_temp, NULL, SYS_TEMP_FAULT, ix-1)
 
 SENSOR_DEVICE_ATTR_TEMP(1);
 SENSOR_DEVICE_ATTR_TEMP(2);
@@ -1362,15 +1417,15 @@ SENSOR_DEVICE_ATTR_TEMP(3);
 
 #define SENSOR_DEVICE_ATTR_ZONE(ix) \
 static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
-        show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+       show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
 static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
-        show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+       show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
 static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
-        show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+       show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
 static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
-        show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+       show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
 static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
-        show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+       show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
 
 SENSOR_DEVICE_ATTR_ZONE(1);
 SENSOR_DEVICE_ATTR_ZONE(2);
@@ -1380,13 +1435,13 @@ SENSOR_DEVICE_ATTR_ZONE(3);
 
 #define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
-        show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+       show_fan, NULL, SYS_FAN_INPUT, ix-1); \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
-        show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+       show_fan, set_fan, SYS_FAN_MIN, ix-1); \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
-        show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+       show_fan, NULL, SYS_FAN_ALARM, ix-1); \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
-        show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+       show_fan, set_fan, SYS_FAN_TYPE, ix-1)
 
 SENSOR_DEVICE_ATTR_FAN_1TO4(1);
 SENSOR_DEVICE_ATTR_FAN_1TO4(2);
@@ -1397,13 +1452,13 @@ SENSOR_DEVICE_ATTR_FAN_1TO4(4);
 
 #define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
-        show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+       show_fan, NULL, SYS_FAN_INPUT, ix-1); \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
-        show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+       show_fan, set_fan, SYS_FAN_MIN, ix-1); \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
-        show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+       show_fan, NULL, SYS_FAN_ALARM, ix-1); \
 static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
-        show_fan, set_fan, SYS_FAN_MAX, ix-1)
+       show_fan, set_fan, SYS_FAN_MAX, ix-1)
 
 SENSOR_DEVICE_ATTR_FAN_5TO6(5);
 SENSOR_DEVICE_ATTR_FAN_5TO6(6);
@@ -1412,21 +1467,21 @@ SENSOR_DEVICE_ATTR_FAN_5TO6(6);
 
 #define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
 static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
-        show_pwm, set_pwm, SYS_PWM, ix-1); \
+       show_pwm, set_pwm, SYS_PWM, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
-        show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+       show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
-        show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+       show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
-        show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+       show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
-        show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+       show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
-        show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+       show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
-        show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+       show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
-        show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+       show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
 
 SENSOR_DEVICE_ATTR_PWM_1TO3(1);
 SENSOR_DEVICE_ATTR_PWM_1TO3(2);
@@ -1436,11 +1491,11 @@ SENSOR_DEVICE_ATTR_PWM_1TO3(3);
 
 #define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
 static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \
-        show_pwm, set_pwm, SYS_PWM, ix-1); \
+       show_pwm, set_pwm, SYS_PWM, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
-        show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+       show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
 static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
-        show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+       show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
 
 SENSOR_DEVICE_ATTR_PWM_5TO6(5);
 SENSOR_DEVICE_ATTR_PWM_5TO6(6);
@@ -1449,6 +1504,7 @@ SENSOR_DEVICE_ATTR_PWM_5TO6(6);
 
 static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);   /* for ISA devices */
 
 #define SENSOR_DEV_ATTR_IN(ix) \
 &sensor_dev_attr_in##ix##_input.dev_attr.attr, \
@@ -1519,53 +1575,53 @@ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \
  * permissions are created read-only and write permissions are added or removed
  * on the fly when required */
 static struct attribute *dme1737_attr[] ={
-        /* Voltages */
-        SENSOR_DEV_ATTR_IN(0),
-        SENSOR_DEV_ATTR_IN(1),
-        SENSOR_DEV_ATTR_IN(2),
-        SENSOR_DEV_ATTR_IN(3),
-        SENSOR_DEV_ATTR_IN(4),
-        SENSOR_DEV_ATTR_IN(5),
-        SENSOR_DEV_ATTR_IN(6),
-        /* Temperatures */
-        SENSOR_DEV_ATTR_TEMP(1),
-        SENSOR_DEV_ATTR_TEMP(2),
-        SENSOR_DEV_ATTR_TEMP(3),
-        /* Zones */
-        SENSOR_DEV_ATTR_ZONE(1),
-        SENSOR_DEV_ATTR_ZONE(2),
-        SENSOR_DEV_ATTR_ZONE(3),
-        /* Misc */
-        &dev_attr_vrm.attr,
-        &dev_attr_cpu0_vid.attr,
+       /* Voltages */
+       SENSOR_DEV_ATTR_IN(0),
+       SENSOR_DEV_ATTR_IN(1),
+       SENSOR_DEV_ATTR_IN(2),
+       SENSOR_DEV_ATTR_IN(3),
+       SENSOR_DEV_ATTR_IN(4),
+       SENSOR_DEV_ATTR_IN(5),
+       SENSOR_DEV_ATTR_IN(6),
+       /* Temperatures */
+       SENSOR_DEV_ATTR_TEMP(1),
+       SENSOR_DEV_ATTR_TEMP(2),
+       SENSOR_DEV_ATTR_TEMP(3),
+       /* Zones */
+       SENSOR_DEV_ATTR_ZONE(1),
+       SENSOR_DEV_ATTR_ZONE(2),
+       SENSOR_DEV_ATTR_ZONE(3),
+       /* Misc */
+       &dev_attr_vrm.attr,
+       &dev_attr_cpu0_vid.attr,
        NULL
 };
 
 static const struct attribute_group dme1737_group = {
-        .attrs = dme1737_attr,
+       .attrs = dme1737_attr,
 };
 
 /* The following structs hold the PWM attributes, some of which are optional.
  * Their creation depends on the chip configuration which is determined during
  * module load. */
 static struct attribute *dme1737_attr_pwm1[] = {
-        SENSOR_DEV_ATTR_PWM_1TO3(1),
+       SENSOR_DEV_ATTR_PWM_1TO3(1),
        NULL
 };
 static struct attribute *dme1737_attr_pwm2[] = {
-        SENSOR_DEV_ATTR_PWM_1TO3(2),
+       SENSOR_DEV_ATTR_PWM_1TO3(2),
        NULL
 };
 static struct attribute *dme1737_attr_pwm3[] = {
-        SENSOR_DEV_ATTR_PWM_1TO3(3),
+       SENSOR_DEV_ATTR_PWM_1TO3(3),
        NULL
 };
 static struct attribute *dme1737_attr_pwm5[] = {
-        SENSOR_DEV_ATTR_PWM_5TO6(5),
+       SENSOR_DEV_ATTR_PWM_5TO6(5),
        NULL
 };
 static struct attribute *dme1737_attr_pwm6[] = {
-        SENSOR_DEV_ATTR_PWM_5TO6(6),
+       SENSOR_DEV_ATTR_PWM_5TO6(6),
        NULL
 };
 
@@ -1582,27 +1638,27 @@ static const struct attribute_group dme1737_pwm_group[] = {
  * Their creation depends on the chip configuration which is determined during
  * module load. */
 static struct attribute *dme1737_attr_fan1[] = {
-        SENSOR_DEV_ATTR_FAN_1TO4(1),
+       SENSOR_DEV_ATTR_FAN_1TO4(1),
        NULL
 };
 static struct attribute *dme1737_attr_fan2[] = {
-        SENSOR_DEV_ATTR_FAN_1TO4(2),
+       SENSOR_DEV_ATTR_FAN_1TO4(2),
        NULL
 };
 static struct attribute *dme1737_attr_fan3[] = {
-        SENSOR_DEV_ATTR_FAN_1TO4(3),
+       SENSOR_DEV_ATTR_FAN_1TO4(3),
        NULL
 };
 static struct attribute *dme1737_attr_fan4[] = {
-        SENSOR_DEV_ATTR_FAN_1TO4(4),
+       SENSOR_DEV_ATTR_FAN_1TO4(4),
        NULL
 };
 static struct attribute *dme1737_attr_fan5[] = {
-        SENSOR_DEV_ATTR_FAN_5TO6(5),
+       SENSOR_DEV_ATTR_FAN_5TO6(5),
        NULL
 };
 static struct attribute *dme1737_attr_fan6[] = {
-        SENSOR_DEV_ATTR_FAN_5TO6(6),
+       SENSOR_DEV_ATTR_FAN_5TO6(6),
        NULL
 };
 
@@ -1637,23 +1693,23 @@ static const struct attribute_group dme1737_lock_group = {
  * writeable if the chip is *not* locked and the respective PWM is available.
  * Otherwise they stay read-only. */
 static struct attribute *dme1737_attr_pwm1_lock[] = {
-        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
+       SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
        NULL
 };
 static struct attribute *dme1737_attr_pwm2_lock[] = {
-        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
+       SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
        NULL
 };
 static struct attribute *dme1737_attr_pwm3_lock[] = {
-        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
+       SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
        NULL
 };
 static struct attribute *dme1737_attr_pwm5_lock[] = {
-        SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
+       SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
        NULL
 };
 static struct attribute *dme1737_attr_pwm6_lock[] = {
-        SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
+       SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
        NULL
 };
 
@@ -1678,6 +1734,16 @@ static struct attribute *dme1737_attr_pwm[] = {
  * Super-IO functions
  * --------------------------------------------------------------------- */
 
+static inline void dme1737_sio_enter(int sio_cip)
+{
+       outb(0x55, sio_cip);
+}
+
+static inline void dme1737_sio_exit(int sio_cip)
+{
+       outb(0xaa, sio_cip);
+}
+
 static inline int dme1737_sio_inb(int sio_cip, int reg)
 {
        outb(reg, sio_cip);
@@ -1690,136 +1756,196 @@ static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
        outb(val, sio_cip + 1);
 }
 
-static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client)
+/* ---------------------------------------------------------------------
+ * Device initialization
+ * --------------------------------------------------------------------- */
+
+static int dme1737_i2c_get_features(int, struct dme1737_data*);
+
+static void dme1737_chmod_file(struct device *dev,
+                              struct attribute *attr, mode_t mode)
 {
-       struct dme1737_data *data = i2c_get_clientdata(client);
-       int err = 0, reg;
-       u16 addr;
+       if (sysfs_chmod_file(&dev->kobj, attr, mode)) {
+               dev_warn(dev, "Failed to change permissions of %s.\n",
+                        attr->name);
+       }
+}
 
-       /* Enter configuration mode */
-       outb(0x55, sio_cip);
+static void dme1737_chmod_group(struct device *dev,
+                               const struct attribute_group *group,
+                               mode_t mode)
+{
+       struct attribute **attr;
 
-       /* Check device ID
-        * The DME1737 can return either 0x78 or 0x77 as its device ID. */
-       reg = dme1737_sio_inb(sio_cip, 0x20);
-       if (!(reg == 0x77 || reg == 0x78)) {
-               err = -ENODEV;
-               goto exit;
+       for (attr = group->attrs; *attr; attr++) {
+               dme1737_chmod_file(dev, *attr, mode);
        }
+}
 
-       /* Select logical device A (runtime registers) */
-       dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+static void dme1737_remove_files(struct device *dev)
+{
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       int ix;
 
-       /* Get the base address of the runtime registers */
-       if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
-                     dme1737_sio_inb(sio_cip, 0x61))) {
-               err = -ENODEV;
-               goto exit;
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+               if (data->has_fan & (1 << ix)) {
+                       sysfs_remove_group(&dev->kobj,
+                                          &dme1737_fan_group[ix]);
+               }
        }
 
-       /* Read the runtime registers to determine which optional features
-        * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
-        * to '10' if the respective feature is enabled. */
-       if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
-               data->has_fan |= (1 << 5);
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+               if (data->has_pwm & (1 << ix)) {
+                       sysfs_remove_group(&dev->kobj,
+                                          &dme1737_pwm_group[ix]);
+               }
        }
-       if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
-               data->has_pwm |= (1 << 5);
+
+       sysfs_remove_group(&dev->kobj, &dme1737_group);
+
+       if (!data->client.driver) {
+               sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
        }
-       if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
-               data->has_fan |= (1 << 4);
+}
+
+static int dme1737_create_files(struct device *dev)
+{
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       int err, ix;
+
+       /* Create a name attribute for ISA devices */
+       if (!data->client.driver &&
+           (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
+               goto exit;
        }
-       if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
-               data->has_pwm |= (1 << 4);
+
+       /* Create standard sysfs attributes */
+       if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) {
+               goto exit_remove;
        }
 
-exit:
-       /* Exit configuration mode */
-       outb(0xaa, sio_cip);
+       /* Create fan sysfs attributes */
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+               if (data->has_fan & (1 << ix)) {
+                       if ((err = sysfs_create_group(&dev->kobj,
+                                               &dme1737_fan_group[ix]))) {
+                               goto exit_remove;
+                       }
+               }
+       }
 
-       return err;
-}
+       /* Create PWM sysfs attributes */
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+               if (data->has_pwm & (1 << ix)) {
+                       if ((err = sysfs_create_group(&dev->kobj,
+                                               &dme1737_pwm_group[ix]))) {
+                               goto exit_remove;
+                       }
+               }
+       }
 
-/* ---------------------------------------------------------------------
- * Device detection, registration and initialization
- * --------------------------------------------------------------------- */
+       /* Inform if the device is locked. Otherwise change the permissions of
+        * selected attributes from read-only to read-writeable. */
+       if (data->config & 0x02) {
+               dev_info(dev, "Device is locked. Some attributes "
+                        "will be read-only.\n");
+       } else {
+               /* Change permissions of standard attributes */
+               dme1737_chmod_group(dev, &dme1737_lock_group,
+                                   S_IRUGO | S_IWUSR);
 
-static struct i2c_driver dme1737_driver;
+               /* Change permissions of PWM attributes */
+               for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
+                       if (data->has_pwm & (1 << ix)) {
+                               dme1737_chmod_group(dev,
+                                               &dme1737_pwm_lock_group[ix],
+                                               S_IRUGO | S_IWUSR);
+                       }
+               }
 
-static void dme1737_chmod_file(struct i2c_client *client,
-                              struct attribute *attr, mode_t mode)
-{
-       if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) {
-               dev_warn(&client->dev, "Failed to change permissions of %s.\n",
-                        attr->name);
+               /* Change permissions of pwm[1-3] if in manual mode */
+               for (ix = 0; ix < 3; ix++) {
+                       if ((data->has_pwm & (1 << ix)) &&
+                           (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+                               dme1737_chmod_file(dev,
+                                               dme1737_attr_pwm[ix],
+                                               S_IRUGO | S_IWUSR);
+                       }
+               }
        }
-}
 
-static void dme1737_chmod_group(struct i2c_client *client,
-                               const struct attribute_group *group,
-                               mode_t mode)
-{
-       struct attribute **attr;
+       return 0;
 
-       for (attr = group->attrs; *attr; attr++) {
-               dme1737_chmod_file(client, *attr, mode);
-       }
+exit_remove:
+       dme1737_remove_files(dev);
+exit:
+       return err;
 }
 
-static int dme1737_init_client(struct i2c_client *client)
+static int dme1737_init_device(struct device *dev)
 {
-       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct dme1737_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = &data->client;
        int ix;
        u8 reg;
 
-        data->config = dme1737_read(client, DME1737_REG_CONFIG);
-        /* Inform if part is not monitoring/started */
-        if (!(data->config & 0x01)) {
-                if (!force_start) {
-                        dev_err(&client->dev, "Device is not monitoring. "
-                                "Use the force_start load parameter to "
-                                "override.\n");
-                        return -EFAULT;
-                }
-
-                /* Force monitoring */
-                data->config |= 0x01;
-                dme1737_write(client, DME1737_REG_CONFIG, data->config);
-        }
+       data->config = dme1737_read(client, DME1737_REG_CONFIG);
+       /* Inform if part is not monitoring/started */
+       if (!(data->config & 0x01)) {
+               if (!force_start) {
+                       dev_err(dev, "Device is not monitoring. "
+                               "Use the force_start load parameter to "
+                               "override.\n");
+                       return -EFAULT;
+               }
+
+               /* Force monitoring */
+               data->config |= 0x01;
+               dme1737_write(client, DME1737_REG_CONFIG, data->config);
+       }
        /* Inform if part is not ready */
        if (!(data->config & 0x04)) {
-               dev_err(&client->dev, "Device is not ready.\n");
+               dev_err(dev, "Device is not ready.\n");
                return -EFAULT;
        }
 
-       data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
-       /* Check if optional fan3 input is enabled */
-       if (data->config2 & 0x04) {
-               data->has_fan |= (1 << 2);
-       }
+       /* Determine which optional fan and pwm features are enabled/present */
+       if (client->driver) {   /* I2C chip */
+               data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+               /* Check if optional fan3 input is enabled */
+               if (data->config2 & 0x04) {
+                       data->has_fan |= (1 << 2);
+               }
 
-       /* Fan4 and pwm3 are only available if the client's I2C address
-        * is the default 0x2e. Otherwise the I/Os associated with these
-        * functions are used for addr enable/select. */
-       if (client->addr == 0x2e) {
-               data->has_fan |= (1 << 3);
-               data->has_pwm |= (1 << 2);
-       }
+               /* Fan4 and pwm3 are only available if the client's I2C address
+                * is the default 0x2e. Otherwise the I/Os associated with
+                * these functions are used for addr enable/select. */
+               if (data->client.addr == 0x2e) {
+                       data->has_fan |= (1 << 3);
+                       data->has_pwm |= (1 << 2);
+               }
 
-       /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled.
-        * For this, we need to query the runtime registers through the
-        * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */
-       if (dme1737_sio_get_features(0x2e, client) &&
-           dme1737_sio_get_features(0x4e, client)) {
-               dev_warn(&client->dev, "Failed to query Super-IO for optional "
-                        "features.\n");
+               /* Determine which of the optional fan[5-6] and pwm[5-6]
+                * features are enabled. For this, we need to query the runtime
+                * registers through the Super-IO LPC interface. Try both
+                * config ports 0x2e and 0x4e. */
+               if (dme1737_i2c_get_features(0x2e, data) &&
+                   dme1737_i2c_get_features(0x4e, data)) {
+                       dev_warn(dev, "Failed to query Super-IO for optional "
+                                "features.\n");
+               }
+       } else {   /* ISA chip */
+               /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6]
+                * don't exist in the ISA chip. */
+               data->has_fan |= (1 << 2);
+               data->has_pwm |= (1 << 2);
        }
 
        /* Fan1, fan2, pwm1, and pwm2 are always present */
        data->has_fan |= 0x03;
        data->has_pwm |= 0x03;
 
-       dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
+       dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
                 "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
                 (data->has_pwm & (1 << 2)) ? "yes" : "no",
                 (data->has_pwm & (1 << 4)) ? "yes" : "no",
@@ -1831,13 +1957,19 @@ static int dme1737_init_client(struct i2c_client *client)
 
        reg = dme1737_read(client, DME1737_REG_TACH_PWM);
        /* Inform if fan-to-pwm mapping differs from the default */
-       if (reg != 0xa4) {
-               dev_warn(&client->dev, "Non-standard fan to pwm mapping: "
+       if (client->driver && reg != 0xa4) {   /* I2C chip */
+               dev_warn(dev, "Non-standard fan to pwm mapping: "
                         "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
                         "fan4->pwm%d. Please report to the driver "
                         "maintainer.\n",
                         (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
                         ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+       } else if (!client->driver && reg != 0x24) {   /* ISA chip */
+               dev_warn(dev, "Non-standard fan to pwm mapping: "
+                        "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
+                        "Please report to the driver maintainer.\n",
+                        (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+                        ((reg >> 4) & 0x03) + 1);
        }
 
        /* Switch pwm[1-3] to manual mode if they are currently disabled and
@@ -1849,7 +1981,7 @@ static int dme1737_init_client(struct i2c_client *client)
                                                DME1737_REG_PWM_CONFIG(ix));
                        if ((data->has_pwm & (1 << ix)) &&
                            (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
-                               dev_info(&client->dev, "Switching pwm%d to "
+                               dev_info(dev, "Switching pwm%d to "
                                         "manual mode.\n", ix + 1);
                                data->pwm_config[ix] = PWM_EN_TO_REG(1,
                                                        data->pwm_config[ix]);
@@ -1872,13 +2004,67 @@ static int dme1737_init_client(struct i2c_client *client)
        return 0;
 }
 
-static int dme1737_detect(struct i2c_adapter *adapter, int address,
-                         int kind)
+/* ---------------------------------------------------------------------
+ * I2C device detection and registration
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_i2c_driver;
+
+static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
+{
+       int err = 0, reg;
+       u16 addr;
+
+       dme1737_sio_enter(sio_cip);
+
+       /* Check device ID
+        * The DME1737 can return either 0x78 or 0x77 as its device ID. */
+       reg = dme1737_sio_inb(sio_cip, 0x20);
+       if (!(reg == 0x77 || reg == 0x78)) {
+               err = -ENODEV;
+               goto exit;
+       }
+
+       /* Select logical device A (runtime registers) */
+       dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+       /* Get the base address of the runtime registers */
+       if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+                     dme1737_sio_inb(sio_cip, 0x61))) {
+               err = -ENODEV;
+               goto exit;
+       }
+
+       /* Read the runtime registers to determine which optional features
+        * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+        * to '10' if the respective feature is enabled. */
+       if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
+               data->has_fan |= (1 << 5);
+       }
+       if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
+               data->has_pwm |= (1 << 5);
+       }
+       if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
+               data->has_fan |= (1 << 4);
+       }
+       if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
+               data->has_pwm |= (1 << 4);
+       }
+
+exit:
+       dme1737_sio_exit(sio_cip);
+
+       return err;
+}
+
+static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
+                             int kind)
 {
        u8 company, verstep = 0;
        struct i2c_client *client;
        struct dme1737_data *data;
-       int ix, err = 0;
+       struct device *dev;
+       int err = 0;
        const char *name;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -1894,7 +2080,8 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address,
        i2c_set_clientdata(client, data);
        client->addr = address;
        client->adapter = adapter;
-       client->driver = &dme1737_driver;
+       client->driver = &dme1737_i2c_driver;
+       dev = &client->dev;
 
        /* A negative kind means that the driver was loaded with no force
         * parameter (default), so we must identify the chip. */
@@ -1922,92 +2109,33 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address,
                goto exit_kfree;
        }
 
+       dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n",
+                client->addr, verstep);
+
        /* Initialize the DME1737 chip */
-       if ((err = dme1737_init_client(client))) {
+       if ((err = dme1737_init_device(dev))) {
+               dev_err(dev, "Failed to initialize device.\n");
                goto exit_detach;
        }
 
-       /* Create standard sysfs attributes */
-       if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) {
-                goto exit_detach;
-       }
-
-       /* Create fan sysfs attributes */
-       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
-               if (data->has_fan & (1 << ix)) {
-                       if ((err = sysfs_create_group(&client->dev.kobj,
-                                               &dme1737_fan_group[ix]))) {
-                               goto exit_remove;
-                       }
-               }
-       }
-
-       /* Create PWM sysfs attributes */
-       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
-               if (data->has_pwm & (1 << ix)) {
-                       if ((err = sysfs_create_group(&client->dev.kobj,
-                                               &dme1737_pwm_group[ix]))) {
-                               goto exit_remove;
-                       }
-               }
-       }
-
-       /* Inform if the device is locked. Otherwise change the permissions of
-        * selected attributes from read-only to read-writeable. */
-       if (data->config & 0x02) {
-               dev_info(&client->dev, "Device is locked. Some attributes "
-                        "will be read-only.\n");
-       } else {
-               /* Change permissions of standard attributes */
-               dme1737_chmod_group(client, &dme1737_lock_group,
-                                   S_IRUGO | S_IWUSR);
-
-               /* Change permissions of PWM attributes */
-               for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
-                       if (data->has_pwm & (1 << ix)) {
-                               dme1737_chmod_group(client,
-                                               &dme1737_pwm_lock_group[ix],
-                                               S_IRUGO | S_IWUSR);
-                       }
-               }
-
-               /* Change permissions of pwm[1-3] if in manual mode */
-               for (ix = 0; ix < 3; ix++) {
-                       if ((data->has_pwm & (1 << ix)) &&
-                           (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
-                               dme1737_chmod_file(client,
-                                                  dme1737_attr_pwm[ix],
-                                                  S_IRUGO | S_IWUSR);
-                       }
-               }
+       /* Create sysfs files */
+       if ((err = dme1737_create_files(dev))) {
+               dev_err(dev, "Failed to create sysfs files.\n");
+               goto exit_detach;
        }
 
        /* Register device */
-       data->class_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               dev_err(dev, "Failed to register device.\n");
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
-       dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x "
-                "(rev 0x%02x)\n", client->addr, verstep);
-
        return 0;
 
 exit_remove:
-       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
-               if (data->has_fan & (1 << ix)) {
-                       sysfs_remove_group(&client->dev.kobj,
-                                          &dme1737_fan_group[ix]);
-               }
-       }
-       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
-               if (data->has_pwm & (1 << ix)) {
-                       sysfs_remove_group(&client->dev.kobj,
-                                          &dme1737_pwm_group[ix]);
-               }
-       }
-       sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+       dme1737_remove_files(dev);
 exit_detach:
        i2c_detach_client(client);
 exit_kfree:
@@ -2016,60 +2144,260 @@ exit:
        return err;
 }
 
-static int dme1737_attach_adapter(struct i2c_adapter *adapter)
+static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter)
 {
        if (!(adapter->class & I2C_CLASS_HWMON)) {
                return 0;
        }
 
-       return i2c_probe(adapter, &addr_data, dme1737_detect);
+       return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);
 }
 
-static int dme1737_detach_client(struct i2c_client *client)
+static int dme1737_i2c_detach_client(struct i2c_client *client)
 {
        struct dme1737_data *data = i2c_get_clientdata(client);
-       int ix, err;
+       int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
+       dme1737_remove_files(&client->dev);
 
-       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
-               if (data->has_fan & (1 << ix)) {
-                       sysfs_remove_group(&client->dev.kobj,
-                                          &dme1737_fan_group[ix]);
-               }
+       if ((err = i2c_detach_client(client))) {
+               return err;
        }
-       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
-               if (data->has_pwm & (1 << ix)) {
-                       sysfs_remove_group(&client->dev.kobj,
-                                          &dme1737_pwm_group[ix]);
-               }
+
+       kfree(data);
+       return 0;
+}
+
+static struct i2c_driver dme1737_i2c_driver = {
+       .driver = {
+               .name = "dme1737",
+       },
+       .attach_adapter = dme1737_i2c_attach_adapter,
+       .detach_client = dme1737_i2c_detach_client,
+};
+
+/* ---------------------------------------------------------------------
+ * ISA device detection and registration
+ * --------------------------------------------------------------------- */
+
+static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
+{
+       int err = 0, reg;
+       unsigned short base_addr;
+
+       dme1737_sio_enter(sio_cip);
+
+       /* Check device ID
+        * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and
+        * SCH3116 (0x7f). */
+       reg = dme1737_sio_inb(sio_cip, 0x20);
+       if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
+               err = -ENODEV;
+               goto exit;
        }
-       sysfs_remove_group(&client->dev.kobj, &dme1737_group);
 
-       if ((err = i2c_detach_client(client))) {
-               return err;
+       /* Select logical device A (runtime registers) */
+       dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+       /* Get the base address of the runtime registers */
+       if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+                          dme1737_sio_inb(sio_cip, 0x61))) {
+               printk(KERN_ERR "dme1737: Base address not set.\n");
+               err = -ENODEV;
+               goto exit;
+       }
+
+       /* Access to the hwmon registers is through an index/data register
+        * pair located at offset 0x70/0x71. */
+       *addr = base_addr + 0x70;
+
+exit:
+       dme1737_sio_exit(sio_cip);
+       return err;
+}
+
+static int __init dme1737_isa_device_add(unsigned short addr)
+{
+       struct resource res = {
+               .start  = addr,
+               .end    = addr + DME1737_EXTENT - 1,
+               .name   = "dme1737",
+               .flags  = IORESOURCE_IO,
+       };
+       int err;
+
+       if (!(pdev = platform_device_alloc("dme1737", addr))) {
+               printk(KERN_ERR "dme1737: Failed to allocate device.\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       if ((err = platform_device_add_resources(pdev, &res, 1))) {
+               printk(KERN_ERR "dme1737: Failed to add device resource "
+                      "(err = %d).\n", err);
+               goto exit_device_put;
+       }
+
+       if ((err = platform_device_add(pdev))) {
+               printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n",
+                      err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+       pdev = NULL;
+exit:
+       return err;
+}
+
+static int __devinit dme1737_isa_probe(struct platform_device *pdev)
+{
+       u8 company, device;
+       struct resource *res;
+       struct i2c_client *client;
+       struct dme1737_data *data;
+       struct device *dev = &pdev->dev;
+       int err;
+
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!request_region(res->start, DME1737_EXTENT, "dme1737")) {
+               dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
+                       (unsigned short)res->start,
+                       (unsigned short)res->start + DME1737_EXTENT - 1);
+                err = -EBUSY;
+                goto exit;
+        }
+
+       if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit_release_region;
+       }
+
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = res->start;
+       platform_set_drvdata(pdev, data);
+
+       company = dme1737_read(client, DME1737_REG_COMPANY);
+       device = dme1737_read(client, DME1737_REG_DEVICE);
+
+       if (!((company == DME1737_COMPANY_SMSC) &&
+             (device == SCH311X_DEVICE))) {
+               err = -ENODEV;
+               goto exit_kfree;
+       }
+
+       /* Fill in the remaining client fields and initialize the mutex */
+       strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
+       mutex_init(&data->update_lock);
+
+       dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr);
+
+       /* Initialize the chip */
+       if ((err = dme1737_init_device(dev))) {
+               dev_err(dev, "Failed to initialize device.\n");
+               goto exit_kfree;
        }
 
+       /* Create sysfs files */
+       if ((err = dme1737_create_files(dev))) {
+               dev_err(dev, "Failed to create sysfs files.\n");
+               goto exit_kfree;
+       }
+
+       /* Register device */
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               dev_err(dev, "Failed to register device.\n");
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
+       dme1737_remove_files(dev);
+exit_kfree:
+       platform_set_drvdata(pdev, NULL);
+       kfree(data);
+exit_release_region:
+       release_region(res->start, DME1737_EXTENT);
+exit:
+       return err;
+}
+
+static int __devexit dme1737_isa_remove(struct platform_device *pdev)
+{
+       struct dme1737_data *data = platform_get_drvdata(pdev);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       dme1737_remove_files(&pdev->dev);
+       release_region(data->client.addr, DME1737_EXTENT);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
+
        return 0;
 }
 
-static struct i2c_driver dme1737_driver = {
+static struct platform_driver dme1737_isa_driver = {
        .driver = {
+               .owner = THIS_MODULE,
                .name = "dme1737",
        },
-       .attach_adapter = dme1737_attach_adapter,
-       .detach_client = dme1737_detach_client,
+       .probe = dme1737_isa_probe,
+       .remove = __devexit_p(dme1737_isa_remove),
 };
 
+/* ---------------------------------------------------------------------
+ * Module initialization and cleanup
+ * --------------------------------------------------------------------- */
+
 static int __init dme1737_init(void)
 {
-       return i2c_add_driver(&dme1737_driver);
+       int err;
+       unsigned short addr;
+
+       if ((err = i2c_add_driver(&dme1737_i2c_driver))) {
+               goto exit;
+       }
+
+       if (dme1737_isa_detect(0x2e, &addr) &&
+           dme1737_isa_detect(0x4e, &addr)) {
+               /* Return 0 if we didn't find an ISA device */
+               return 0;
+       }
+
+       if ((err = platform_driver_register(&dme1737_isa_driver))) {
+               goto exit_del_i2c_driver;
+       }
+
+       /* Sets global pdev as a side effect */
+       if ((err = dme1737_isa_device_add(addr))) {
+               goto exit_del_isa_driver;
+       }
+
+       return 0;
+
+exit_del_isa_driver:
+       platform_driver_unregister(&dme1737_isa_driver);
+exit_del_i2c_driver:
+       i2c_del_driver(&dme1737_i2c_driver);
+exit:
+       return err;
 }
 
 static void __exit dme1737_exit(void)
 {
-       i2c_del_driver(&dme1737_driver);
+       if (pdev) {
+               platform_device_unregister(pdev);
+               platform_driver_unregister(&dme1737_isa_driver);
+       }
+
+       i2c_del_driver(&dme1737_i2c_driver);
 }
 
 MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
index 1212d6b7f316ee6297374d1f3454a76d2e7ac0ae..b7bd000b130f4a76e2316f3036ec4817fc55437f 100644 (file)
@@ -73,7 +73,7 @@ static const u8 DS1621_REG_TEMP[3] = {
 /* Each client has this additional data */
 struct ds1621_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -151,7 +151,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct i2c_client *client = to_i2c_client(dev);
        struct ds1621_data *data = ds1621_update_client(dev);
-       u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
+       u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
 
        mutex_lock(&data->update_lock);
        data->temp[attr->index] = val;
@@ -266,9 +266,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
        if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -289,7 +289,7 @@ static int ds1621_detach_client(struct i2c_client *client)
        struct ds1621_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &ds1621_group);
 
        if ((err = i2c_detach_client(client)))
index 6f60715f34f815021662f03c1ce605a60bf28827..5d9d5cc816a24d1a2e871deb5da53bf59d950f3d 100644 (file)
@@ -10,6 +10,9 @@
  * The F71872F/FG is almost the same, with two more voltages monitored,
  * and 6 VID inputs.
  *
+ * The F71806F/FG is essentially the same as the F71872F/FG. It even has
+ * the same chip ID, so the driver can't differentiate between.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -159,7 +162,7 @@ struct f71805f_auto_point {
 struct f71805f_data {
        unsigned short addr;
        const char *name;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
 
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
@@ -1378,9 +1381,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
                }
        }
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
                goto exit_remove_files;
        }
@@ -1407,7 +1410,7 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
        struct resource *res;
        int i;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
        for (i = 0; i < 4; i++)
                sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
@@ -1485,7 +1488,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
 
        static const char *names[] = {
                "F71805F/FG",
-               "F71872F/FG",
+               "F71872F/FG or F71806F/FG",
        };
 
        superio_enter(sioaddr);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
new file mode 100644 (file)
index 0000000..6db7443
--- /dev/null
@@ -0,0 +1,950 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Hans Edgington <hans@edgington.nl>              *
+ *   Copyright (C) 2007 by Hans de Goede  <j.w.r.degoede@hhs.nl>           *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+#define DRVNAME "f71882fg"
+
+#define SIO_F71882FG_LD_HWM    0x04    /* Hardware monitor logical device*/
+#define SIO_UNLOCK_KEY         0x87    /* Key to enable Super-I/O */
+#define SIO_LOCK_KEY           0xAA    /* Key to diasble Super-I/O */
+
+#define SIO_REG_LDSEL          0x07    /* Logical device select */
+#define SIO_REG_DEVID          0x20    /* Device ID (2 bytes) */
+#define SIO_REG_DEVREV         0x22    /* Device revision */
+#define SIO_REG_MANID          0x23    /* Fintek ID (2 bytes) */
+#define SIO_REG_ENABLE         0x30    /* Logical device enable */
+#define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
+
+#define SIO_FINTEK_ID          0x1934  /* Manufacturers ID */
+#define SIO_F71882_ID          0x0541  /* Chipset ID */
+
+#define REGION_LENGTH          8
+#define ADDR_REG_OFFSET                5
+#define DATA_REG_OFFSET                6
+
+#define F71882FG_REG_PECI              0x0A
+
+#define F71882FG_REG_IN_STATUS         0x12
+#define F71882FG_REG_IN_BEEP           0x13
+#define F71882FG_REG_IN(nr)            (0x20  + (nr))
+#define F71882FG_REG_IN1_HIGH          0x32
+
+#define F71882FG_REG_FAN(nr)           (0xA0 + (16 * (nr)))
+#define F71882FG_REG_FAN_STATUS                0x92
+#define F71882FG_REG_FAN_BEEP          0x93
+
+#define F71882FG_REG_TEMP(nr)          (0x72 + 2 * (nr))
+#define F71882FG_REG_TEMP_OVT(nr)      (0x82 + 2 * (nr))
+#define F71882FG_REG_TEMP_HIGH(nr)     (0x83 + 2 * (nr))
+#define F71882FG_REG_TEMP_STATUS       0x62
+#define F71882FG_REG_TEMP_BEEP         0x63
+#define F71882FG_REG_TEMP_HYST1                0x6C
+#define F71882FG_REG_TEMP_HYST23       0x6D
+#define F71882FG_REG_TEMP_TYPE         0x6B
+#define F71882FG_REG_TEMP_DIODE_OPEN   0x6F
+
+#define        F71882FG_REG_START              0x01
+
+#define FAN_MIN_DETECT                 366 /* Lowest detectable fanspeed */
+
+static struct platform_device *f71882fg_pdev = NULL;
+
+/* Super-I/O Function prototypes */
+static inline int superio_inb(int base, int reg);
+static inline int superio_inw(int base, int reg);
+static inline void superio_enter(int base);
+static inline void superio_select(int base, int ld);
+static inline void superio_exit(int base);
+
+static inline u16 fan_from_reg ( u16 reg );
+
+struct f71882fg_data {
+       unsigned short addr;
+       struct device *hwmon_dev;
+
+       struct mutex update_lock;
+       char valid;                     /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+       unsigned long last_limits;      /* In jiffies */
+
+       /* Register Values */
+       u8      in[9];
+       u8      in1_max;
+       u8      in_status;
+       u8      in_beep;
+       u16     fan[4];
+       u8      fan_status;
+       u8      fan_beep;
+       u8      temp[3];
+       u8      temp_ovt[3];
+       u8      temp_high[3];
+       u8      temp_hyst[3];
+       u8      temp_type[3];
+       u8      temp_status;
+       u8      temp_beep;
+       u8      temp_diode_open;
+};
+
+static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg);
+static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg);
+static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val);
+
+/* Sysfs in*/
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+       char *buf);
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count);
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count);
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+/* Sysfs Fan */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+       char *buf);
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count);
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+/* Sysfs Temp */
+static ssize_t show_temp(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count);
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count);
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+       *devattr, char *buf);
+/* Sysfs misc */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+       char *buf);
+
+static int __devinit f71882fg_probe(struct platform_device * pdev);
+static int __devexit f71882fg_remove(struct platform_device *pdev);
+static int __init f71882fg_init(void);
+static int __init f71882fg_find(int sioaddr, unsigned short *address);
+static int __init f71882fg_device_add(unsigned short address);
+static void __exit f71882fg_exit(void);
+
+static struct platform_driver f71882fg_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = DRVNAME,
+       },
+       .probe          = f71882fg_probe,
+       .remove         = __devexit_p(f71882fg_remove),
+};
+
+static struct device_attribute f71882fg_dev_attr[] =
+{
+       __ATTR( name, S_IRUGO, show_name, NULL ),
+};
+
+static struct sensor_device_attribute f71882fg_in_temp_attr[] =
+{
+       SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+       SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+       SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1),
+       SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1),
+       SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1),
+       SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+       SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+       SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+       SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+       SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+       SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+       SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+       SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+       SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 0),
+       SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 0),
+       SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 0),
+       SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0),
+       SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+       SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+               store_temp_beep, 0),
+       SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
+       SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
+       SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+       SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 1),
+       SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 1),
+       SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 1),
+       SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
+       SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+       SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+               store_temp_beep, 1),
+       SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
+       SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
+       SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+       SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 2),
+       SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 2),
+       SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 2),
+       SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2),
+       SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
+       SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+               store_temp_beep, 2),
+       SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
+       SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2)
+};
+
+static struct sensor_device_attribute f71882fg_fan_attr[] =
+{
+       SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+       SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0),
+       SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0),
+       SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+       SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 1),
+       SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1),
+       SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+       SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 2),
+       SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2),
+       SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+       SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 3),
+       SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3)
+};
+
+
+/* Super I/O functions */
+static inline int superio_inb(int base, int reg)
+{
+       outb(reg, base);
+       return inb(base + 1);
+}
+
+static int superio_inw(int base, int reg)
+{
+       int val;
+       outb(reg++, base);
+       val = inb(base + 1) << 8;
+       outb(reg, base);
+       val |= inb(base + 1);
+       return val;
+}
+
+static inline void superio_enter(int base)
+{
+       /* according to the datasheet the key must be send twice! */
+       outb( SIO_UNLOCK_KEY, base);
+       outb( SIO_UNLOCK_KEY, base);
+}
+
+static inline void superio_select( int base, int ld)
+{
+       outb(SIO_REG_LDSEL, base);
+       outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+       outb(SIO_LOCK_KEY, base);
+}
+
+static inline u16 fan_from_reg(u16 reg)
+{
+       return reg ? (1500000 / reg) : 0;
+}
+
+static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
+{
+       u8 val;
+
+       outb(reg, data->addr + ADDR_REG_OFFSET);
+       val = inb(data->addr + DATA_REG_OFFSET);
+
+       return val;
+}
+
+static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
+{
+       u16 val;
+
+       outb(reg++, data->addr + ADDR_REG_OFFSET);
+       val = inb(data->addr + DATA_REG_OFFSET) << 8;
+       outb(reg, data->addr + ADDR_REG_OFFSET);
+       val |= inb(data->addr + DATA_REG_OFFSET);
+
+       return val;
+}
+
+static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
+{
+       outb(reg, data->addr + ADDR_REG_OFFSET);
+       outb(val, data->addr + DATA_REG_OFFSET);
+}
+
+static struct f71882fg_data *f71882fg_update_device(struct device * dev)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int nr, reg, reg2;
+
+       mutex_lock(&data->update_lock);
+
+       /* Update once every 60 seconds */
+       if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
+                       !data->valid) {
+               data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
+               data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
+
+               /* Get High & boundary temps*/
+               for (nr = 0; nr < 3; nr++) {
+                       data->temp_ovt[nr] = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP_OVT(nr));
+                       data->temp_high[nr] = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP_HIGH(nr));
+               }
+
+               /* Have to hardcode hyst*/
+               data->temp_hyst[0] = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP_HYST1) >> 4;
+               /* Hyst temps 2 & 3 stored in same register */
+               reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23);
+               data->temp_hyst[1] = reg & 0x0F;
+               data->temp_hyst[2] = reg >> 4;
+
+               /* Have to hardcode type, because temp1 is special */
+               reg  = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+               reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
+               if ((reg2 & 0x03) == 0x01)
+                       data->temp_type[0] = 6 /* PECI */;
+               else if ((reg2 & 0x03) == 0x02)
+                       data->temp_type[0] = 5 /* AMDSI */;
+               else
+                       data->temp_type[0] = (reg & 0x02) ? 2 : 4;
+
+               data->temp_type[1] = (reg & 0x04) ? 2 : 4;
+               data->temp_type[2] = (reg & 0x08) ? 2 : 4;
+
+               data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
+
+               data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
+
+               data->last_limits = jiffies;
+       }
+
+       /* Update every second */
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               data->temp_status = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP_STATUS);
+               data->temp_diode_open = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP_DIODE_OPEN);
+               for (nr = 0; nr < 3; nr++)
+                       data->temp[nr] = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP(nr));
+
+               data->fan_status = f71882fg_read8(data,
+                                               F71882FG_REG_FAN_STATUS);
+               for (nr = 0; nr < 4; nr++)
+                       data->fan[nr] = f71882fg_read16(data,
+                                               F71882FG_REG_FAN(nr));
+
+               data->in_status = f71882fg_read8(data,
+                                               F71882FG_REG_IN_STATUS);
+               for (nr = 0; nr < 9; nr++)
+                       data->in[nr] = f71882fg_read8(data,
+                                               F71882FG_REG_IN(nr));
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/* Sysfs Interface */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       int speed = fan_from_reg(data->fan[nr]);
+
+       if (speed == FAN_MIN_DETECT)
+               speed = 0;
+
+       return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       if (data->fan_beep & (1 << nr))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       int val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       if (val)
+               data->fan_beep |= 1 << nr;
+       else
+               data->fan_beep &= ~(1 << nr);
+
+       f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       if (data->fan_status & (1 << nr))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%d\n", data->in[nr] * 8);
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+
+       return sprintf(buf, "%d\n", data->in1_max * 8);
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int val = simple_strtoul(buf, NULL, 10) / 8;
+
+       if (val > 255)
+               val = 255;
+
+       mutex_lock(&data->update_lock);
+       f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
+       data->in1_max = val;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       if (data->in_beep & (1 << nr))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       int val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       if (val)
+               data->in_beep |= 1 << nr;
+       else
+               data->in_beep &= ~(1 << nr);
+
+       f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       if (data->in_status & (1 << nr))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%d\n", data->temp[nr] * 1000);
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       int val = simple_strtoul(buf, NULL, 10) / 1000;
+
+       if (val > 255)
+               val = 255;
+
+       mutex_lock(&data->update_lock);
+       f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
+       data->temp_high[nr] = val;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%d\n",
+               (data->temp_high[nr] - data->temp_hyst[nr]) * 1000);
+}
+
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       int val = simple_strtoul(buf, NULL, 10) / 1000;
+       ssize_t ret = count;
+
+       mutex_lock(&data->update_lock);
+
+       /* convert abs to relative and check */
+       val = data->temp_high[nr] - val;
+       if (val < 0 || val > 15) {
+               ret = -EINVAL;
+               goto store_temp_max_hyst_exit;
+       }
+
+       data->temp_hyst[nr] = val;
+
+       /* convert value to register contents */
+       switch (nr) {
+               case 0:
+                       val = val << 4;
+                       break;
+               case 1:
+                       val = val | (data->temp_hyst[2] << 4);
+                       break;
+               case 2:
+                       val = data->temp_hyst[1] | (val << 4);
+                       break;
+       }
+
+       f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 :
+               F71882FG_REG_TEMP_HYST1, val);
+
+store_temp_max_hyst_exit:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
+}
+
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       int val = simple_strtoul(buf, NULL, 10) / 1000;
+
+       if (val > 255)
+               val = 255;
+
+       mutex_lock(&data->update_lock);
+       f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
+       data->temp_ovt[nr] = val;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%d\n",
+               (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000);
+}
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%d\n", data->temp_type[nr]);
+}
+
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       if (data->temp_beep & (1 << (nr + 1)))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       int val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       if (val)
+               data->temp_beep |= 1 << (nr + 1);
+       else
+               data->temp_beep &= ~(1 << (nr + 1));
+
+       f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       if (data->temp_status & (1 << (nr + 1)))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int nr = to_sensor_dev_attr(devattr)->index;
+
+       if (data->temp_diode_open & (1 << (nr + 1)))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       return sprintf(buf, DRVNAME "\n");
+}
+
+
+static int __devinit f71882fg_probe(struct platform_device * pdev)
+{
+       struct f71882fg_data *data;
+       int err, i;
+       u8 start_reg;
+
+       if (!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL)))
+               return -ENOMEM;
+
+       data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+       mutex_init(&data->update_lock);
+       platform_set_drvdata(pdev, data);
+
+       /* Register sysfs interface files */
+       for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) {
+               err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]);
+               if (err)
+                       goto exit_unregister_sysfs;
+       }
+
+       start_reg = f71882fg_read8(data, F71882FG_REG_START);
+       if (start_reg & 0x01) {
+               for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) {
+                       err = device_create_file(&pdev->dev,
+                                       &f71882fg_in_temp_attr[i].dev_attr);
+                       if (err)
+                               goto exit_unregister_sysfs;
+               }
+       }
+
+       if (start_reg & 0x02) {
+               for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) {
+                       err = device_create_file(&pdev->dev,
+                                       &f71882fg_fan_attr[i].dev_attr);
+                       if (err)
+                               goto exit_unregister_sysfs;
+               }
+       }
+
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_unregister_sysfs;
+       }
+
+       return 0;
+
+exit_unregister_sysfs:
+       for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
+               device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
+
+       for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
+               device_remove_file(&pdev->dev,
+                                       &f71882fg_in_temp_attr[i].dev_attr);
+
+       for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
+               device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
+
+       kfree(data);
+
+       return err;
+}
+
+static int __devexit f71882fg_remove(struct platform_device *pdev)
+{
+       int i;
+       struct f71882fg_data *data = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       hwmon_device_unregister(data->hwmon_dev);
+
+       for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
+               device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
+
+       for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
+               device_remove_file(&pdev->dev,
+                                       &f71882fg_in_temp_attr[i].dev_attr);
+
+       for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
+               device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
+
+       kfree(data);
+
+       return 0;
+}
+
+static int __init f71882fg_find(int sioaddr, unsigned short *address)
+{
+       int err = -ENODEV;
+       u16 devid;
+       u8 start_reg;
+       struct f71882fg_data data;
+
+       superio_enter(sioaddr);
+
+       devid = superio_inw(sioaddr, SIO_REG_MANID);
+       if (devid != SIO_FINTEK_ID) {
+               printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
+               goto exit;
+       }
+
+       devid = superio_inw(sioaddr, SIO_REG_DEVID);
+       if (devid != SIO_F71882_ID) {
+               printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
+               goto exit;
+       }
+
+       superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+       if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+               printk(KERN_WARNING DRVNAME ": Device not activated\n");
+               goto exit;
+       }
+
+       *address = superio_inw(sioaddr, SIO_REG_ADDR);
+       if (*address == 0)
+       {
+               printk(KERN_WARNING DRVNAME ": Base address not set\n");
+               goto exit;
+       }
+       *address &= ~(REGION_LENGTH - 1);       /* Ignore 3 LSB */
+
+       data.addr = *address;
+       start_reg = f71882fg_read8(&data, F71882FG_REG_START);
+       if (!(start_reg & 0x03)) {
+               printk(KERN_WARNING DRVNAME
+                       ": Hardware monitoring not activated\n");
+               goto exit;
+       }
+
+       err = 0;
+       printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n",
+               (unsigned int)*address,
+               (int)superio_inb(sioaddr, SIO_REG_DEVREV));
+exit:
+       superio_exit(sioaddr);
+       return err;
+}
+
+static int __init f71882fg_device_add(unsigned short address)
+{
+       struct resource res = {
+               .start  = address,
+               .end    = address + REGION_LENGTH - 1,
+               .flags  = IORESOURCE_IO,
+       };
+       int err;
+
+       f71882fg_pdev = platform_device_alloc(DRVNAME, address);
+       if (!f71882fg_pdev)
+               return -ENOMEM;
+
+       res.name = f71882fg_pdev->name;
+       err = platform_device_add_resources(f71882fg_pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(f71882fg_pdev);
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Device addition failed\n");
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(f71882fg_pdev);
+
+       return err;
+}
+
+static int __init f71882fg_init(void)
+{
+       int err = -ENODEV;
+       unsigned short address;
+
+       if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address))
+               goto exit;
+
+       if ((err = platform_driver_register(&f71882fg_driver)))
+               goto exit;
+
+       if ((err = f71882fg_device_add(address)))
+               goto exit_driver;
+
+       return 0;
+
+exit_driver:
+       platform_driver_unregister(&f71882fg_driver);
+exit:
+       return err;
+}
+
+static void __exit f71882fg_exit(void)
+{
+       platform_device_unregister(f71882fg_pdev);
+       platform_driver_unregister(&f71882fg_driver);
+}
+
+MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
+MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)");
+MODULE_LICENSE("GPL");
+
+module_init(f71882fg_init);
+module_exit(f71882fg_exit);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
new file mode 100644 (file)
index 0000000..13a0413
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * f75375s.c - driver for the Fintek F75375/SP and F75373
+ *             hardware monitoring features
+ * Copyright (C) 2006-2007  Riku Voipio <riku.voipio@movial.fi>
+ *
+ * Datasheets available at:
+ *
+ * f75375:
+ * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf
+ *
+ * f75373:
+ * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_2(f75373, f75375);
+
+/* Fintek F75375 registers  */
+#define F75375_REG_CONFIG0             0x0
+#define F75375_REG_CONFIG1             0x1
+#define F75375_REG_CONFIG2             0x2
+#define F75375_REG_CONFIG3             0x3
+#define F75375_REG_ADDR                        0x4
+#define F75375_REG_INTR                        0x31
+#define F75375_CHIP_ID                 0x5A
+#define F75375_REG_VERSION             0x5C
+#define F75375_REG_VENDOR              0x5D
+#define F75375_REG_FAN_TIMER           0x60
+
+#define F75375_REG_VOLT(nr)            (0x10 + (nr))
+#define F75375_REG_VOLT_HIGH(nr)       (0x20 + (nr) * 2)
+#define F75375_REG_VOLT_LOW(nr)                (0x21 + (nr) * 2)
+
+#define F75375_REG_TEMP(nr)            (0x14 + (nr))
+#define F75375_REG_TEMP_HIGH(nr)       (0x28 + (nr) * 2)
+#define F75375_REG_TEMP_HYST(nr)       (0x29 + (nr) * 2)
+
+#define F75375_REG_FAN(nr)             (0x16 + (nr) * 2)
+#define F75375_REG_FAN_MIN(nr)         (0x2C + (nr) * 2)
+#define F75375_REG_FAN_FULL(nr)                (0x70 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_DUTY(nr)    (0x76 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_CLOCK(nr)   (0x7D + (nr) * 0x10)
+
+#define F75375_REG_FAN_EXP(nr)         (0x74 + (nr) * 0x10)
+#define F75375_REG_FAN_B_TEMP(nr, step)        ((0xA0 + (nr) * 0x10) + (step))
+#define F75375_REG_FAN_B_SPEED(nr, step) \
+       ((0xA5 + (nr) * 0x10) + (step) * 2)
+
+#define F75375_REG_PWM1_RAISE_DUTY     0x69
+#define F75375_REG_PWM2_RAISE_DUTY     0x6A
+#define F75375_REG_PWM1_DROP_DUTY      0x6B
+#define F75375_REG_PWM2_DROP_DUTY      0x6C
+
+#define FAN_CTRL_LINEAR(nr)            (4 + nr)
+#define FAN_CTRL_MODE(nr)              (5 + ((nr) * 2))
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct f75375_data {
+       unsigned short addr;
+       struct i2c_client client;
+       struct device *hwmon_dev;
+
+       const char *name;
+       int kind;
+       struct mutex update_lock; /* protect register access */
+       char valid;
+       unsigned long last_updated;     /* In jiffies */
+       unsigned long last_limits;      /* In jiffies */
+
+       /* Register values */
+       u8 in[4];
+       u8 in_max[4];
+       u8 in_min[4];
+       u16 fan[2];
+       u16 fan_min[2];
+       u16 fan_full[2];
+       u16 fan_exp[2];
+       u8 fan_timer;
+       u8 pwm[2];
+       u8 pwm_mode[2];
+       u8 pwm_enable[2];
+       s8 temp[2];
+       s8 temp_high[2];
+       s8 temp_max_hyst[2];
+};
+
+static int f75375_attach_adapter(struct i2c_adapter *adapter);
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
+static int f75375_detach_client(struct i2c_client *client);
+
+static struct i2c_driver f75375_driver = {
+       .driver = {
+               .name = "f75375",
+       },
+       .attach_adapter = f75375_attach_adapter,
+       .detach_client = f75375_detach_client,
+};
+
+static inline int f75375_read8(struct i2c_client *client, u8 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* in most cases, should be called while holding update_lock */
+static inline u16 f75375_read16(struct i2c_client *client, u8 reg)
+{
+       return ((i2c_smbus_read_byte_data(client, reg) << 8)
+               | i2c_smbus_read_byte_data(client, reg + 1));
+}
+
+static inline void f75375_write8(struct i2c_client *client, u8 reg,
+               u8 value)
+{
+       i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline void f75375_write16(struct i2c_client *client, u8 reg,
+               u16 value)
+{
+       int err = i2c_smbus_write_byte_data(client, reg, (value << 8));
+       if (err)
+               return;
+       i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
+}
+
+static struct f75375_data *f75375_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int nr;
+
+       mutex_lock(&data->update_lock);
+
+       /* Limit registers cache is refreshed after 60 seconds */
+       if (time_after(jiffies, data->last_limits + 60 * HZ)
+               || !data->valid) {
+               for (nr = 0; nr < 2; nr++) {
+                       data->temp_high[nr] =
+                               f75375_read8(client, F75375_REG_TEMP_HIGH(nr));
+                       data->temp_max_hyst[nr] =
+                               f75375_read8(client, F75375_REG_TEMP_HYST(nr));
+                       data->fan_full[nr] =
+                               f75375_read16(client, F75375_REG_FAN_FULL(nr));
+                       data->fan_min[nr] =
+                               f75375_read16(client, F75375_REG_FAN_MIN(nr));
+                       data->fan_exp[nr] =
+                               f75375_read16(client, F75375_REG_FAN_EXP(nr));
+                       data->pwm[nr] = f75375_read8(client,
+                               F75375_REG_FAN_PWM_DUTY(nr));
+
+               }
+               for (nr = 0; nr < 4; nr++) {
+                       data->in_max[nr] =
+                               f75375_read8(client, F75375_REG_VOLT_HIGH(nr));
+                       data->in_min[nr] =
+                               f75375_read8(client, F75375_REG_VOLT_LOW(nr));
+               }
+               data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER);
+               data->last_limits = jiffies;
+       }
+
+       /* Measurement registers cache is refreshed after 2 second */
+       if (time_after(jiffies, data->last_updated + 2 * HZ)
+               || !data->valid) {
+               for (nr = 0; nr < 2; nr++) {
+                       data->temp[nr] =
+                               f75375_read8(client, F75375_REG_TEMP(nr));
+                       data->fan[nr] =
+                               f75375_read16(client, F75375_REG_FAN(nr));
+               }
+               for (nr = 0; nr < 4; nr++)
+                       data->in[nr] =
+                               f75375_read8(client, F75375_REG_VOLT(nr));
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+       return data;
+}
+
+static inline u16 rpm_from_reg(u16 reg)
+{
+       if (reg == 0 || reg == 0xffff)
+               return 0;
+       return (1500000 / reg);
+}
+
+static inline u16 rpm_to_reg(int rpm)
+{
+       if (rpm < 367 || rpm > 0xffff)
+               return 0xffff;
+       return (1500000 / rpm);
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->fan_min[nr] = rpm_to_reg(val);
+       f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->fan_exp[nr] = rpm_to_reg(val);
+       f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_exp[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+       f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+               *attr, char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_enable[nr]);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtoul(buf, NULL, 10);
+       u8 fanmode;
+
+       if (val < 0 || val > 4)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
+       fanmode = ~(3 << FAN_CTRL_MODE(nr));
+
+       switch (val) {
+       case 0: /* Full speed */
+               fanmode  |= (3 << FAN_CTRL_MODE(nr));
+               data->pwm[nr] = 255;
+               f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
+                               data->pwm[nr]);
+               break;
+       case 1: /* PWM */
+               fanmode  |= (3 << FAN_CTRL_MODE(nr));
+               break;
+       case 2: /* AUTOMATIC*/
+               fanmode  |= (2 << FAN_CTRL_MODE(nr));
+               break;
+       case 3: /* fan speed */
+               break;
+       }
+       f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
+       data->pwm_enable[nr] = val;
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtoul(buf, NULL, 10);
+       u8 conf = 0;
+
+       if (val != 0 || val != 1 || data->kind == f75373)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       conf = f75375_read8(client, F75375_REG_CONFIG1);
+       conf = ~(1 << FAN_CTRL_LINEAR(nr));
+
+       if (val == 0)
+               conf |= (1 << FAN_CTRL_LINEAR(nr)) ;
+
+       f75375_write8(client, F75375_REG_CONFIG1, conf);
+       data->pwm_mode[nr] = val;
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute
+               *attr, char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm[nr]);
+}
+
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute
+               *attr, char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_mode[nr]);
+}
+
+#define VOLT_FROM_REG(val) ((val) * 8)
+#define VOLT_TO_REG(val) ((val) / 8)
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr]));
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtoul(buf, NULL, 10);
+       val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+       mutex_lock(&data->update_lock);
+       data->in_max[nr] = val;
+       f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtoul(buf, NULL, 10);
+       val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+       mutex_lock(&data->update_lock);
+       data->in_min[nr] = val;
+       f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+#define TEMP_FROM_REG(val) ((val) * 1000)
+#define TEMP_TO_REG(val) ((val) / 1000)
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct f75375_data *data = f75375_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtol(buf, NULL, 10);
+       val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+       mutex_lock(&data->update_lock);
+       data->temp_high[nr] = val;
+       f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t set_temp_max_hyst(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int val = simple_strtol(buf, NULL, 10);
+       val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+       mutex_lock(&data->update_lock);
+       data->temp_max_hyst[nr] = val;
+       f75375_write8(client, F75375_REG_TEMP_HYST(nr),
+               data->temp_max_hyst[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+#define show_fan(thing) \
+static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \
+                       char *buf)\
+{\
+       int nr = to_sensor_dev_attr(attr)->index;\
+       struct f75375_data *data = f75375_update_device(dev); \
+       return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \
+}
+
+show_fan(fan);
+show_fan(fan_min);
+show_fan(fan_full);
+show_fan(fan_exp);
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR,
+       show_in_max, set_in_max, 0);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR,
+       show_in_min, set_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR,
+       show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR,
+       show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR,
+       show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR,
+       show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR,
+       show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR,
+       show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR,
+       show_temp_max_hyst, set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,
+       show_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR,
+       show_temp_max_hyst, set_temp_max_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,
+       show_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_full, S_IRUGO, show_fan_full, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR,
+       show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan1_exp, S_IRUGO|S_IWUSR,
+       show_fan_exp, set_fan_exp, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_full, S_IRUGO, show_fan_full, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR,
+       show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_exp, S_IRUGO|S_IWUSR,
+       show_fan_exp, set_fan_exp, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,
+       show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR,
+       show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO|S_IWUSR,
+       show_pwm_mode, set_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
+       show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR,
+       show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO|S_IWUSR,
+       show_pwm_mode, set_pwm_mode, 1);
+
+static struct attribute *f75375_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_full.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_exp.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_full.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_exp.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group f75375_group = {
+       .attrs = f75375_attributes,
+};
+
+static int f75375_detach_client(struct i2c_client *client)
+{
+       struct f75375_data *data = i2c_get_clientdata(client);
+       int err;
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &f75375_group);
+
+       err = i2c_detach_client(client);
+       if (err) {
+               dev_err(&client->dev,
+                       "Client deregistration failed, "
+                       "client not detached.\n");
+               return err;
+       }
+       kfree(data);
+       return 0;
+}
+
+static int f75375_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_probe(adapter, &addr_data, f75375_detect);
+}
+
+/* This function is called by i2c_probe */
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       struct f75375_data *data;
+       u8 version = 0;
+       int err = 0;
+       const char *name = "";
+
+       if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &f75375_driver;
+
+       if (kind < 0) {
+               u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
+               u16 chipid = f75375_read16(client, F75375_CHIP_ID);
+               version = f75375_read8(client, F75375_REG_VERSION);
+               if (chipid == 0x0306 && vendid == 0x1934) {
+                       kind = f75375;
+               } else if (chipid == 0x0204 && vendid == 0x1934) {
+                       kind = f75373;
+               } else {
+                       dev_err(&adapter->dev,
+                               "failed,%02X,%02X,%02X\n",
+                               chipid, version, vendid);
+                       goto exit_free;
+               }
+       }
+
+       if (kind == f75375) {
+               name = "f75375";
+       } else if (kind == f75373) {
+               name = "f75373";
+       }
+
+       dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
+       strlcpy(client->name, name, I2C_NAME_SIZE);
+       data->kind = kind;
+       mutex_init(&data->update_lock);
+       if ((err = i2c_attach_client(client)))
+               goto exit_free;
+
+       if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
+               goto exit_detach;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+exit_remove:
+       sysfs_remove_group(&client->dev.kobj, &f75375_group);
+exit_detach:
+       i2c_detach_client(client);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int __init sensors_f75375_init(void)
+{
+       return i2c_add_driver(&f75375_driver);
+}
+
+static void __exit sensors_f75375_exit(void)
+{
+       i2c_del_driver(&f75375_driver);
+}
+
+MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver");
+
+module_init(sensors_f75375_init);
+module_exit(sensors_f75375_exit);
index b34b546c68b847486d5688edd021eaf17916ae22..e67c36953b2d8d2f46c9af5825be753f16da1855 100644 (file)
@@ -134,7 +134,7 @@ static struct i2c_driver fscher_driver = {
 
 struct fscher_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -344,9 +344,9 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -367,7 +367,7 @@ static int fscher_detach_client(struct i2c_client *client)
        struct fscher_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &fscher_group);
 
        if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
new file mode 100644 (file)
index 0000000..63a4df0
--- /dev/null
@@ -0,0 +1,778 @@
+/* fschmd.c
+ *
+ * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
+ *  Scylla, Heracles and Heimdall chips
+ *
+ *  Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
+ *  (candidate) fschmd drivers:
+ *  Copyright (C) 2006 Thilo Cestonaro
+ *                     <thilo.cestonaro.external@fujitsu-siemens.com>
+ *  Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
+ *  Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
+ *  Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de>
+ *  Copyright (C) 2000 Hermann Jung <hej@odn.de>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
+
+/*
+ * The FSCHMD registers and other defines
+ */
+
+/* chip identification */
+#define FSCHMD_REG_IDENT_0             0x00
+#define FSCHMD_REG_IDENT_1             0x01
+#define FSCHMD_REG_IDENT_2             0x02
+#define FSCHMD_REG_REVISION            0x03
+
+/* global control and status */
+#define FSCHMD_REG_EVENT_STATE         0x04
+#define FSCHMD_REG_CONTROL             0x05
+
+#define FSCHMD_CONTROL_ALERT_LED_MASK  0x01
+
+/* watchdog (support to be implemented) */
+#define FSCHMD_REG_WDOG_PRESET         0x28
+#define FSCHMD_REG_WDOG_STATE          0x23
+#define FSCHMD_REG_WDOG_CONTROL                0x21
+
+/* voltages, weird order is to keep the same order as the old drivers */
+static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
+
+/* minimum pwm at which the fan is driven (pwm can by increased depending on
+   the temp. Notice that for the scy some fans share there minimum speed.
+   Also notice that with the scy the sensor order is different then with the
+   other chips, this order was in the 2.4 driver and kept for consistency. */
+static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
+       { 0x55, 0x65 },                                 /* pos */
+       { 0x55, 0x65, 0xb5 },                           /* her */
+       { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 },         /* scy */
+       { 0x55, 0x65, 0xa5, 0xb5 },                     /* hrc */
+       { 0x55, 0x65, 0xa5, 0xb5, 0xc5 },               /* hmd */
+};
+
+/* actual fan speed */
+static const u8 FSCHMD_REG_FAN_ACT[5][6] = {
+       { 0x0e, 0x6b, 0xab },                           /* pos */
+       { 0x0e, 0x6b, 0xbb },                           /* her */
+       { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb },         /* scy */
+       { 0x0e, 0x6b, 0xab, 0xbb },                     /* hrc */
+       { 0x5b, 0x6b, 0xab, 0xbb, 0xcb },               /* hmd */
+};
+
+/* fan status registers */
+static const u8 FSCHMD_REG_FAN_STATE[5][6] = {
+       { 0x0d, 0x62, 0xa2 },                           /* pos */
+       { 0x0d, 0x62, 0xb2 },                           /* her */
+       { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 },         /* scy */
+       { 0x0d, 0x62, 0xa2, 0xb2 },                     /* hrc */
+       { 0x52, 0x62, 0xa2, 0xb2, 0xc2 },               /* hmd */
+};
+
+/* fan ripple / divider registers */
+static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
+       { 0x0f, 0x6f, 0xaf },                           /* pos */
+       { 0x0f, 0x6f, 0xbf },                           /* her */
+       { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf },         /* scy */
+       { 0x0f, 0x6f, 0xaf, 0xbf },                     /* hrc */
+       { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },               /* hmd */
+};
+
+static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
+
+/* Fan status register bitmasks */
+#define FSCHMD_FAN_ALARM_MASK          0x04 /* called fault by FSC! */
+#define FSCHMD_FAN_NOT_PRESENT_MASK    0x08 /* not documented */
+
+
+/* actual temperature registers */
+static const u8 FSCHMD_REG_TEMP_ACT[5][5] = {
+       { 0x64, 0x32, 0x35 },                           /* pos */
+       { 0x64, 0x32, 0x35 },                           /* her */
+       { 0x64, 0xD0, 0x32, 0x35 },                     /* scy */
+       { 0x64, 0x32, 0x35 },                           /* hrc */
+       { 0x70, 0x80, 0x90, 0xd0, 0xe0 },               /* hmd */
+};
+
+/* temperature state registers */
+static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
+       { 0x71, 0x81, 0x91 },                           /* pos */
+       { 0x71, 0x81, 0x91 },                           /* her */
+       { 0x71, 0xd1, 0x81, 0x91 },                     /* scy */
+       { 0x71, 0x81, 0x91 },                           /* hrc */
+       { 0x71, 0x81, 0x91, 0xd1, 0xe1 },               /* hmd */
+};
+
+/* temperature high limit registers, FSC does not document these. Proven to be
+   there with field testing on the fscher and fschrc, already supported / used
+   in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
+   at these addresses, but doesn't want to confirm they are the same as with
+   the fscher?? */
+static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
+       { 0, 0, 0 },                                    /* pos */
+       { 0x76, 0x86, 0x96 },                           /* her */
+       { 0x76, 0xd6, 0x86, 0x96 },                     /* scy */
+       { 0x76, 0x86, 0x96 },                           /* hrc */
+       { 0x76, 0x86, 0x96, 0xd6, 0xe6 },               /* hmd */
+};
+
+/* These were found through experimenting with an fscher, currently they are
+   not used, but we keep them around for future reference.
+static const u8 FSCHER_REG_TEMP_AUTOP1[] =     { 0x73, 0x83, 0x93 };
+static const u8 FSCHER_REG_TEMP_AUTOP2[] =     { 0x75, 0x85, 0x95 }; */
+
+static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
+
+/* temp status register bitmasks */
+#define FSCHMD_TEMP_WORKING_MASK       0x01
+#define FSCHMD_TEMP_ALERT_MASK         0x02
+/* there only really is an alarm if the sensor is working and alert == 1 */
+#define FSCHMD_TEMP_ALARM_MASK \
+       (FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK)
+
+/* our driver name */
+#define FSCHMD_NAME "fschmd"
+
+/*
+ * Functions declarations
+ */
+
+static int fschmd_attach_adapter(struct i2c_adapter *adapter);
+static int fschmd_detach_client(struct i2c_client *client);
+static struct fschmd_data *fschmd_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver fschmd_driver = {
+       .driver = {
+               .name   = FSCHMD_NAME,
+       },
+       .attach_adapter = fschmd_attach_adapter,
+       .detach_client  = fschmd_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct fschmd_data {
+       struct i2c_client client;
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       int kind;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* in jiffies */
+
+       /* register values */
+       u8 global_control;      /* global control register */
+       u8 volt[3];             /* 12, 5, battery voltage */
+       u8 temp_act[5];         /* temperature */
+       u8 temp_status[5];      /* status of sensor */
+       u8 temp_max[5];         /* high temp limit, notice: undocumented! */
+       u8 fan_act[6];          /* fans revolutions per second */
+       u8 fan_status[6];       /* fan status */
+       u8 fan_min[6];          /* fan min value for rps */
+       u8 fan_ripple[6];       /* divider for rps */
+};
+
+/*
+ * Sysfs attr show / store functions
+ */
+
+static ssize_t show_in_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       const int max_reading[3] = { 14200, 6600, 3300 };
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       return sprintf(buf, "%d\n", (data->volt[index] *
+               max_reading[index] + 128) / 255);
+}
+
+
+#define TEMP_FROM_REG(val)     (((val) - 128) * 1000)
+
+static ssize_t show_temp_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index]));
+}
+
+static ssize_t show_temp_max(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = dev_get_drvdata(dev);
+       long v = simple_strtol(buf, NULL, 10) / 1000;
+
+       v = SENSORS_LIMIT(v, -128, 127) + 128;
+
+       mutex_lock(&data->update_lock);
+       i2c_smbus_write_byte_data(&data->client,
+               FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
+       data->temp_max[index] = v;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_temp_fault(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       /* bit 0 set means sensor working ok, so no fault! */
+       if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK)
+               return sprintf(buf, "0\n");
+       else
+               return sprintf(buf, "1\n");
+}
+
+static ssize_t show_temp_alarm(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
+                       FSCHMD_TEMP_ALARM_MASK)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+
+#define RPM_FROM_REG(val)      ((val) * 60)
+
+static ssize_t show_fan_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       /* bits 2..7 reserved => mask with 3 */
+       return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
+}
+
+static ssize_t store_fan_div(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       u8 reg;
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = dev_get_drvdata(dev);
+       /* supported values: 2, 4, 8 */
+       unsigned long v = simple_strtoul(buf, NULL, 10);
+
+       switch (v) {
+       case 2: v = 1; break;
+       case 4: v = 2; break;
+       case 8: v = 3; break;
+       default:
+               dev_err(dev, "fan_div value %lu not supported. "
+                       "Choose one of 2, 4 or 8!\n", v);
+               return -EINVAL;
+       }
+
+       mutex_lock(&data->update_lock);
+
+       reg = i2c_smbus_read_byte_data(&data->client,
+               FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
+
+       /* bits 2..7 reserved => mask with 0x03 */
+       reg &= ~0x03;
+       reg |= v;
+
+       i2c_smbus_write_byte_data(&data->client,
+               FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
+
+       data->fan_ripple[index] = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_fan_fault(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+
+static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       int val = fschmd_update_device(dev)->fan_min[index];
+
+       /* 0 = allow turning off, 1-255 = 50-100% */
+       if (val)
+               val = val / 2 + 128;
+
+       return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct fschmd_data *data = dev_get_drvdata(dev);
+       unsigned long v = simple_strtoul(buf, NULL, 10);
+
+       /* register: 0 = allow turning off, 1-255 = 50-100% */
+       if (v) {
+               v = SENSORS_LIMIT(v, 128, 255);
+               v = (v - 128) * 2 + 1;
+       }
+
+       mutex_lock(&data->update_lock);
+
+       i2c_smbus_write_byte_data(&data->client,
+               FSCHMD_REG_FAN_MIN[data->kind][index], v);
+       data->fan_min[index] = v;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+
+/* The FSC hwmon family has the ability to force an attached alert led to flash
+   from software, we export this as an alert_led sysfs attr */
+static ssize_t show_alert_led(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct fschmd_data *data = fschmd_update_device(dev);
+
+       if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t store_alert_led(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count)
+{
+       u8 reg;
+       struct fschmd_data *data = dev_get_drvdata(dev);
+       unsigned long v = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+
+       reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL);
+
+       if (v)
+               reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
+       else
+               reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
+
+       i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg);
+
+       data->global_control = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static struct sensor_device_attribute fschmd_attr[] = {
+       SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
+       SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
+       SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
+       SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
+};
+
+static struct sensor_device_attribute fschmd_temp_attr[] = {
+       SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
+       SENSOR_ATTR(temp1_max,   0644, show_temp_max, store_temp_max, 0),
+       SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
+       SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
+       SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
+       SENSOR_ATTR(temp2_max,   0644, show_temp_max, store_temp_max, 1),
+       SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
+       SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
+       SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
+       SENSOR_ATTR(temp3_max,   0644, show_temp_max, store_temp_max, 2),
+       SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
+       SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
+       SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
+       SENSOR_ATTR(temp4_max,   0644, show_temp_max, store_temp_max, 3),
+       SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
+       SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
+       SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
+       SENSOR_ATTR(temp5_max,   0644, show_temp_max, store_temp_max, 4),
+       SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
+       SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
+};
+
+static struct sensor_device_attribute fschmd_fan_attr[] = {
+       SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
+       SENSOR_ATTR(fan1_div,   0644, show_fan_div, store_fan_div, 0),
+       SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
+       SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
+       SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 0),
+       SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
+       SENSOR_ATTR(fan2_div,   0644, show_fan_div, store_fan_div, 1),
+       SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
+       SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
+       SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 1),
+       SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
+       SENSOR_ATTR(fan3_div,   0644, show_fan_div, store_fan_div, 2),
+       SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
+       SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
+       SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 2),
+       SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
+       SENSOR_ATTR(fan4_div,   0644, show_fan_div, store_fan_div, 3),
+       SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
+       SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
+       SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 3),
+       SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
+       SENSOR_ATTR(fan5_div,   0644, show_fan_div, store_fan_div, 4),
+       SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
+       SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
+       SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 4),
+       SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
+       SENSOR_ATTR(fan6_div,   0644, show_fan_div, store_fan_div, 5),
+       SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
+       SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
+       SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+               store_pwm_auto_point1_pwm, 5),
+};
+
+
+/*
+ * Real code
+ */
+
+static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       struct fschmd_data *data;
+       u8 revision;
+       const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
+                                       "Heracles", "Heimdall" };
+       const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
+                                               "fschrc", "fschmd" };
+       int i, err = 0;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       /* OK. For now, we presume we have a valid client. We now create the
+        * client structure, even though we cannot fill it completely yet.
+        * But it allows us to access i2c_smbus_read_byte_data. */
+       if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL)))
+               return -ENOMEM;
+
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &fschmd_driver;
+       mutex_init(&data->update_lock);
+
+       /* Detect & Identify the chip */
+       if (kind <= 0) {
+               char id[4];
+
+               id[0] = i2c_smbus_read_byte_data(client,
+                               FSCHMD_REG_IDENT_0);
+               id[1] = i2c_smbus_read_byte_data(client,
+                               FSCHMD_REG_IDENT_1);
+               id[2] = i2c_smbus_read_byte_data(client,
+                               FSCHMD_REG_IDENT_2);
+               id[3] = '\0';
+
+               if (!strcmp(id, "PEG"))
+                       kind = fscpos;
+               else if (!strcmp(id, "HER"))
+                       kind = fscher;
+               else if (!strcmp(id, "SCY"))
+                       kind = fscscy;
+               else if (!strcmp(id, "HRC"))
+                       kind = fschrc;
+               else if (!strcmp(id, "HMD"))
+                       kind = fschmd;
+               else
+                       goto exit_free;
+       }
+
+       if (kind == fscpos) {
+               /* The Poseidon has hardwired temp limits, fill these
+                  in for the alarm resetting code */
+               data->temp_max[0] = 70 + 128;
+               data->temp_max[1] = 50 + 128;
+               data->temp_max[2] = 50 + 128;
+       }
+
+       /* i2c kind goes from 1-5, we want from 0-4 to address arrays */
+       data->kind = kind - 1;
+       strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(client)))
+               goto exit_free;
+
+       for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
+               err = device_create_file(&client->dev,
+                                       &fschmd_attr[i].dev_attr);
+               if (err)
+                       goto exit_detach;
+       }
+
+       for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
+               /* Poseidon doesn't have TEMP_LIMIT registers */
+               if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
+                               show_temp_max)
+                       continue;
+
+               err = device_create_file(&client->dev,
+                                       &fschmd_temp_attr[i].dev_attr);
+               if (err)
+                       goto exit_detach;
+       }
+
+       for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
+               /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
+               if (kind == fscpos &&
+                               !strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
+                                       "pwm3_auto_point1_pwm"))
+                       continue;
+
+               err = device_create_file(&client->dev,
+                                       &fschmd_fan_attr[i].dev_attr);
+               if (err)
+                       goto exit_detach;
+       }
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               data->hwmon_dev = NULL;
+               goto exit_detach;
+       }
+
+       revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
+       printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n",
+               names[data->kind], (int) revision);
+
+       return 0;
+
+exit_detach:
+       fschmd_detach_client(client); /* will also free data for us */
+       return err;
+
+exit_free:
+       kfree(data);
+       return err;
+}
+
+static int fschmd_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_probe(adapter, &addr_data, fschmd_detect);
+}
+
+static int fschmd_detach_client(struct i2c_client *client)
+{
+       struct fschmd_data *data = i2c_get_clientdata(client);
+       int i, err;
+
+       /* Check if registered in case we're called from fschmd_detect
+          to cleanup after an error */
+       if (data->hwmon_dev)
+               hwmon_device_unregister(data->hwmon_dev);
+
+       for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)
+               device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
+       for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
+               device_remove_file(&client->dev,
+                                       &fschmd_temp_attr[i].dev_attr);
+       for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
+               device_remove_file(&client->dev,
+                                       &fschmd_fan_attr[i].dev_attr);
+
+       if ((err = i2c_detach_client(client)))
+               return err;
+
+       kfree(data);
+       return 0;
+}
+
+static struct fschmd_data *fschmd_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct fschmd_data *data = i2c_get_clientdata(client);
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+
+               for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
+                       data->temp_act[i] = i2c_smbus_read_byte_data(client,
+                                       FSCHMD_REG_TEMP_ACT[data->kind][i]);
+                       data->temp_status[i] = i2c_smbus_read_byte_data(client,
+                                       FSCHMD_REG_TEMP_STATE[data->kind][i]);
+
+                       /* The fscpos doesn't have TEMP_LIMIT registers */
+                       if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
+                               data->temp_max[i] = i2c_smbus_read_byte_data(
+                                       client,
+                                       FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
+
+                       /* reset alarm if the alarm condition is gone,
+                          the chip doesn't do this itself */
+                       if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
+                                       FSCHMD_TEMP_ALARM_MASK &&
+                                       data->temp_act[i] < data->temp_max[i])
+                               i2c_smbus_write_byte_data(client,
+                                       FSCHMD_REG_TEMP_STATE[data->kind][i],
+                                       FSCHMD_TEMP_ALERT_MASK);
+               }
+
+               for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
+                       data->fan_act[i] = i2c_smbus_read_byte_data(client,
+                                       FSCHMD_REG_FAN_ACT[data->kind][i]);
+                       data->fan_status[i] = i2c_smbus_read_byte_data(client,
+                                       FSCHMD_REG_FAN_STATE[data->kind][i]);
+                       data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
+                                       FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
+
+                       /* The fscpos third fan doesn't have a fan_min */
+                       if (FSCHMD_REG_FAN_MIN[data->kind][i])
+                               data->fan_min[i] = i2c_smbus_read_byte_data(
+                                       client,
+                                       FSCHMD_REG_FAN_MIN[data->kind][i]);
+
+                       /* reset fan status if speed is back to > 0 */
+                       if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) &&
+                                       data->fan_act[i])
+                               i2c_smbus_write_byte_data(client,
+                                       FSCHMD_REG_FAN_STATE[data->kind][i],
+                                       FSCHMD_FAN_ALARM_MASK);
+               }
+
+               for (i = 0; i < 3; i++)
+                       data->volt[i] = i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_VOLT[i]);
+
+               data->global_control = i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_CONTROL);
+
+               /* To be implemented in the future
+               data->watchdog[0] = i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_WDOG_PRESET);
+               data->watchdog[1] = i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_WDOG_STATE);
+               data->watchdog[2] = i2c_smbus_read_byte_data(client,
+                                               FSCHMD_REG_WDOG_CONTROL); */
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+static int __init fschmd_init(void)
+{
+       return i2c_add_driver(&fschmd_driver);
+}
+
+static void __exit fschmd_exit(void)
+{
+       i2c_del_driver(&fschmd_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
+                       "Heimdall driver");
+MODULE_LICENSE("GPL");
+
+module_init(fschmd_init);
+module_exit(fschmd_exit);
index ea506a77f9c9d25f701b5cc222c471439f56ca6a..92c9703d0ac0d16ee0d576f796f626a4fac170c3 100644 (file)
@@ -115,7 +115,7 @@ static struct i2c_driver fscpos_driver = {
  */
 struct fscpos_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;             /* 0 until following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -539,9 +539,9 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -562,7 +562,7 @@ static int fscpos_detach_client(struct i2c_client *client)
        struct fscpos_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &fscpos_group);
 
        if ((err = i2c_detach_client(client)))
index c103640455a324614f253c741807d34de7e31af7..bb58d9866a3774b996481b224f8ec7e81075b5ba 100644 (file)
@@ -119,7 +119,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 /* Each client has this additional data */
 struct gl518_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        enum chips type;
 
        struct mutex update_lock;
@@ -460,9 +460,9 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -502,7 +502,7 @@ static int gl518_detach_client(struct i2c_client *client)
        struct gl518_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &gl518_group);
 
        if ((err = i2c_detach_client(client)))
index ebe7b9aaa91696f092bda00593400f4a1215ab27..a3b56c816e11d3924c98698f6978802c27e6fc29 100644 (file)
@@ -122,7 +122,7 @@ static struct i2c_driver gl520_driver = {
 /* Client data */
 struct gl520_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;             /* zero until the following fields are valid */
        unsigned long last_updated;     /* in jiffies */
@@ -622,9 +622,9 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
        }
 
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -685,7 +685,7 @@ static int gl520_detach_client(struct i2c_client *client)
        struct gl520_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &gl520_group);
        sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
 
index affcc00764d3d207cf2225240802a5255b2a7d9c..3db28450a3b34504facc27cc8a9611a8e53569cd 100644 (file)
@@ -28,17 +28,17 @@ static DEFINE_IDR(hwmon_idr);
 static DEFINE_SPINLOCK(idr_lock);
 
 /**
- * hwmon_device_register - register w/ hwmon sysfs class
+ * hwmon_device_register - register w/ hwmon
  * @dev: the device to register
  *
- * hwmon_device_unregister() must be called when the class device is no
+ * hwmon_device_unregister() must be called when the device is no
  * longer needed.
  *
- * Returns the pointer to the new struct class device.
+ * Returns the pointer to the new device.
  */
-struct class_device *hwmon_device_register(struct device *dev)
+struct device *hwmon_device_register(struct device *dev)
 {
-       struct class_device *cdev;
+       struct device *hwdev;
        int id, err;
 
 again:
@@ -55,34 +55,33 @@ again:
                return ERR_PTR(err);
 
        id = id & MAX_ID_MASK;
-       cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev,
-                                       HWMON_ID_FORMAT, id);
+       hwdev = device_create(hwmon_class, dev, MKDEV(0,0), HWMON_ID_FORMAT, id);
 
-       if (IS_ERR(cdev)) {
+       if (IS_ERR(hwdev)) {
                spin_lock(&idr_lock);
                idr_remove(&hwmon_idr, id);
                spin_unlock(&idr_lock);
        }
 
-       return cdev;
+       return hwdev;
 }
 
 /**
  * hwmon_device_unregister - removes the previously registered class device
  *
- * @cdev: the class device to destroy
+ * @dev: the class device to destroy
  */
-void hwmon_device_unregister(struct class_device *cdev)
+void hwmon_device_unregister(struct device *dev)
 {
        int id;
 
-       if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) {
-               class_device_unregister(cdev);
+       if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) {
+               device_unregister(dev);
                spin_lock(&idr_lock);
                idr_remove(&hwmon_idr, id);
                spin_unlock(&idr_lock);
        } else
-               dev_dbg(cdev->dev,
+               dev_dbg(dev->parent,
                        "hwmon_device_unregister() failed: bad class ID!\n");
 }
 
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
new file mode 100644 (file)
index 0000000..c462824
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * A hwmon driver for the IBM PowerExecutive temperature/power sensors
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/ipmi.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+
+#define REFRESH_INTERVAL       (2 * HZ)
+#define DRVNAME                        "ibmpex"
+
+#define PEX_GET_VERSION                1
+#define PEX_GET_SENSOR_COUNT   2
+#define PEX_GET_SENSOR_NAME    3
+#define PEX_RESET_HIGH_LOW     4
+#define PEX_GET_SENSOR_DATA    6
+
+#define PEX_NET_FUNCTION       0x3A
+#define PEX_COMMAND            0x3C
+
+static inline u16 extract_value(const char *data, int offset)
+{
+       return be16_to_cpup((u16 *)&data[offset]);
+}
+
+#define TEMP_SENSOR            1
+#define POWER_SENSOR           2
+
+#define PEX_SENSOR_TYPE_LEN    3
+static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72};
+static u8 const temp_sensor_sig[]  = {0x74, 0x65, 0x6D};
+
+#define PEX_MULT_LEN           2
+static u8 const watt_sensor_sig[]  = {0x41, 0x43};
+
+#define PEX_NUM_SENSOR_FUNCS   3
+static char const * const power_sensor_name_templates[] = {
+       "%s%d_average",
+       "%s%d_average_lowest",
+       "%s%d_average_highest"
+};
+static char const * const temp_sensor_name_templates[] = {
+       "%s%d_input",
+       "%s%d_input_lowest",
+       "%s%d_input_highest"
+};
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+static void ibmpex_register_bmc(int iface, struct device *dev);
+static void ibmpex_bmc_gone(int iface);
+
+struct ibmpex_sensor_data {
+       int                     in_use;
+       s16                     values[PEX_NUM_SENSOR_FUNCS];
+       int                     multiplier;
+
+       struct sensor_device_attribute_2        attr[PEX_NUM_SENSOR_FUNCS];
+};
+
+struct ibmpex_bmc_data {
+       struct list_head        list;
+       struct device           *hwmon_dev;
+       struct device           *bmc_device;
+       struct mutex            lock;
+       char                    valid;
+       unsigned long           last_updated;   /* In jiffies */
+
+       struct ipmi_addr        address;
+       struct completion       read_complete;
+       ipmi_user_t             user;
+       int                     interface;
+
+       struct kernel_ipmi_msg  tx_message;
+       unsigned char           tx_msg_data[IPMI_MAX_MSG_LENGTH];
+       long                    tx_msgid;
+
+       unsigned char           rx_msg_data[IPMI_MAX_MSG_LENGTH];
+       unsigned long           rx_msg_len;
+       unsigned char           rx_result;
+       int                     rx_recv_type;
+
+       unsigned char           sensor_major;
+       unsigned char           sensor_minor;
+
+       unsigned char           num_sensors;
+       struct ibmpex_sensor_data       *sensors;
+};
+
+struct ibmpex_driver_data {
+       struct list_head        bmc_data;
+       struct ipmi_smi_watcher bmc_events;
+       struct ipmi_user_hndl   ipmi_hndlrs;
+};
+
+static struct ibmpex_driver_data driver_data = {
+       .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data),
+       .bmc_events = {
+               .owner = THIS_MODULE,
+               .new_smi = ibmpex_register_bmc,
+               .smi_gone = ibmpex_bmc_gone,
+       },
+       .ipmi_hndlrs = {
+               .ipmi_recv_hndl = ibmpex_msg_handler,
+       },
+};
+
+static int ibmpex_send_message(struct ibmpex_bmc_data *data)
+{
+       int err;
+
+       err = ipmi_validate_addr(&data->address, sizeof(data->address));
+       if (err)
+               goto out;
+
+       data->tx_msgid++;
+       err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
+                                  &data->tx_message, data, 0, 0, 0);
+       if (err)
+               goto out1;
+
+       return 0;
+out1:
+       printk(KERN_ERR "%s: request_settime=%x\n", __FUNCTION__, err);
+       return err;
+out:
+       printk(KERN_ERR "%s: validate_addr=%x\n", __FUNCTION__, err);
+       return err;
+}
+
+static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
+{
+       data->tx_msg_data[0] = PEX_GET_VERSION;
+       data->tx_message.data_len = 1;
+       ibmpex_send_message(data);
+
+       wait_for_completion(&data->read_complete);
+
+       if (data->rx_result || data->rx_msg_len != 6)
+               return -ENOENT;
+
+       data->sensor_major = data->rx_msg_data[0];
+       data->sensor_minor = data->rx_msg_data[1];
+
+       printk(KERN_INFO DRVNAME ": Found BMC with sensor interface "
+              "v%d.%d %d-%02d-%02d on interface %d\n",
+              data->sensor_major,
+              data->sensor_minor,
+              extract_value(data->rx_msg_data, 2),
+              data->rx_msg_data[4],
+              data->rx_msg_data[5],
+              data->interface);
+
+       return 0;
+}
+
+static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data)
+{
+       data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT;
+       data->tx_message.data_len = 1;
+       ibmpex_send_message(data);
+
+       wait_for_completion(&data->read_complete);
+
+       if (data->rx_result || data->rx_msg_len != 1)
+               return -ENOENT;
+
+       return data->rx_msg_data[0];
+}
+
+static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor)
+{
+       data->tx_msg_data[0] = PEX_GET_SENSOR_NAME;
+       data->tx_msg_data[1] = sensor;
+       data->tx_message.data_len = 2;
+       ibmpex_send_message(data);
+
+       wait_for_completion(&data->read_complete);
+
+       if (data->rx_result || data->rx_msg_len < 1)
+               return -ENOENT;
+
+       return 0;
+}
+
+static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor)
+{
+       data->tx_msg_data[0] = PEX_GET_SENSOR_DATA;
+       data->tx_msg_data[1] = sensor;
+       data->tx_message.data_len = 2;
+       ibmpex_send_message(data);
+
+       wait_for_completion(&data->read_complete);
+
+       if (data->rx_result || data->rx_msg_len < 26) {
+               printk(KERN_ERR "Error reading sensor %d, please check.\n",
+                      sensor);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data)
+{
+       data->tx_msg_data[0] = PEX_RESET_HIGH_LOW;
+       data->tx_message.data_len = 1;
+       ibmpex_send_message(data);
+
+       wait_for_completion(&data->read_complete);
+
+       return 0;
+}
+
+static void ibmpex_update_device(struct ibmpex_bmc_data *data)
+{
+       int i, err;
+
+       mutex_lock(&data->lock);
+       if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+           data->valid)
+               goto out;
+
+       for (i = 0; i < data->num_sensors; i++) {
+               if (!data->sensors[i].in_use)
+                       continue;
+               err = ibmpex_query_sensor_data(data, i);
+               if (err)
+                       continue;
+               data->sensors[i].values[0] =
+                       extract_value(data->rx_msg_data, 16);
+               data->sensors[i].values[1] =
+                       extract_value(data->rx_msg_data, 18);
+               data->sensors[i].values[2] =
+                       extract_value(data->rx_msg_data, 20);
+       }
+
+       data->last_updated = jiffies;
+       data->valid = 1;
+
+out:
+       mutex_unlock(&data->lock);
+}
+
+static struct ibmpex_bmc_data *get_bmc_data(int iface)
+{
+       struct ibmpex_bmc_data *p, *next;
+
+       list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+               if (p->interface == iface)
+                       return p;
+
+       return NULL;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       return sprintf(buf, "%s\n", DRVNAME);
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static ssize_t ibmpex_show_sensor(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+       int mult = data->sensors[attr->index].multiplier;
+       ibmpex_update_device(data);
+
+       return sprintf(buf, "%d\n",
+                      data->sensors[attr->index].values[attr->nr] * mult);
+}
+
+static ssize_t ibmpex_reset_high_low(struct device *dev,
+                                    struct device_attribute *devattr,
+                                    const char *buf,
+                                    size_t count)
+{
+       struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+
+       ibmpex_reset_high_low_data(data);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(reset_high_low, S_IWUSR, NULL,
+                         ibmpex_reset_high_low, 0);
+
+static int is_power_sensor(const char *sensor_id, int len)
+{
+       if (len < PEX_SENSOR_TYPE_LEN)
+               return 0;
+
+       if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN))
+               return 1;
+       return 0;
+}
+
+static int is_temp_sensor(const char *sensor_id, int len)
+{
+       if (len < PEX_SENSOR_TYPE_LEN)
+               return 0;
+
+       if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN))
+               return 1;
+       return 0;
+}
+
+static int power_sensor_multiplier(const char *sensor_id, int len)
+{
+       int i;
+
+       for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++)
+               if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN))
+                       return 1000000;
+
+       return 100000;
+}
+
+static int create_sensor(struct ibmpex_bmc_data *data, int type,
+                        int counter, int sensor, int func)
+{
+       int err;
+       char *n;
+
+       n = kmalloc(32, GFP_KERNEL);
+       if (!n)
+               return -ENOMEM;
+
+       if (type == TEMP_SENSOR)
+               sprintf(n, temp_sensor_name_templates[func], "temp", counter);
+       else if (type == POWER_SENSOR)
+               sprintf(n, power_sensor_name_templates[func], "power", counter);
+
+       data->sensors[sensor].attr[func].dev_attr.attr.name = n;
+       data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO;
+       data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;
+       data->sensors[sensor].attr[func].index = sensor;
+       data->sensors[sensor].attr[func].nr = func;
+
+       err = device_create_file(data->bmc_device,
+                                &data->sensors[sensor].attr[func].dev_attr);
+       if (err) {
+               data->sensors[sensor].attr[func].dev_attr.attr.name = NULL;
+               kfree(n);
+               return err;
+       }
+
+       return 0;
+}
+
+static int ibmpex_find_sensors(struct ibmpex_bmc_data *data)
+{
+       int i, j, err;
+       int sensor_type;
+       int sensor_counter;
+       int num_power = 0;
+       int num_temp = 0;
+
+       err = ibmpex_query_sensor_count(data);
+       if (err <= 0)
+               return -ENOENT;
+       data->num_sensors = err;
+
+       data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors),
+                               GFP_KERNEL);
+       if (!data->sensors)
+               return -ENOMEM;
+
+       for (i = 0; i < data->num_sensors; i++) {
+               err = ibmpex_query_sensor_name(data, i);
+               if (err)
+                       continue;
+
+               if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) {
+                       sensor_type = POWER_SENSOR;
+                       num_power++;
+                       sensor_counter = num_power;
+                       data->sensors[i].multiplier =
+                               power_sensor_multiplier(data->rx_msg_data,
+                                                    data->rx_msg_len);
+               } else if (is_temp_sensor(data->rx_msg_data,
+                                         data->rx_msg_len)) {
+                       sensor_type = TEMP_SENSOR;
+                       num_temp++;
+                       sensor_counter = num_temp;
+                       data->sensors[i].multiplier = 1;
+               } else
+                       continue;
+
+               data->sensors[i].in_use = 1;
+
+               /* Create attributes */
+               for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+                       err = create_sensor(data, sensor_type, sensor_counter,
+                                           i, j);
+                       if (err)
+                               goto exit_remove;
+               }
+       }
+
+       err = device_create_file(data->bmc_device,
+                       &sensor_dev_attr_reset_high_low.dev_attr);
+       if (err)
+               goto exit_remove;
+
+       err = device_create_file(data->bmc_device,
+                       &sensor_dev_attr_name.dev_attr);
+       if (err)
+               goto exit_remove;
+
+       return 0;
+
+exit_remove:
+       device_remove_file(data->bmc_device,
+                          &sensor_dev_attr_reset_high_low.dev_attr);
+       device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+       for (i = 0; i < data->num_sensors; i++)
+               for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+                       if (!data->sensors[i].attr[j].dev_attr.attr.name)
+                               continue;
+                       device_remove_file(data->bmc_device,
+                               &data->sensors[i].attr[j].dev_attr);
+                       kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+               }
+
+       kfree(data->sensors);
+       return err;
+}
+
+static void ibmpex_register_bmc(int iface, struct device *dev)
+{
+       struct ibmpex_bmc_data *data;
+       int err;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               printk(KERN_ERR DRVNAME ": Insufficient memory for BMC "
+                      "interface %d.\n", data->interface);
+               return;
+       }
+
+       data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+       data->address.channel = IPMI_BMC_CHANNEL;
+       data->address.data[0] = 0;
+       data->interface = iface;
+       data->bmc_device = dev;
+
+       /* Create IPMI messaging interface user */
+       err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
+                              data, &data->user);
+       if (err < 0) {
+               printk(KERN_ERR DRVNAME ": Error, unable to register user with "
+                      "ipmi interface %d\n",
+                      data->interface);
+               goto out;
+       }
+
+       mutex_init(&data->lock);
+
+       /* Initialize message */
+       data->tx_msgid = 0;
+       init_completion(&data->read_complete);
+       data->tx_message.netfn = PEX_NET_FUNCTION;
+       data->tx_message.cmd = PEX_COMMAND;
+       data->tx_message.data = data->tx_msg_data;
+
+       /* Does this BMC support PowerExecutive? */
+       err = ibmpex_ver_check(data);
+       if (err)
+               goto out_user;
+
+       /* Register the BMC as a HWMON class device */
+       data->hwmon_dev = hwmon_device_register(data->bmc_device);
+
+       if (IS_ERR(data->hwmon_dev)) {
+               printk(KERN_ERR DRVNAME ": Error, unable to register hwmon "
+                      "class device for interface %d\n",
+                      data->interface);
+               goto out_user;
+       }
+
+       /* finally add the new bmc data to the bmc data list */
+       dev_set_drvdata(dev, data);
+       list_add_tail(&data->list, &driver_data.bmc_data);
+
+       /* Now go find all the sensors */
+       err = ibmpex_find_sensors(data);
+       if (err) {
+               printk(KERN_ERR "Error %d allocating memory\n", err);
+               goto out_register;
+       }
+
+       return;
+
+out_register:
+       hwmon_device_unregister(data->hwmon_dev);
+out_user:
+       ipmi_destroy_user(data->user);
+out:
+       kfree(data);
+}
+
+static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
+{
+       int i, j;
+
+       device_remove_file(data->bmc_device,
+                          &sensor_dev_attr_reset_high_low.dev_attr);
+       device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+       for (i = 0; i < data->num_sensors; i++)
+               for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+                       if (!data->sensors[i].attr[j].dev_attr.attr.name)
+                               continue;
+                       device_remove_file(data->bmc_device,
+                               &data->sensors[i].attr[j].dev_attr);
+                       kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+               }
+
+       list_del(&data->list);
+       dev_set_drvdata(data->bmc_device, NULL);
+       hwmon_device_unregister(data->hwmon_dev);
+       ipmi_destroy_user(data->user);
+       kfree(data->sensors);
+       kfree(data);
+}
+
+static void ibmpex_bmc_gone(int iface)
+{
+       struct ibmpex_bmc_data *data = get_bmc_data(iface);
+
+       if (!data)
+               return;
+
+       ibmpex_bmc_delete(data);
+}
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+       struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
+
+       if (msg->msgid != data->tx_msgid) {
+               printk(KERN_ERR "Received msgid (%02x) and transmitted "
+                      "msgid (%02x) mismatch!\n",
+                      (int)msg->msgid,
+                      (int)data->tx_msgid);
+               ipmi_free_recv_msg(msg);
+               return;
+       }
+
+       data->rx_recv_type = msg->recv_type;
+       if (msg->msg.data_len > 0)
+               data->rx_result = msg->msg.data[0];
+       else
+               data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
+
+       if (msg->msg.data_len > 1) {
+               data->rx_msg_len = msg->msg.data_len - 1;
+               memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
+       } else
+               data->rx_msg_len = 0;
+
+       ipmi_free_recv_msg(msg);
+       complete(&data->read_complete);
+}
+
+static int __init ibmpex_init(void)
+{
+       return ipmi_smi_watcher_register(&driver_data.bmc_events);
+}
+
+static void __exit ibmpex_exit(void)
+{
+       struct ibmpex_bmc_data *p, *next;
+
+       ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+       list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+               ibmpex_bmc_delete(p);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(ibmpex_init);
+module_exit(ibmpex_exit);
index d75dba9b810b3aa81b80afc489fd22e11ae1b101..6a182e14cf589d59f7a5d8e244b8aa9c34c0409d 100644 (file)
@@ -141,10 +141,10 @@ static int fix_pwm_polarity;
 
 /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
 
-#define IT87_REG_FAN(nr)       (0x0d + (nr))
-#define IT87_REG_FAN_MIN(nr)   (0x10 + (nr))
-#define IT87_REG_FANX(nr)      (0x18 + (nr))
-#define IT87_REG_FANX_MIN(nr)  (0x1b + (nr))
+static const u8 IT87_REG_FAN[]         = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
+static const u8 IT87_REG_FAN_MIN[]     = { 0x10, 0x11, 0x12, 0x84, 0x86 };
+static const u8 IT87_REG_FANX[]                = { 0x18, 0x19, 0x1a, 0x81, 0x83 };
+static const u8 IT87_REG_FANX_MIN[]    = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
 #define IT87_REG_FAN_MAIN_CTRL 0x13
 #define IT87_REG_FAN_CTL       0x14
 #define IT87_REG_PWM(nr)       (0x15 + (nr))
@@ -222,7 +222,7 @@ struct it87_sio_data {
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct it87_data {
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        enum chips type;
 
        unsigned short addr;
@@ -235,8 +235,8 @@ struct it87_data {
        u8 in_max[8];           /* Register value */
        u8 in_min[8];           /* Register value */
        u8 has_fan;             /* Bitfield, fans enabled */
-       u16 fan[3];             /* Register values, possibly combined */
-       u16 fan_min[3];         /* Register values, possibly combined */
+       u16 fan[5];             /* Register values, possibly combined */
+       u16 fan_min[5];         /* Register values, possibly combined */
        u8 temp[3];             /* Register value */
        u8 temp_high[3];        /* Register value */
        u8 temp_low[3];         /* Register value */
@@ -555,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
        }
 
        data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-       it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+       it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -596,7 +596,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 
        /* Restore fan min limit */
        data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-       it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+       it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
 
        mutex_unlock(&data->update_lock);
        return count;
@@ -729,9 +729,9 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
 
        mutex_lock(&data->update_lock);
        data->fan_min[nr] = FAN16_TO_REG(val);
-       it87_write_value(data, IT87_REG_FAN_MIN(nr),
+       it87_write_value(data, IT87_REG_FAN_MIN[nr],
                         data->fan_min[nr] & 0xff);
-       it87_write_value(data, IT87_REG_FANX_MIN(nr),
+       it87_write_value(data, IT87_REG_FANX_MIN[nr],
                         data->fan_min[nr] >> 8);
        mutex_unlock(&data->update_lock);
        return count;
@@ -751,6 +751,8 @@ static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
 show_fan16_offset(1);
 show_fan16_offset(2);
 show_fan16_offset(3);
+show_fan16_offset(4);
+show_fan16_offset(5);
 
 /* Alarms */
 static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
@@ -763,7 +765,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 static ssize_t
 show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct it87_data *data = it87_update_device(dev);
+       struct it87_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%u\n", data->vrm);
 }
 static ssize_t
@@ -851,6 +853,10 @@ static struct attribute *it87_attributes_opt[] = {
        &sensor_dev_attr_fan2_min16.dev_attr.attr,
        &sensor_dev_attr_fan3_input16.dev_attr.attr,
        &sensor_dev_attr_fan3_min16.dev_attr.attr,
+       &sensor_dev_attr_fan4_input16.dev_attr.attr,
+       &sensor_dev_attr_fan4_min16.dev_attr.attr,
+       &sensor_dev_attr_fan5_input16.dev_attr.attr,
+       &sensor_dev_attr_fan5_min16.dev_attr.attr,
 
        &sensor_dev_attr_fan1_input.dev_attr.attr,
        &sensor_dev_attr_fan1_min.dev_attr.attr,
@@ -1024,6 +1030,20 @@ static int __devinit it87_probe(struct platform_device *pdev)
                             &sensor_dev_attr_fan3_min16.dev_attr)))
                                goto ERROR4;
                }
+               if (data->has_fan & (1 << 3)) {
+                       if ((err = device_create_file(dev,
+                            &sensor_dev_attr_fan4_input16.dev_attr))
+                        || (err = device_create_file(dev,
+                            &sensor_dev_attr_fan4_min16.dev_attr)))
+                               goto ERROR4;
+               }
+               if (data->has_fan & (1 << 4)) {
+                       if ((err = device_create_file(dev,
+                            &sensor_dev_attr_fan5_input16.dev_attr))
+                        || (err = device_create_file(dev,
+                            &sensor_dev_attr_fan5_min16.dev_attr)))
+                               goto ERROR4;
+               }
        } else {
                /* 8-bit tachometers with clock divider */
                if (data->has_fan & (1 << 0)) {
@@ -1089,9 +1109,9 @@ static int __devinit it87_probe(struct platform_device *pdev)
                        goto ERROR4;
        }
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto ERROR4;
        }
 
@@ -1113,7 +1133,7 @@ static int __devexit it87_remove(struct platform_device *pdev)
 {
        struct it87_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &it87_group);
        sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
 
@@ -1260,6 +1280,10 @@ static void __devinit it87_init_device(struct platform_device *pdev)
                        it87_write_value(data, IT87_REG_FAN_16BIT,
                                         tmp | 0x07);
                }
+               if (tmp & (1 << 4))
+                       data->has_fan |= (1 << 3);      /* fan4 enabled */
+               if (tmp & (1 << 5))
+                       data->has_fan |= (1 << 4);      /* fan5 enabled */
        }
 
        /* Set current fan mode registers and the default settings for the
@@ -1314,21 +1338,21 @@ static struct it87_data *it87_update_device(struct device *dev)
                data->in[8] =
                    it87_read_value(data, IT87_REG_VIN(8));
 
-               for (i = 0; i < 3; i++) {
+               for (i = 0; i < 5; i++) {
                        /* Skip disabled fans */
                        if (!(data->has_fan & (1 << i)))
                                continue;
 
                        data->fan_min[i] =
-                           it87_read_value(data, IT87_REG_FAN_MIN(i));
+                           it87_read_value(data, IT87_REG_FAN_MIN[i]);
                        data->fan[i] = it87_read_value(data,
-                                      IT87_REG_FAN(i));
+                                      IT87_REG_FAN[i]);
                        /* Add high byte if in 16-bit mode */
                        if (data->type == it8716 || data->type == it8718) {
                                data->fan[i] |= it87_read_value(data,
-                                               IT87_REG_FANX(i)) << 8;
+                                               IT87_REG_FANX[i]) << 8;
                                data->fan_min[i] |= it87_read_value(data,
-                                               IT87_REG_FANX_MIN(i)) << 8;
+                                               IT87_REG_FANX_MIN[i]) << 8;
                        }
                }
                for (i = 0; i < 3; i++) {
index 5d8d0ca08fa9a344f58f7e3d8f8984fa5ae78a87..bd2bde0ef95e4c4b411bc1682c2c0243be55c22f 100644 (file)
@@ -38,7 +38,7 @@
 #define SEL_CORE       0x04
 
 struct k8temp_data {
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        const char *name;
        char valid;             /* zero until following fields are valid */
@@ -225,10 +225,10 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
        if (err)
                goto exit_remove;
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
 
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -255,7 +255,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
 {
        struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        device_remove_file(&pdev->dev,
                           &sensor_dev_attr_temp1_input.dev_attr);
        device_remove_file(&pdev->dev,
index 2162d69a8c0658144dfc7538e174b6523d5d874d..f207434730de66f472d7e6203e4eb31b1752827d 100644 (file)
@@ -154,7 +154,7 @@ static struct i2c_driver lm63_driver = {
 
 struct lm63_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -502,9 +502,9 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
                        goto exit_remove_files;
        }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -561,7 +561,7 @@ static int lm63_detach_client(struct i2c_client *client)
        struct lm63_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm63_group);
        sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
 
index 275d392eca6116d62461db1f16b6468655af3c2e..dd366889ce9b8038c2e59342a70b8c7d340c818b 100644 (file)
@@ -37,7 +37,7 @@
 #define DRVNAME                "lm70"
 
 struct lm70 {
-       struct class_device *cdev;
+       struct device *hwmon_dev;
        struct semaphore sem;
 };
 
@@ -81,7 +81,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
         * So it's equivalent to multiplying by 0.25 * 1000 = 250.
         */
        val = ((int)raw/32) * 250;
-       status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */
+       status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
 out:
        up(&p_lm70->sem);
        return status;
@@ -89,6 +89,14 @@ out:
 
 static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
 
+static ssize_t lm70_show_name(struct device *dev, struct device_attribute
+                             *devattr, char *buf)
+{
+       return sprintf(buf, "lm70\n");
+}
+
+static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
+
 /*----------------------------------------------------------------------*/
 
 static int __devinit lm70_probe(struct spi_device *spi)
@@ -107,15 +115,16 @@ static int __devinit lm70_probe(struct spi_device *spi)
        init_MUTEX(&p_lm70->sem);
 
        /* sysfs hook */
-       p_lm70->cdev = hwmon_device_register(&spi->dev);
-       if (IS_ERR(p_lm70->cdev)) {
+       p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
+       if (IS_ERR(p_lm70->hwmon_dev)) {
                dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
-               status = PTR_ERR(p_lm70->cdev);
+               status = PTR_ERR(p_lm70->hwmon_dev);
                goto out_dev_reg_failed;
        }
        dev_set_drvdata(&spi->dev, p_lm70);
 
-       if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) {
+       if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
+        || (status = device_create_file(&spi->dev, &dev_attr_name))) {
                dev_dbg(&spi->dev, "device_create_file failure.\n");
                goto out_dev_create_file_failed;
        }
@@ -123,7 +132,8 @@ static int __devinit lm70_probe(struct spi_device *spi)
        return 0;
 
 out_dev_create_file_failed:
-       hwmon_device_unregister(p_lm70->cdev);
+       device_remove_file(&spi->dev, &dev_attr_temp1_input);
+       hwmon_device_unregister(p_lm70->hwmon_dev);
 out_dev_reg_failed:
        dev_set_drvdata(&spi->dev, NULL);
        kfree(p_lm70);
@@ -135,7 +145,8 @@ static int __devexit lm70_remove(struct spi_device *spi)
        struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
 
        device_remove_file(&spi->dev, &dev_attr_temp1_input);
-       hwmon_device_unregister(p_lm70->cdev);
+       device_remove_file(&spi->dev, &dev_attr_name);
+       hwmon_device_unregister(p_lm70->hwmon_dev);
        dev_set_drvdata(&spi->dev, NULL);
        kfree(p_lm70);
 
index a40166ffad127665b756668e403754b71b6c5c99..37a8cc032ffa9a0b535ac26b9d07d37edb78bd3e 100644 (file)
@@ -50,7 +50,7 @@ static const u8 LM75_REG_TEMP[3] = {
 /* Each client has this additional data */
 struct lm75_data {
        struct i2c_client       client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex            update_lock;
        char                    valid;          /* !=0 if following fields are valid */
        unsigned long           last_updated;   /* In jiffies */
@@ -95,7 +95,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
        struct i2c_client *client = to_i2c_client(dev);
        struct lm75_data *data = i2c_get_clientdata(client);
        int nr = attr->index;
-       unsigned long temp = simple_strtoul(buf, NULL, 10);
+       long temp = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp[nr] = LM75_TEMP_TO_REG(temp);
@@ -219,9 +219,9 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -240,7 +240,7 @@ exit:
 static int lm75_detach_client(struct i2c_client *client)
 {
        struct lm75_data *data = i2c_get_clientdata(client);
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm75_group);
        i2c_detach_client(client);
        kfree(data);
index af7dc650ee1506878901453ea51bc75dee764392..7c93454bb4e3eb4d01e482b2475335aa03aafc7e 100644 (file)
@@ -33,7 +33,7 @@
 
 /* TEMP: 0.001C/bit (-55C to +125C)
    REG: (0.5C/bit, two's complement) << 7 */
-static inline u16 LM75_TEMP_TO_REG(int temp)
+static inline u16 LM75_TEMP_TO_REG(long temp)
 {
        int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
        ntemp += (ntemp<0 ? -250 : 250);
index dd969f1e84154e6d754b63cfd8f013d09b3dc87e..cee5c2e8cfad29f3a4c6fc21d9d7abed8910219e 100644 (file)
@@ -51,7 +51,7 @@ I2C_CLIENT_INSMOD_1(lm77);
 /* Each client has this additional data */
 struct lm77_data {
        struct i2c_client       client;
-       struct class_device *class_dev;
+       struct device           *hwmon_dev;
        struct mutex            update_lock;
        char                    valid;
        unsigned long           last_updated;   /* In jiffies */
@@ -138,7 +138,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
 {                                                                              \
        struct i2c_client *client = to_i2c_client(dev);                         \
        struct lm77_data *data = i2c_get_clientdata(client);                    \
-       long val = simple_strtoul(buf, NULL, 10);                               \
+       long val = simple_strtol(buf, NULL, 10);                                \
                                                                                \
        mutex_lock(&data->update_lock);                                         \
        data->value = val;                              \
@@ -337,9 +337,9 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -358,7 +358,7 @@ exit:
 static int lm77_detach_client(struct i2c_client *client)
 {
        struct lm77_data *data = i2c_get_clientdata(client);
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm77_group);
        i2c_detach_client(client);
        kfree(data);
index 6eea3476b90c37f6993e86421f4d5eb6d43429ef..3f7055ee679fab746a40902f10b5ad54ba2728c5 100644 (file)
@@ -131,7 +131,7 @@ static inline int TEMP_FROM_REG(s8 val)
    the driver field to differentiate between I2C and ISA chips. */
 struct lm78_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
        enum chips type;
 
@@ -438,6 +438,25 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+                         char *buf)
+{
+       struct lm78_data *data = lm78_update_device(dev);
+       int nr = to_sensor_dev_attr(da)->index;
+       return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+
 /* This function is called when:
      * lm78_driver is inserted (when this module is loaded), for each
        available adapter
@@ -453,36 +472,47 @@ static struct attribute *lm78_attributes[] = {
        &sensor_dev_attr_in0_input.dev_attr.attr,
        &sensor_dev_attr_in0_min.dev_attr.attr,
        &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
        &sensor_dev_attr_in1_input.dev_attr.attr,
        &sensor_dev_attr_in1_min.dev_attr.attr,
        &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
        &sensor_dev_attr_in2_input.dev_attr.attr,
        &sensor_dev_attr_in2_min.dev_attr.attr,
        &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
        &sensor_dev_attr_in3_input.dev_attr.attr,
        &sensor_dev_attr_in3_min.dev_attr.attr,
        &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
        &sensor_dev_attr_in4_input.dev_attr.attr,
        &sensor_dev_attr_in4_min.dev_attr.attr,
        &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
        &sensor_dev_attr_in5_input.dev_attr.attr,
        &sensor_dev_attr_in5_min.dev_attr.attr,
        &sensor_dev_attr_in5_max.dev_attr.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
        &sensor_dev_attr_in6_input.dev_attr.attr,
        &sensor_dev_attr_in6_min.dev_attr.attr,
        &sensor_dev_attr_in6_max.dev_attr.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
        &dev_attr_temp1_input.attr,
        &dev_attr_temp1_max.attr,
        &dev_attr_temp1_max_hyst.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
        &sensor_dev_attr_fan1_input.dev_attr.attr,
        &sensor_dev_attr_fan1_min.dev_attr.attr,
        &sensor_dev_attr_fan1_div.dev_attr.attr,
+       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
        &sensor_dev_attr_fan2_input.dev_attr.attr,
        &sensor_dev_attr_fan2_min.dev_attr.attr,
        &sensor_dev_attr_fan2_div.dev_attr.attr,
+       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
        &sensor_dev_attr_fan3_input.dev_attr.attr,
        &sensor_dev_attr_fan3_min.dev_attr.attr,
        &sensor_dev_attr_fan3_div.dev_attr.attr,
+       &sensor_dev_attr_fan3_alarm.dev_attr.attr,
        &dev_attr_alarms.attr,
        &dev_attr_cpu0_vid.attr,
 
@@ -585,9 +615,9 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
                goto ERROR3;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto ERROR4;
        }
 
@@ -608,7 +638,7 @@ static int lm78_detach_client(struct i2c_client *client)
        struct lm78_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm78_group);
 
        if ((err = i2c_detach_client(client)))
@@ -659,9 +689,9 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev)
         || (err = device_create_file(&pdev->dev, &dev_attr_name)))
                goto exit_remove_files;
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -681,7 +711,7 @@ static int __devexit lm78_isa_remove(struct platform_device *pdev)
 {
        struct lm78_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
        device_remove_file(&pdev->dev, &dev_attr_name);
        release_region(data->client.addr, LM78_EXTENT);
index 064516d824add6deca6527a1a7a0255884a19514..063cdba00a884c5eab975101d61d3b58a24a0ddb 100644 (file)
@@ -108,7 +108,7 @@ static inline long TEMP_FROM_REG(u16 temp)
 
 struct lm80_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -497,9 +497,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
                goto error_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto error_remove;
        }
 
@@ -520,7 +520,7 @@ static int lm80_detach_client(struct i2c_client *client)
        struct lm80_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm80_group);
        if ((err = i2c_detach_client(client)))
                return err;
index 654c0f73464d3f502f566d72e71626dd664914ea..0336b4572a61bd8001d909b78d1c69979e7e9889 100644 (file)
@@ -144,7 +144,7 @@ static struct i2c_driver lm83_driver = {
 
 struct lm83_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -400,9 +400,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
                        goto exit_remove_files;
        }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -424,7 +424,7 @@ static int lm83_detach_client(struct i2c_client *client)
        struct lm83_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm83_group);
        sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
 
index 20a8c648280d5c64cfe94da9f4de860053ff183d..a02480be65f24db5e2c4fdca873d3b5682f92b10 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 
@@ -122,23 +123,6 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 #define        EMC6D102_REG_EXTEND_ADC3        0x87
 #define        EMC6D102_REG_EXTEND_ADC4        0x88
 
-#define        LM85_ALARM_IN0                  0x0001
-#define        LM85_ALARM_IN1                  0x0002
-#define        LM85_ALARM_IN2                  0x0004
-#define        LM85_ALARM_IN3                  0x0008
-#define        LM85_ALARM_TEMP1                0x0010
-#define        LM85_ALARM_TEMP2                0x0020
-#define        LM85_ALARM_TEMP3                0x0040
-#define        LM85_ALARM_ALARM2               0x0080
-#define        LM85_ALARM_IN4                  0x0100
-#define        LM85_ALARM_RESERVED             0x0200
-#define        LM85_ALARM_FAN1                 0x0400
-#define        LM85_ALARM_FAN2                 0x0800
-#define        LM85_ALARM_FAN3                 0x1000
-#define        LM85_ALARM_FAN4                 0x2000
-#define        LM85_ALARM_TEMP1_FAULT          0x4000
-#define        LM85_ALARM_TEMP3_FAULT          0x8000
-
 
 /* Conversions. Rounding and limit checking is only done on the TO_REG 
    variants. Note that you should be a bit careful with which arguments
@@ -155,22 +139,26 @@ static int lm85_scaling[] = {  /* .001 Volts */
 #define INS_TO_REG(n,val)      \
                SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)
 
-#define INSEXT_FROM_REG(n,val,ext,scale)       \
-               SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n])
+#define INSEXT_FROM_REG(n,val,ext)     \
+               SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
 
-#define INS_FROM_REG(n,val)   INSEXT_FROM_REG(n,val,0,1)
+#define INS_FROM_REG(n,val)    SCALE((val), 192, lm85_scaling[n])
 
 /* FAN speed is measured using 90kHz clock */
-#define FAN_TO_REG(val)                (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
+static inline u16 FAN_TO_REG(unsigned long val)
+{
+       if (!val)
+               return 0xffff;
+       return SENSORS_LIMIT(5400000 / val, 1, 0xfffe);
+}
 #define FAN_FROM_REG(val)      ((val)==0?-1:(val)==0xffff?0:5400000/(val))
 
 /* Temperature is reported in .001 degC increments */
 #define TEMP_TO_REG(val)       \
                SENSORS_LIMIT(SCALE(val,1000,1),-127,127)
-#define TEMPEXT_FROM_REG(val,ext,scale)        \
-               SCALE((val)*scale + (ext),scale,1000)
-#define TEMP_FROM_REG(val)     \
-               TEMPEXT_FROM_REG(val,0,1)
+#define TEMPEXT_FROM_REG(val,ext)      \
+               SCALE(((val) << 4) + (ext), 16, 1000)
+#define TEMP_FROM_REG(val)     ((val) * 1000)
 
 #define PWM_TO_REG(val)                        (SENSORS_LIMIT(val,0,255))
 #define PWM_FROM_REG(val)              (val)
@@ -328,7 +316,7 @@ struct lm85_autofan {
    The structure is dynamically allocated. */
 struct lm85_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        enum chips type;
 
        struct mutex update_lock;
@@ -350,7 +338,6 @@ struct lm85_data {
        u8 tach_mode;           /* Register encoding, combined */
        u8 temp_ext[3];         /* Decoded values */
        u8 in_ext[8];           /* Decoded values */
-       u8 adc_scale;           /* ADC Extended bits scaling factor */
        u8 fan_ppr;             /* Register value */
        u8 smooth[3];           /* Register encoding */
        u8 vid;                 /* Register value */
@@ -387,22 +374,29 @@ static struct i2c_driver lm85_driver = {
 
 
 /* 4 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) );
 }
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) );
 }
-static ssize_t set_fan_min(struct device *dev, const char *buf, 
-               size_t count, int nr)
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->fan_min[nr] = FAN_TO_REG(val);
@@ -412,23 +406,10 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
 }
 
 #define show_fan_offset(offset)                                                \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf)        \
-{                                                                      \
-       return show_fan(dev, buf, offset - 1);                          \
-}                                                                      \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)  \
-{                                                                      \
-       return show_fan_min(dev, buf, offset - 1);                      \
-}                                                                      \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr,              \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_fan_min(dev, buf, count, offset - 1);                \
-}                                                                      \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset,    \
-               NULL);                                                  \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,               \
-               show_fan_##offset##_min, set_fan_##offset##_min);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,                        \
+               show_fan, NULL, offset - 1);                            \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,                \
+               show_fan_min, set_fan_min, offset - 1)
 
 show_fan_offset(1);
 show_fan_offset(2);
@@ -457,7 +438,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 
 static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct lm85_data *data = lm85_update_device(dev);
+       struct lm85_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 
@@ -482,16 +463,46 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr
 
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct lm85_data *data = lm85_update_device(dev);
+       return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13);
+
 /* pwm */
 
-static ssize_t show_pwm(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) );
 }
-static ssize_t set_pwm(struct device *dev, const char *buf, 
-               size_t count, int nr)
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -502,8 +513,11 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+               *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        int     pwm_zone;
 
@@ -512,23 +526,10 @@ static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
 }
 
 #define show_pwm_reg(offset)                                           \
-static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf)        \
-{                                                                      \
-       return show_pwm(dev, buf, offset - 1);                          \
-}                                                                      \
-static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr,                    \
-                                const char *buf, size_t count)         \
-{                                                                      \
-       return set_pwm(dev, buf, count, offset - 1);                    \
-}                                                                      \
-static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf)  \
-{                                                                      \
-       return show_pwm_enable(dev, buf, offset - 1);                   \
-}                                                                      \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,                     \
-               show_pwm_##offset, set_pwm_##offset);                   \
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO,                      \
-               show_pwm_enable##offset, NULL);
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,              \
+               show_pwm, set_pwm, offset - 1);                         \
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO,               \
+               show_pwm_enable, NULL, offset - 1)
 
 show_pwm_reg(1);
 show_pwm_reg(2);
@@ -536,22 +537,28 @@ show_pwm_reg(3);
 
 /* Voltages */
 
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr,
                                                     data->in[nr],
-                                                    data->in_ext[nr],
-                                                    data->adc_scale) );
+                                                    data->in_ext[nr]));
 }
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_in_min(struct device *dev,  struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) );
 }
-static ssize_t set_in_min(struct device *dev, const char *buf, 
-               size_t count, int nr)
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -562,14 +569,19 @@ static ssize_t set_in_min(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) );
 }
-static ssize_t set_in_max(struct device *dev, const char *buf, 
-               size_t count, int nr)
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -580,59 +592,47 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
+
 #define show_in_reg(offset)                                            \
-static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf)         \
-{                                                                      \
-       return show_in(dev, buf, offset);                               \
-}                                                                      \
-static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)   \
-{                                                                      \
-       return show_in_min(dev, buf, offset);                           \
-}                                                                      \
-static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf)   \
-{                                                                      \
-       return show_in_max(dev, buf, offset);                           \
-}                                                                      \
-static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr,               \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_in_min(dev, buf, count, offset);                     \
-}                                                                      \
-static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr,               \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_in_max(dev, buf, count, offset);                     \
-}                                                                      \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset,      \
-               NULL);                                                  \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,                \
-               show_in_##offset##_min, set_in_##offset##_min);         \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,                \
-               show_in_##offset##_max, set_in_##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,                 \
+               show_in, NULL, offset);                                 \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,         \
+               show_in_min, set_in_min, offset);                       \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,         \
+               show_in_max, set_in_max, offset)
 
 show_in_reg(0);
 show_in_reg(1);
 show_in_reg(2);
 show_in_reg(3);
 show_in_reg(4);
+show_in_reg(5);
+show_in_reg(6);
+show_in_reg(7);
 
 /* Temps */
 
-static ssize_t show_temp(struct device *dev, char *buf, int nr)
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr],
-                                                   data->temp_ext[nr],
-                                                   data->adc_scale) );
+                                                   data->temp_ext[nr]));
 }
-static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) );
 }
-static ssize_t set_temp_min(struct device *dev, const char *buf, 
-               size_t count, int nr)
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -643,14 +643,19 @@ static ssize_t set_temp_min(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) );
 }
-static ssize_t set_temp_max(struct device *dev, const char *buf, 
-               size_t count, int nr)
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);        
@@ -661,35 +666,14 @@ static ssize_t set_temp_max(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
+
 #define show_temp_reg(offset)                                          \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf)       \
-{                                                                      \
-       return show_temp(dev, buf, offset - 1);                         \
-}                                                                      \
-static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{                                                                      \
-       return show_temp_min(dev, buf, offset - 1);                     \
-}                                                                      \
-static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{                                                                      \
-       return show_temp_max(dev, buf, offset - 1);                     \
-}                                                                      \
-static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr,             \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_temp_min(dev, buf, count, offset - 1);               \
-}                                                                      \
-static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr,             \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_temp_max(dev, buf, count, offset - 1);               \
-}                                                                      \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset,  \
-               NULL);                                                  \
-static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,              \
-               show_temp_##offset##_min, set_temp_##offset##_min);     \
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,              \
-               show_temp_##offset##_max, set_temp_##offset##_max);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,               \
+               show_temp, NULL, offset - 1);                           \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,       \
+               show_temp_min, set_temp_min, offset - 1);               \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,       \
+               show_temp_max, set_temp_max, offset - 1);
 
 show_temp_reg(1);
 show_temp_reg(2);
@@ -698,14 +682,18 @@ show_temp_reg(3);
 
 /* Automatic PWM control */
 
-static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm_auto_channels(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config));
 }
-static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf,
-       size_t count, int nr)
+
+static ssize_t set_pwm_auto_channels(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);   
@@ -718,14 +706,19 @@ static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_min(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm));
 }
-static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf,
-       size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_min(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -737,14 +730,19 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_minctl(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", data->autofan[nr].min_off);
 }
-static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf,
-       size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_minctl(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -760,14 +758,19 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_freq(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq));
 }
-static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf,
-               size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_freq(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -781,74 +784,40 @@ static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
+
 #define pwm_auto(offset)                                               \
-static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr,    \
-       char *buf)                                                      \
-{                                                                      \
-       return show_pwm_auto_channels(dev, buf, offset - 1);            \
-}                                                                      \
-static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr,     \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_pwm_auto_channels(dev, buf, count, offset - 1);      \
-}                                                                      \
-static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr,     \
-       char *buf)                                                      \
-{                                                                      \
-       return show_pwm_auto_pwm_min(dev, buf, offset - 1);             \
-}                                                                      \
-static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr,      \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_pwm_auto_pwm_min(dev, buf, count, offset - 1);       \
-}                                                                      \
-static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr,  \
-       char *buf)                                                      \
-{                                                                      \
-       return show_pwm_auto_pwm_minctl(dev, buf, offset - 1);          \
-}                                                                      \
-static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr,   \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1);    \
-}                                                                      \
-static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr,    \
-       char *buf)                                                      \
-{                                                                      \
-       return show_pwm_auto_pwm_freq(dev, buf, offset - 1);            \
-}                                                                      \
-static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr,      \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1);      \
-}                                                                      \
-static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR,     \
-               show_pwm##offset##_auto_channels,                       \
-               set_pwm##offset##_auto_channels);                       \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR,      \
-               show_pwm##offset##_auto_pwm_min,                        \
-               set_pwm##offset##_auto_pwm_min);                        \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR,   \
-               show_pwm##offset##_auto_pwm_minctl,                     \
-               set_pwm##offset##_auto_pwm_minctl);                     \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR,     \
-               show_pwm##offset##_auto_pwm_freq,                       \
-               set_pwm##offset##_auto_pwm_freq);              
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels,                 \
+               S_IRUGO | S_IWUSR, show_pwm_auto_channels,              \
+               set_pwm_auto_channels, offset - 1);                     \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_min,                  \
+               S_IRUGO | S_IWUSR, show_pwm_auto_pwm_min,               \
+               set_pwm_auto_pwm_min, offset - 1);                      \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_minctl,               \
+               S_IRUGO | S_IWUSR, show_pwm_auto_pwm_minctl,            \
+               set_pwm_auto_pwm_minctl, offset - 1);                   \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_freq,                 \
+               S_IRUGO | S_IWUSR, show_pwm_auto_pwm_freq,              \
+               set_pwm_auto_pwm_freq, offset - 1);
+
 pwm_auto(1);
 pwm_auto(2);
 pwm_auto(3);
 
 /* Temperature settings for automatic PWM control */
 
-static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_auto_temp_off(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) -
                HYST_FROM_REG(data->zone[nr].hyst));
 }
-static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf,
-       size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_off(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        int min;
@@ -871,14 +840,19 @@ static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_min(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) );
 }
-static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf,
-       size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_min(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -913,15 +887,20 @@ static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_max(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) +
                RANGE_FROM_REG(data->zone[nr].range));
 }
-static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf,
-       size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_max(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        int min;
@@ -938,14 +917,19 @@ static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_crit(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical));
 }
-static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf,
-               size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_crit(struct device *dev,
+               struct device_attribute *attr,const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
@@ -957,59 +941,21 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf,
        mutex_unlock(&data->update_lock);
        return count;
 }
+
 #define temp_auto(offset)                                              \
-static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr,   \
-       char *buf)                                                      \
-{                                                                      \
-       return show_temp_auto_temp_off(dev, buf, offset - 1);           \
-}                                                                      \
-static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr,    \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_temp_auto_temp_off(dev, buf, count, offset - 1);     \
-}                                                                      \
-static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr,   \
-       char *buf)                                                      \
-{                                                                      \
-       return show_temp_auto_temp_min(dev, buf, offset - 1);           \
-}                                                                      \
-static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr,    \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_temp_auto_temp_min(dev, buf, count, offset - 1);     \
-}                                                                      \
-static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr,   \
-       char *buf)                                                      \
-{                                                                      \
-       return show_temp_auto_temp_max(dev, buf, offset - 1);           \
-}                                                                      \
-static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr,    \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_temp_auto_temp_max(dev, buf, count, offset - 1);     \
-}                                                                      \
-static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr,  \
-       char *buf)                                                      \
-{                                                                      \
-       return show_temp_auto_temp_crit(dev, buf, offset - 1);          \
-}                                                                      \
-static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr,   \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_temp_auto_temp_crit(dev, buf, count, offset - 1);    \
-}                                                                      \
-static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR,    \
-               show_temp##offset##_auto_temp_off,                      \
-               set_temp##offset##_auto_temp_off);                      \
-static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR,    \
-               show_temp##offset##_auto_temp_min,                      \
-               set_temp##offset##_auto_temp_min);                      \
-static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR,    \
-               show_temp##offset##_auto_temp_max,                      \
-               set_temp##offset##_auto_temp_max);                      \
-static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR,   \
-               show_temp##offset##_auto_temp_crit,                     \
-               set_temp##offset##_auto_temp_crit);
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_off,                        \
+               S_IRUGO | S_IWUSR, show_temp_auto_temp_off,             \
+               set_temp_auto_temp_off, offset - 1);                    \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_min,                        \
+               S_IRUGO | S_IWUSR, show_temp_auto_temp_min,             \
+               set_temp_auto_temp_min, offset - 1);                    \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_max,                        \
+               S_IRUGO | S_IWUSR, show_temp_auto_temp_max,             \
+               set_temp_auto_temp_max, offset - 1);                    \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_crit,               \
+               S_IRUGO | S_IWUSR, show_temp_auto_temp_crit,            \
+               set_temp_auto_temp_crit, offset - 1);
+
 temp_auto(1);
 temp_auto(2);
 temp_auto(3);
@@ -1022,69 +968,87 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter)
 }
 
 static struct attribute *lm85_attributes[] = {
-       &dev_attr_fan1_input.attr,
-       &dev_attr_fan2_input.attr,
-       &dev_attr_fan3_input.attr,
-       &dev_attr_fan4_input.attr,
-       &dev_attr_fan1_min.attr,
-       &dev_attr_fan2_min.attr,
-       &dev_attr_fan3_min.attr,
-       &dev_attr_fan4_min.attr,
-       &dev_attr_pwm1.attr,
-       &dev_attr_pwm2.attr,
-       &dev_attr_pwm3.attr,
-       &dev_attr_pwm1_enable.attr,
-       &dev_attr_pwm2_enable.attr,
-       &dev_attr_pwm3_enable.attr,
-       &dev_attr_in0_input.attr,
-       &dev_attr_in1_input.attr,
-       &dev_attr_in2_input.attr,
-       &dev_attr_in3_input.attr,
-       &dev_attr_in0_min.attr,
-       &dev_attr_in1_min.attr,
-       &dev_attr_in2_min.attr,
-       &dev_attr_in3_min.attr,
-       &dev_attr_in0_max.attr,
-       &dev_attr_in1_max.attr,
-       &dev_attr_in2_max.attr,
-       &dev_attr_in3_max.attr,
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp2_input.attr,
-       &dev_attr_temp3_input.attr,
-       &dev_attr_temp1_min.attr,
-       &dev_attr_temp2_min.attr,
-       &dev_attr_temp3_min.attr,
-       &dev_attr_temp1_max.attr,
-       &dev_attr_temp2_max.attr,
-       &dev_attr_temp3_max.attr,
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm3.dev_attr.attr,
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_channels.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_pwm_freq.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_pwm_freq.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_pwm_freq.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_temp_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_temp_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_temp_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_temp_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_temp_crit.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_temp_crit.dev_attr.attr,
+
        &dev_attr_vrm.attr,
        &dev_attr_cpu0_vid.attr,
        &dev_attr_alarms.attr,
-       &dev_attr_pwm1_auto_channels.attr,
-       &dev_attr_pwm2_auto_channels.attr,
-       &dev_attr_pwm3_auto_channels.attr,
-       &dev_attr_pwm1_auto_pwm_min.attr,
-       &dev_attr_pwm2_auto_pwm_min.attr,
-       &dev_attr_pwm3_auto_pwm_min.attr,
-       &dev_attr_pwm1_auto_pwm_minctl.attr,
-       &dev_attr_pwm2_auto_pwm_minctl.attr,
-       &dev_attr_pwm3_auto_pwm_minctl.attr,
-       &dev_attr_pwm1_auto_pwm_freq.attr,
-       &dev_attr_pwm2_auto_pwm_freq.attr,
-       &dev_attr_pwm3_auto_pwm_freq.attr,
-       &dev_attr_temp1_auto_temp_off.attr,
-       &dev_attr_temp2_auto_temp_off.attr,
-       &dev_attr_temp3_auto_temp_off.attr,
-       &dev_attr_temp1_auto_temp_min.attr,
-       &dev_attr_temp2_auto_temp_min.attr,
-       &dev_attr_temp3_auto_temp_min.attr,
-       &dev_attr_temp1_auto_temp_max.attr,
-       &dev_attr_temp2_auto_temp_max.attr,
-       &dev_attr_temp3_auto_temp_max.attr,
-       &dev_attr_temp1_auto_temp_crit.attr,
-       &dev_attr_temp2_auto_temp_crit.attr,
-       &dev_attr_temp3_auto_temp_crit.attr,
-
        NULL
 };
 
@@ -1092,16 +1056,36 @@ static const struct attribute_group lm85_group = {
        .attrs = lm85_attributes,
 };
 
-static struct attribute *lm85_attributes_opt[] = {
-       &dev_attr_in4_input.attr,
-       &dev_attr_in4_min.attr,
-       &dev_attr_in4_max.attr,
+static struct attribute *lm85_attributes_in4[] = {
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group lm85_group_in4 = {
+       .attrs = lm85_attributes_in4,
+};
 
+static struct attribute *lm85_attributes_in567[] = {
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in7_input.dev_attr.attr,
+       &sensor_dev_attr_in5_min.dev_attr.attr,
+       &sensor_dev_attr_in6_min.dev_attr.attr,
+       &sensor_dev_attr_in7_min.dev_attr.attr,
+       &sensor_dev_attr_in5_max.dev_attr.attr,
+       &sensor_dev_attr_in6_max.dev_attr.attr,
+       &sensor_dev_attr_in7_max.dev_attr.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
+       &sensor_dev_attr_in7_alarm.dev_attr.attr,
        NULL
 };
 
-static const struct attribute_group lm85_group_opt = {
-       .attrs = lm85_attributes_opt,
+static const struct attribute_group lm85_group_in567 = {
+       .attrs = lm85_attributes_in567,
 };
 
 static int lm85_detect(struct i2c_adapter *adapter, int address,
@@ -1249,17 +1233,19 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
           as a sixth digital VID input rather than an analog input. */
        data->vid = lm85_read_value(new_client, LM85_REG_VID);
        if (!(kind == adt7463 && (data->vid & 0x80)))
-               if ((err = device_create_file(&new_client->dev,
-                                       &dev_attr_in4_input))
-                || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_in4_min))
-                || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_in4_max)))
+               if ((err = sysfs_create_group(&new_client->dev.kobj,
+                                       &lm85_group_in4)))
                        goto ERROR3;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       /* The EMC6D100 has 3 additional voltage inputs */
+       if (kind == emc6d100)
+               if ((err = sysfs_create_group(&new_client->dev.kobj,
+                                       &lm85_group_in567)))
+                       goto ERROR3;
+
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto ERROR3;
        }
 
@@ -1268,7 +1254,9 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
        /* Error out and cleanup code */
     ERROR3:
        sysfs_remove_group(&new_client->dev.kobj, &lm85_group);
-       sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt);
+       sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in4);
+       if (kind == emc6d100)
+               sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in567);
     ERROR2:
        i2c_detach_client(new_client);
     ERROR1:
@@ -1280,9 +1268,11 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
 static int lm85_detach_client(struct i2c_client *client)
 {
        struct lm85_data *data = i2c_get_clientdata(client);
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm85_group);
-       sysfs_remove_group(&client->dev.kobj, &lm85_group_opt);
+       sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
+       if (data->type == emc6d100)
+               sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
        i2c_detach_client(client);
        kfree(data);
        return 0;
@@ -1405,6 +1395,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                
                /* Have to read extended bits first to "freeze" the
                 * more significant bits that are read later.
+                * There are 2 additional resolution bits per channel and we
+                * have room for 4, so we shift them to the left.
                 */
                if ( (data->type == adm1027) || (data->type == adt7463) ) {
                        int ext1 = lm85_read_value(client,
@@ -1414,18 +1406,12 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                        int val = (ext1 << 8) + ext2;
 
                        for(i = 0; i <= 4; i++)
-                               data->in_ext[i] = (val>>(i * 2))&0x03;
+                               data->in_ext[i] = ((val>>(i * 2))&0x03) << 2;
 
                        for(i = 0; i <= 2; i++)
-                               data->temp_ext[i] = (val>>((i + 5) * 2))&0x03;
+                               data->temp_ext[i] = (val>>((i + 4) * 2))&0x0c;
                }
 
-               /* adc_scale is 2^(number of LSBs). There are 4 extra bits in
-                  the emc6d102 and 2 in the adt7463 and adm1027. In all
-                  other chips ext is always 0 and the value of scale is
-                  irrelevant. So it is left in 4*/
-               data->adc_scale = (data->type == emc6d102 ) ? 16 : 4;
-
                data->vid = lm85_read_value(client, LM85_REG_VID);
 
                for (i = 0; i <= 3; ++i) {
index 988ae1c4aada69ebb2f9315258ac1b4ee878f65b..28cdff0c556b35eb9dba9f20ed3e9256ea26ac5b 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
@@ -129,7 +130,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
                                 (((val) < 0 ? (val)-500 : (val)+500) / 1000))
 
 #define FAN_FROM_REG(reg,div)  ((reg) == 255 || (reg) == 0 ? 0 : \
-                                1350000 + (reg)*(div) / 2) / ((reg)*(div))
+                                (1350000 + (reg)*(div) / 2) / ((reg)*(div)))
 #define FAN_TO_REG(val,div)    ((val)*(div) * 255 <= 1350000 ? 255 : \
                                 (1350000 + (val)*(div) / 2) / ((val)*(div)))
 
@@ -145,7 +146,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
 #define CHAN_NO_FAN(nr)                (1 << (nr))
 #define CHAN_TEMP3             (1 << 2)
 #define CHAN_VCC_5V            (1 << 3)
-#define CHAN_NO_VID            (1 << 8)
+#define CHAN_NO_VID            (1 << 7)
 
 /*
  * Functions declaration
@@ -176,7 +177,7 @@ static struct i2c_driver lm87_driver = {
 
 struct lm87_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* In jiffies */
@@ -500,7 +501,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 
 static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct lm87_data *data = lm87_update_device(dev);
+       struct lm87_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", data->vrm);
 }
 static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -531,6 +532,29 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const
 }
 static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+
 /*
  * Real code
  */
@@ -546,24 +570,31 @@ static struct attribute *lm87_attributes[] = {
        &dev_attr_in1_input.attr,
        &dev_attr_in1_min.attr,
        &dev_attr_in1_max.attr,
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
        &dev_attr_in2_input.attr,
        &dev_attr_in2_min.attr,
        &dev_attr_in2_max.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
        &dev_attr_in3_input.attr,
        &dev_attr_in3_min.attr,
        &dev_attr_in3_max.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
        &dev_attr_in4_input.attr,
        &dev_attr_in4_min.attr,
        &dev_attr_in4_max.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
 
        &dev_attr_temp1_input.attr,
        &dev_attr_temp1_max.attr,
        &dev_attr_temp1_min.attr,
        &dev_attr_temp1_crit.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
        &dev_attr_temp2_input.attr,
        &dev_attr_temp2_max.attr,
        &dev_attr_temp2_min.attr,
        &dev_attr_temp2_crit.attr,
+       &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
 
        &dev_attr_alarms.attr,
        &dev_attr_aout_output.attr,
@@ -579,30 +610,38 @@ static struct attribute *lm87_attributes_opt[] = {
        &dev_attr_in6_input.attr,
        &dev_attr_in6_min.attr,
        &dev_attr_in6_max.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
 
        &dev_attr_fan1_input.attr,
        &dev_attr_fan1_min.attr,
        &dev_attr_fan1_div.attr,
+       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
 
        &dev_attr_in7_input.attr,
        &dev_attr_in7_min.attr,
        &dev_attr_in7_max.attr,
+       &sensor_dev_attr_in7_alarm.dev_attr.attr,
 
        &dev_attr_fan2_input.attr,
        &dev_attr_fan2_min.attr,
        &dev_attr_fan2_div.attr,
+       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
 
        &dev_attr_temp3_input.attr,
        &dev_attr_temp3_max.attr,
        &dev_attr_temp3_min.attr,
        &dev_attr_temp3_crit.attr,
+       &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
 
        &dev_attr_in0_input.attr,
        &dev_attr_in0_min.attr,
        &dev_attr_in0_max.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
        &dev_attr_in5_input.attr,
        &dev_attr_in5_min.attr,
        &dev_attr_in5_max.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
 
        &dev_attr_cpu0_vid.attr,
        &dev_attr_vrm.attr,
@@ -690,7 +729,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_in6_min))
                 || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_in6_max)))
+                                       &dev_attr_in6_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in6_alarm.dev_attr)))
                        goto exit_remove;
        } else {
                if ((err = device_create_file(&new_client->dev,
@@ -698,7 +739,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_fan1_min))
                 || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_fan1_div)))
+                                       &dev_attr_fan1_div))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_fan1_alarm.dev_attr)))
                        goto exit_remove;
        }
 
@@ -708,7 +751,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_in7_min))
                 || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_in7_max)))
+                                       &dev_attr_in7_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in7_alarm.dev_attr)))
                        goto exit_remove;
        } else {
                if ((err = device_create_file(&new_client->dev,
@@ -716,7 +761,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_fan2_min))
                 || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_fan2_div)))
+                                       &dev_attr_fan2_div))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_fan2_alarm.dev_attr)))
                        goto exit_remove;
        }
 
@@ -728,7 +775,11 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_temp3_min))
                 || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_temp3_crit)))
+                                       &dev_attr_temp3_crit))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_temp3_alarm.dev_attr))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_temp3_fault.dev_attr)))
                        goto exit_remove;
        } else {
                if ((err = device_create_file(&new_client->dev,
@@ -737,12 +788,16 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
                                        &dev_attr_in0_min))
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_in0_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in0_alarm.dev_attr))
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_in5_input))
                 || (err = device_create_file(&new_client->dev,
                                        &dev_attr_in5_min))
                 || (err = device_create_file(&new_client->dev,
-                                       &dev_attr_in5_max)))
+                                       &dev_attr_in5_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in5_alarm.dev_attr)))
                        goto exit_remove;
        }
 
@@ -755,9 +810,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
                        goto exit_remove;
        }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -816,7 +871,7 @@ static int lm87_detach_client(struct i2c_client *client)
        struct lm87_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm87_group);
        sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
 
index af541d67245dd040b055c6bed708b99b9caf5f9e..960df9fa75afe16cc4d0ecad7bf6130f4cb665e4 100644 (file)
@@ -41,7 +41,8 @@
  *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
  * Note that there is no easy way to differentiate between the three
  * variants. The extra address and features of the MAX6659 are not
- * supported by this driver.
+ * supported by this driver. These chips lack the remote temperature
+ * offset feature.
  *
  * This driver also supports the MAX6680 and MAX6681, two other sensor
  * chips made by Maxim. These are quite similar to the other Maxim
@@ -214,7 +215,7 @@ static struct i2c_driver lm90_driver = {
 
 struct lm90_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -226,9 +227,10 @@ struct lm90_data {
                           2: local high limit
                           3: local critical limit
                           4: remote critical limit */
-       s16 temp11[3];  /* 0: remote input
+       s16 temp11[4];  /* 0: remote input
                           1: remote low limit
-                          2: remote high limit */
+                          2: remote high limit
+                          3: remote offset (except max6657) */
        u8 temp_hyst;
        u8 alarms; /* bitvector */
 };
@@ -282,11 +284,13 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
 static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
                          const char *buf, size_t count)
 {
-       static const u8 reg[4] = {
+       static const u8 reg[6] = {
                LM90_REG_W_REMOTE_LOWH,
                LM90_REG_W_REMOTE_LOWL,
                LM90_REG_W_REMOTE_HIGHH,
                LM90_REG_W_REMOTE_HIGHL,
+               LM90_REG_W_REMOTE_OFFSH,
+               LM90_REG_W_REMOTE_OFFSL,
        };
 
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -367,6 +371,8 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
 static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
        set_temphyst, 3);
 static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+       set_temp11, 3);
 
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
@@ -652,10 +658,15 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
                                              &dev_attr_pec)))
                        goto exit_remove_files;
        }
+       if (data->kind != max6657) {
+               if ((err = device_create_file(&new_client->dev,
+                               &sensor_dev_attr_temp2_offset.dev_attr)))
+                       goto exit_remove_files;
+       }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -707,9 +718,12 @@ static int lm90_detach_client(struct i2c_client *client)
        struct lm90_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm90_group);
        device_remove_file(&client->dev, &dev_attr_pec);
+       if (data->kind != max6657)
+               device_remove_file(&client->dev,
+                                  &sensor_dev_attr_temp2_offset.dev_attr);
 
        if ((err = i2c_detach_client(client)))
                return err;
@@ -763,6 +777,13 @@ static struct lm90_data *lm90_update_device(struct device *dev)
                if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0
                 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0)
                        data->temp11[2] = (newh << 8) | l;
+               if (data->kind != max6657) {
+                       if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
+                                         &newh) == 0
+                        && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
+                                         &l) == 0)
+                               data->temp11[3] = (newh << 8) | l;
+               }
                lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms);
 
                data->last_updated = jiffies;
index 30b536333f1469f537bd27799f5c5ada55d88323..61d1bd1d5b6e971d9e6a2f89bb885c36c3079951 100644 (file)
@@ -96,7 +96,7 @@ static struct i2c_driver lm92_driver;
 /* Client data (each client gets its own) */
 struct lm92_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -379,9 +379,9 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -409,7 +409,7 @@ static int lm92_detach_client(struct i2c_client *client)
        struct lm92_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm92_group);
 
        if ((err = i2c_detach_client(client)))
index d84f8bf6f28476edf6c8e422eb675972af44acc1..ea61946a4bf76ede2aa2cb4d7af0c42fb6c73220 100644 (file)
@@ -201,7 +201,7 @@ struct block1_t {
  */
 struct lm93_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
 
        struct mutex update_lock;
        unsigned long last_updated;     /* In jiffies */
@@ -413,7 +413,7 @@ static int LM93_TEMP_FROM_REG(u8 reg)
 
 /* TEMP: 1/1000 degrees C (-128C to +127C)
    REG: 1C/bit, two's complement */
-static u8 LM93_TEMP_TO_REG(int temp)
+static u8 LM93_TEMP_TO_REG(long temp)
 {
        int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
        ntemp += (ntemp<0 ? -500 : 500);
@@ -1268,7 +1268,7 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
        int nr = (to_sensor_dev_attr(attr))->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm93_data *data = i2c_get_clientdata(client);
-       u32 val = simple_strtoul(buf, NULL, 10);
+       long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
@@ -1298,7 +1298,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
        int nr = (to_sensor_dev_attr(attr))->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm93_data *data = i2c_get_clientdata(client);
-       u32 val = simple_strtoul(buf, NULL, 10);
+       long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
@@ -1329,7 +1329,7 @@ static ssize_t store_temp_auto_base(struct device *dev,
        int nr = (to_sensor_dev_attr(attr))->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm93_data *data = i2c_get_clientdata(client);
-       u32 val = simple_strtoul(buf, NULL, 10);
+       long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->block10.base[nr] = LM93_TEMP_TO_REG(val);
@@ -1360,7 +1360,7 @@ static ssize_t store_temp_auto_boost(struct device *dev,
        int nr = (to_sensor_dev_attr(attr))->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm93_data *data = i2c_get_clientdata(client);
-       u32 val = simple_strtoul(buf, NULL, 10);
+       long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->boost[nr] = LM93_TEMP_TO_REG(val);
@@ -2078,8 +2078,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
        return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
 }
 
-static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
-static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu1_vid, S_IRUGO, show_vid, NULL, 1);
 
 static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
                                char *buf)
@@ -2431,8 +2431,8 @@ static struct attribute *lm93_attrs[] = {
        &sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
        &dev_attr_pwm_auto_prochot_ramp.attr,
        &dev_attr_pwm_auto_vrdhot_ramp.attr,
-       &sensor_dev_attr_vid1.dev_attr.attr,
-       &sensor_dev_attr_vid2.dev_attr.attr,
+       &sensor_dev_attr_cpu0_vid.dev_attr.attr,
+       &sensor_dev_attr_cpu1_vid.dev_attr.attr,
        &sensor_dev_attr_prochot1.dev_attr.attr,
        &sensor_dev_attr_prochot2.dev_attr.attr,
        &sensor_dev_attr_prochot1_avg.dev_attr.attr,
@@ -2590,11 +2590,11 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
                goto err_detach;
 
        /* Register hwmon driver class */
-       data->class_dev = hwmon_device_register(&client->dev);
-       if ( !IS_ERR(data->class_dev))
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if ( !IS_ERR(data->hwmon_dev))
                return 0;
 
-       err = PTR_ERR(data->class_dev);
+       err = PTR_ERR(data->hwmon_dev);
        dev_err(&client->dev, "error registering hwmon device.\n");
        sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
 err_detach:
@@ -2619,7 +2619,7 @@ static int lm93_detach_client(struct i2c_client *client)
        struct lm93_data *data = i2c_get_clientdata(client);
        int err = 0;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
 
        err = i2c_detach_client(client);
index 2f58f651f03a5c7af92d8322c3ff041a83cc12b1..38a44c3d6ceebd213e47d165d5815cc38a4db08f 100644 (file)
@@ -105,7 +105,7 @@ static struct i2c_driver max1619_driver = {
 
 struct max1619_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -293,9 +293,9 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
        if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -331,7 +331,7 @@ static int max1619_detach_client(struct i2c_client *client)
        struct max1619_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &max1619_group);
 
        if ((err = i2c_detach_client(client)))
index 8415664f33c2cf42f24987a56a39dc5792026e34..755570c1f4ebc841d960ddc96726dab1eeaa9b3b 100644 (file)
@@ -128,7 +128,7 @@ static struct i2c_driver max6650_driver = {
 struct max6650_data
 {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -523,11 +523,11 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
        if (err)
                goto err_detach;
 
-       data->class_dev = hwmon_device_register(&client->dev);
-       if (!IS_ERR(data->class_dev))
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (!IS_ERR(data->hwmon_dev))
                return 0;
 
-       err = PTR_ERR(data->class_dev);
+       err = PTR_ERR(data->hwmon_dev);
        dev_err(&client->dev, "error registering hwmon device.\n");
        sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
 err_detach:
@@ -543,7 +543,7 @@ static int max6650_detach_client(struct i2c_client *client)
        int err;
 
        sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        err = i2c_detach_client(client);
        if (!err)
                kfree(data);
index f57c75d59a5bcf0273aba9569b0958e417eaa81d..9d660133d517302535c1d42ef6e0ee79097b9acc 100644 (file)
@@ -180,7 +180,7 @@ static inline u8 PWM_TO_REG(int val, int inv)
 
 struct pc87360_data {
        const char *name;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
@@ -500,7 +500,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 
 static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct pc87360_data *data = pc87360_update_device(dev);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%u\n", data->vrm);
 }
 static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -1054,9 +1054,9 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
        if ((err = device_create_file(dev, &dev_attr_name)))
                goto ERROR3;
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto ERROR3;
        }
        return 0;
@@ -1083,7 +1083,7 @@ static int __devexit pc87360_remove(struct platform_device *pdev)
        struct pc87360_data *data = platform_get_drvdata(pdev);
        int i;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
 
        device_remove_file(&pdev->dev, &dev_attr_name);
        sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
index 2915bc4ad0d566f6a212abff02a9bac71ab52e28..d40509ad6ae6233dc0a702f9887de6f11edde5fb 100644 (file)
@@ -42,7 +42,7 @@ static struct platform_device *pdev;
    device is using banked registers) and the register cache (needed to keep
    the data in the registers and the cache in sync at any time). */
 struct pc87427_data {
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
        int address[2];
        const char *name;
@@ -454,9 +454,9 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
                        goto exit_remove_files;
        }
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
                goto exit_remove_files;
        }
@@ -484,7 +484,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
        struct resource *res;
        int i;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        device_remove_file(&pdev->dev, &dev_attr_name);
        for (i = 0; i < 8; i++) {
                if (!(data->fan_enabled & (1 << i)))
index 92956eb3f3c15b657bcabf341cf4984b484cbbd0..860b71ccbb86bde3e27dcc549303d8ea95ee76b8 100644 (file)
@@ -163,7 +163,7 @@ static inline u8 DIV_TO_REG(int val)
 struct sis5595_data {
        unsigned short addr;
        const char *name;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
 
        struct mutex update_lock;
@@ -517,7 +517,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, data);
 
        /* Check revision and pin registers to determine whether 4 or 5 voltages */
-       pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
+       data->revision = s_bridge->revision;
        /* 4 voltages, 1 temp */
        data->maxins = 3;
        if (data->revision >= REV2MIN) {
@@ -557,9 +557,9 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
                        goto exit_remove_files;
        }
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -580,7 +580,7 @@ static int __devexit sis5595_remove(struct platform_device *pdev)
 {
        struct sis5595_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
        sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
 
@@ -739,11 +739,10 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
        int *i;
 
        for (i = blacklist; *i != 0; i++) {
-               struct pci_dev *dev;
-               dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
-               if (dev) {
-                       dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
-                       pci_dev_put(dev);
+               struct pci_dev *d;
+               if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) {
+                       dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
+                       pci_dev_put(d);
                        return -ENODEV;
                }
        }
index 45266b30ce1d760f800b79ea6f59dbd7a27d75b3..0b57d2ea2cf714493dc9174e614190036b04ca09 100644 (file)
@@ -94,7 +94,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
 struct smsc47b397_data {
        unsigned short addr;
        const char *name;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
 
        struct mutex update_lock;
@@ -222,7 +222,7 @@ static int __devexit smsc47b397_remove(struct platform_device *pdev)
        struct smsc47b397_data *data = platform_get_drvdata(pdev);
        struct resource *res;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        release_region(res->start, SMSC_EXTENT);
@@ -272,9 +272,9 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev)
        if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group)))
                goto error_free;
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto error_remove;
        }
 
index d3181967f1671a9359fc474dd1a009634c511991..a10a380868e2640b6d424e682e7400988a3e8ede 100644 (file)
@@ -116,7 +116,7 @@ struct smsc47m1_data {
        unsigned short addr;
        const char *name;
        enum chips type;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
 
        struct mutex update_lock;
        unsigned long last_updated;     /* In jiffies */
@@ -553,7 +553,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_fan3_div.dev_attr)))
                        goto error_remove_files;
-       } else
+       } else if (data->type == smsc47m2)
                dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
 
        if (pwm1) {
@@ -580,7 +580,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
                 || (err = device_create_file(dev,
                                &sensor_dev_attr_pwm3_enable.dev_attr)))
                        goto error_remove_files;
-       } else
+       } else if (data->type == smsc47m2)
                dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
 
        if ((err = device_create_file(dev, &dev_attr_alarms)))
@@ -588,9 +588,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
        if ((err = device_create_file(dev, &dev_attr_name)))
                goto error_remove_files;
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto error_remove_files;
        }
 
@@ -611,7 +611,7 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
        struct smsc47m1_data *data = platform_get_drvdata(pdev);
        struct resource *res;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
index d3a3ba04cb0f1aac62503f96a65cfd3cde4b79ec..b87552652588ba3e411c0e50e3d3c3442c13f761 100644 (file)
@@ -97,7 +97,7 @@ static inline int TEMP_FROM_REG(s8 val)
 
 struct smsc47m192_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -334,7 +334,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
-       struct smsc47m192_data *data = smsc47m192_update_device(dev);
+       struct smsc47m192_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", data->vrm);
 }
 
@@ -553,9 +553,9 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
                        goto exit_remove_files;
        }
 
-       data->class_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -577,7 +577,7 @@ static int smsc47m192_detach_client(struct i2c_client *client)
        struct smsc47m192_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
        sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
 
index 9395b52d9b99260498e64d5cf3af2bc24df96121..04dd7699b3ac7c1735ecb82d58c45f941637c3b1 100644 (file)
@@ -46,6 +46,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
 #define THMC50_REG_COMPANY_ID                  0x3E
 #define THMC50_REG_DIE_CODE                    0x3F
 #define THMC50_REG_ANALOG_OUT                  0x19
+/*
+ * The mirror status register cannot be used as
+ * reading it does not clear alarms.
+ */
+#define THMC50_REG_INTR                                0x41
 
 const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
 const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
@@ -56,7 +61,7 @@ const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
 /* Each client has this additional data */
 struct thmc50_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
 
        struct mutex update_lock;
        enum chips type;
@@ -69,6 +74,7 @@ struct thmc50_data {
        s8 temp_max[3];
        s8 temp_min[3];
        u8 analog_out;
+       u8 alarms;
 };
 
 static int thmc50_attach_adapter(struct i2c_adapter *adapter);
@@ -180,6 +186,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int index = to_sensor_dev_attr(attr)->index;
+       struct thmc50_data *data = thmc50_update_device(dev);
+
+       return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
 #define temp_reg(offset)                                               \
 static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp,    \
                        NULL, offset - 1);                              \
@@ -192,6 +207,12 @@ temp_reg(1);
 temp_reg(2);
 temp_reg(3);
 
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+
 static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
                          set_analog_out, 0);
 static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
@@ -200,9 +221,12 @@ static struct attribute *thmc50_attributes[] = {
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp1_min.dev_attr.attr,
        &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
        &sensor_dev_attr_temp2_max.dev_attr.attr,
        &sensor_dev_attr_temp2_min.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &sensor_dev_attr_pwm1.dev_attr.attr,
        &sensor_dev_attr_pwm1_mode.dev_attr.attr,
        NULL
@@ -213,15 +237,17 @@ static const struct attribute_group thmc50_group = {
 };
 
 /* for ADM1022 3rd temperature mode */
-static struct attribute *adm1022_attributes[] = {
+static struct attribute *temp3_attributes[] = {
        &sensor_dev_attr_temp3_max.dev_attr.attr,
        &sensor_dev_attr_temp3_min.dev_attr.attr,
        &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
        NULL
 };
 
-static const struct attribute_group adm1022_group = {
-       .attrs = adm1022_attributes,
+static const struct attribute_group temp3_group = {
+       .attrs = temp3_attributes,
 };
 
 static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -233,7 +259,7 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
        struct thmc50_data *data;
        struct device *dev;
        int err = 0;
-       const char *type_name = "";
+       const char *type_name;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
                pr_debug("thmc50: detect failed, "
@@ -283,13 +309,9 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
                pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
                goto exit_free;
        }
-       pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
-                type_name, (revision >> 4) - 0xc, revision & 0xf);
        data->type = kind;
 
-       if (kind == thmc50)
-               type_name = "thmc50";
-       else if (kind == adm1022) {
+       if (kind == adm1022) {
                int id = i2c_adapter_id(client->adapter);
                int i;
 
@@ -302,7 +324,11 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
                                data->has_temp3 = 1;
                                break;
                        }
+       } else {
+               type_name = "thmc50";
        }
+       pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
+                type_name, (revision >> 4) - 0xc, revision & 0xf);
 
        /* Fill in the remaining client fields & put it into the global list */
        strlcpy(client->name, type_name, I2C_NAME_SIZE);
@@ -319,23 +345,23 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
                goto exit_detach;
 
        /* Register ADM1022 sysfs hooks */
-       if (data->type == adm1022)
+       if (data->has_temp3)
                if ((err = sysfs_create_group(&client->dev.kobj,
-                                             &adm1022_group)))
+                                             &temp3_group)))
                        goto exit_remove_sysfs_thmc50;
 
        /* Register a new directory entry with module sensors */
-       data->class_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_sysfs;
        }
 
        return 0;
 
 exit_remove_sysfs:
-       if (data->type == adm1022)
-               sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+       if (data->has_temp3)
+               sysfs_remove_group(&client->dev.kobj, &temp3_group);
 exit_remove_sysfs_thmc50:
        sysfs_remove_group(&client->dev.kobj, &thmc50_group);
 exit_detach:
@@ -358,10 +384,10 @@ static int thmc50_detach_client(struct i2c_client *client)
        struct thmc50_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &thmc50_group);
-       if (data->type == adm1022)
-               sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+       if (data->has_temp3)
+               sysfs_remove_group(&client->dev.kobj, &temp3_group);
 
        if ((err = i2c_detach_client(client)))
                return err;
@@ -414,6 +440,8 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
                }
                data->analog_out =
                    i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
+               data->alarms =
+                   i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
                data->last_updated = jiffies;
                data->valid = 1;
        }
index 696c8a2e537473e75e49bda1a97ef81c3dd480da..8f63dada6019347eb9ee40bb4f6ff8c8177ef738 100644 (file)
@@ -294,7 +294,7 @@ static inline long TEMP_FROM_REG10(u16 val)
 struct via686a_data {
        unsigned short addr;
        const char *name;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -627,9 +627,9 @@ static int __devinit via686a_probe(struct platform_device *pdev)
        if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
                goto exit_free;
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -648,7 +648,7 @@ static int __devexit via686a_remove(struct platform_device *pdev)
 {
        struct via686a_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
 
        release_region(data->addr, VIA686A_EXTENT);
index 9f3e332c5b7fe129f6ec9a62baa3201168ecf0c3..e69416465e6dbbe6fae9295d6fcde620568e26da 100644 (file)
@@ -108,7 +108,7 @@ static const u8 bitalarmfan[]       = {6, 7};
 struct vt1211_data {
        unsigned short addr;
        const char *name;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
 
        struct mutex update_lock;
        char valid;                     /* !=0 if following fields are valid */
@@ -1191,9 +1191,9 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
        }
 
        /* Register device */
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                dev_err(dev, "Class registration failed (%d)\n", err);
                goto EXIT_DEV_REMOVE_SILENT;
        }
@@ -1217,7 +1217,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev)
        struct vt1211_data *data = platform_get_drvdata(pdev);
        struct resource *res;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        vt1211_remove_sysfs(pdev);
        platform_set_drvdata(pdev, NULL);
        kfree(data);
index 3e63eaf19041edec1d92ee2207d9f204992bf9b9..2196a84603f5b700178f6157dffbead54999d333 100644 (file)
@@ -148,7 +148,7 @@ struct vt8231_data {
        const char *name;
 
        struct mutex update_lock;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
 
@@ -676,7 +676,7 @@ static struct pci_driver vt8231_pci_driver = {
        .probe          = vt8231_pci_probe,
 };
 
-int vt8231_probe(struct platform_device *pdev)
+static int vt8231_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct vt8231_data *data;
@@ -726,9 +726,9 @@ int vt8231_probe(struct platform_device *pdev)
                }
        }
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
        return 0;
@@ -756,7 +756,7 @@ static int __devexit vt8231_remove(struct platform_device *pdev)
        struct vt8231_data *data = platform_get_drvdata(pdev);
        int i;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
 
        for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
                sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
index d9a9ec7dd84aee91e1e0f7ddbea62bd44f7be7fa..b15c6a998b7271aeb0f45ce21fa21be75be2cf2f 100644 (file)
@@ -223,7 +223,7 @@ temp1_from_reg(s8 reg)
 }
 
 static inline s8
-temp1_to_reg(int temp, int min, int max)
+temp1_to_reg(long temp, int min, int max)
 {
        if (temp <= min)
                return min / 1000;
@@ -256,7 +256,7 @@ struct w83627ehf_data {
        int addr;       /* IO base of hw monitor block */
        const char *name;
 
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
 
        struct mutex update_lock;
@@ -805,7 +805,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
                  const char *buf, size_t count) \
 { \
        struct w83627ehf_data *data = dev_get_drvdata(dev); \
-       u32 val = simple_strtoul(buf, NULL, 10); \
+       long val = simple_strtol(buf, NULL, 10); \
  \
        mutex_lock(&data->update_lock); \
        data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
@@ -840,7 +840,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
        struct w83627ehf_data *data = dev_get_drvdata(dev); \
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
        int nr = sensor_attr->index; \
-       u32 val = simple_strtoul(buf, NULL, 10); \
+       long val = simple_strtol(buf, NULL, 10); \
  \
        mutex_lock(&data->update_lock); \
        data->reg[nr] = LM75_TEMP_TO_REG(val); \
@@ -1384,9 +1384,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
                        goto exit_remove;
        }
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -1406,7 +1406,7 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev)
 {
        struct w83627ehf_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        w83627ehf_device_remove_files(&pdev->dev);
        release_region(data->addr, IOREGION_LENGTH);
        platform_set_drvdata(pdev, NULL);
index 7a4a15f4bf8ba2fd42ebab9c42a9667768dad348..20ae425a1980ce7add4c6a29b055279908a54a60 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
@@ -218,7 +219,7 @@ static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
 static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
                              W83627THF_REG_PWM3 };
 #define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
-                                     regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
+                                   regpwm_627hf[nr] : regpwm[nr])
 
 #define W83627HF_REG_PWM_FREQ          0x5C    /* Only for the 627HF */
 
@@ -263,7 +264,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 
 /* TEMP: 0.001C/bit (-128C to +127C)
    REG: 1C/bit, two's complement */
-static u8 TEMP_TO_REG(int temp)
+static u8 TEMP_TO_REG(long temp)
 {
         int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
         ntemp += (ntemp<0 ? -500 : 500);
@@ -346,7 +347,7 @@ static inline u8 DIV_TO_REG(long val)
 struct w83627hf_data {
        unsigned short addr;
        const char *name;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
        enum chips type;
 
@@ -372,11 +373,8 @@ struct w83627hf_data {
        u8 beep_enable;         /* Boolean */
        u8 pwm[3];              /* Register value */
        u8 pwm_freq[3];         /* Register value */
-       u16 sens[3];            /* 782D/783S only.
-                                  1 = pentium diode; 2 = 3904 diode;
-                                  3000-5000 = thermistor beta.
-                                  Default = 3435.
-                                  Other Betas unimplemented */
+       u16 sens[3];            /* 1 = pentium diode; 2 = 3904 diode;
+                                  4 = thermistor */
        u8 vrm;
        u8 vrm_ovt;             /* Register value, 627THF/637HF/687THF only */
 };
@@ -391,6 +389,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev);
 
 static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
 static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
+static void w83627hf_update_fan_div(struct w83627hf_data *data);
 static struct w83627hf_data *w83627hf_update_device(struct device *dev);
 static void w83627hf_init_device(struct platform_device *pdev);
 
@@ -403,72 +402,71 @@ static struct platform_driver w83627hf_driver = {
        .remove         = __devexit_p(w83627hf_remove),
 };
 
-/* following are the sysfs callback functions */
-#define show_in_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
-       struct w83627hf_data *data = w83627hf_update_device(dev); \
-       return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
+static ssize_t
+show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
 }
-show_in_reg(in)
-show_in_reg(in_min)
-show_in_reg(in_max)
-
-#define store_in_reg(REG, reg) \
-static ssize_t \
-store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
-{ \
-       struct w83627hf_data *data = dev_get_drvdata(dev); \
-       u32 val; \
-        \
-       val = simple_strtoul(buf, NULL, 10); \
-        \
-       mutex_lock(&data->update_lock); \
-       data->in_##reg[nr] = IN_TO_REG(val); \
-       w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \
-                           data->in_##reg[nr]); \
-        \
-       mutex_unlock(&data->update_lock); \
-       return count; \
+static ssize_t
+show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
 }
-store_in_reg(MIN, min)
-store_in_reg(MAX, max)
+static ssize_t
+show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
+}
+static ssize_t
+store_in_min(struct device *dev, struct device_attribute *devattr,
+            const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       long val = simple_strtol(buf, NULL, 10);
 
-#define sysfs_in_offset(offset) \
-static ssize_t \
-show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-        return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
+       mutex_lock(&data->update_lock);
+       data->in_min[nr] = IN_TO_REG(val);
+       w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+static ssize_t
+store_in_max(struct device *dev, struct device_attribute *devattr,
+            const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       long val = simple_strtol(buf, NULL, 10);
 
-#define sysfs_in_reg_offset(reg, offset) \
-static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_in_##reg (dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \
-                           const char *buf, size_t count) \
-{ \
-       return store_in_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
-                 show_regs_in_##reg##offset, store_regs_in_##reg##offset);
-
-#define sysfs_in_offsets(offset) \
-sysfs_in_offset(offset) \
-sysfs_in_reg_offset(min, offset) \
-sysfs_in_reg_offset(max, offset)
-
-sysfs_in_offsets(1);
-sysfs_in_offsets(2);
-sysfs_in_offsets(3);
-sysfs_in_offsets(4);
-sysfs_in_offsets(5);
-sysfs_in_offsets(6);
-sysfs_in_offsets(7);
-sysfs_in_offsets(8);
+       mutex_lock(&data->update_lock);
+       data->in_max[nr] = IN_TO_REG(val);
+       w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+#define sysfs_vin_decl(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,         \
+                         show_in_input, NULL, offset);         \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR,   \
+                         show_in_min, store_in_min, offset);   \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR,   \
+                         show_in_max, store_in_max, offset);
+
+sysfs_vin_decl(1);
+sysfs_vin_decl(2);
+sysfs_vin_decl(3);
+sysfs_vin_decl(4);
+sysfs_vin_decl(5);
+sysfs_vin_decl(6);
+sysfs_vin_decl(7);
+sysfs_vin_decl(8);
 
 /* use a different set of functions for in0 */
 static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
@@ -566,134 +564,148 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
 static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
        show_regs_in_max0, store_regs_in_max0);
 
-#define show_fan_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
-       struct w83627hf_data *data = w83627hf_update_device(dev); \
-       return sprintf(buf,"%ld\n", \
-               FAN_FROM_REG(data->reg[nr-1], \
-                           (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
+static ssize_t
+show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
+                               (long)DIV_FROM_REG(data->fan_div[nr])));
 }
-show_fan_reg(fan);
-show_fan_reg(fan_min);
-
 static ssize_t
-store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
+                               (long)DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *devattr,
+             const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = dev_get_drvdata(dev);
-       u32 val;
-
-       val = simple_strtoul(buf, NULL, 10);
+       u32 val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
-       data->fan_min[nr - 1] =
-           FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
-       w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr),
-                           data->fan_min[nr - 1]);
+       data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+       w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1),
+                            data->fan_min[nr]);
 
        mutex_unlock(&data->update_lock);
        return count;
 }
+#define sysfs_fan_decl(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,                        \
+                         show_fan_input, NULL, offset - 1);            \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,                \
+                         show_fan_min, store_fan_min, offset - 1);
 
-#define sysfs_fan_offset(offset) \
-static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_fan(dev, buf, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
+sysfs_fan_decl(1);
+sysfs_fan_decl(2);
+sysfs_fan_decl(3);
 
-#define sysfs_fan_min_offset(offset) \
-static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_fan_min(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-       return store_fan_min(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
-                 show_regs_fan_min##offset, store_regs_fan_min##offset);
-
-sysfs_fan_offset(1);
-sysfs_fan_min_offset(1);
-sysfs_fan_offset(2);
-sysfs_fan_min_offset(2);
-sysfs_fan_offset(3);
-sysfs_fan_min_offset(3);
-
-#define show_temp_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
-       struct w83627hf_data *data = w83627hf_update_device(dev); \
-       if (nr >= 2) {  /* TEMP2 and TEMP3 */ \
-               return sprintf(buf,"%ld\n", \
-                       (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
-       } else {        /* TEMP1 */ \
-               return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
-       } \
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       if (nr >= 2) {  /* TEMP2 and TEMP3 */
+               return sprintf(buf, "%ld\n",
+                       (long)LM75_TEMP_FROM_REG(data->temp_add[nr-2]));
+       } else {        /* TEMP1 */
+               return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->temp));
+       }
 }
-show_temp_reg(temp);
-show_temp_reg(temp_max);
-show_temp_reg(temp_max_hyst);
 
-#define store_temp_reg(REG, reg) \
-static ssize_t \
-store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
-{ \
-       struct w83627hf_data *data = dev_get_drvdata(dev); \
-       u32 val; \
-        \
-       val = simple_strtoul(buf, NULL, 10); \
-        \
-       mutex_lock(&data->update_lock); \
-        \
-       if (nr >= 2) {  /* TEMP2 and TEMP3 */ \
-               data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
-               w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
-                               data->temp_##reg##_add[nr-2]); \
-       } else {        /* TEMP1 */ \
-               data->temp_##reg = TEMP_TO_REG(val); \
-               w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
-                       data->temp_##reg); \
-       } \
-        \
-       mutex_unlock(&data->update_lock); \
-       return count; \
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *devattr,
+             char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       if (nr >= 2) {  /* TEMP2 and TEMP3 */
+               return sprintf(buf, "%ld\n",
+                       (long)LM75_TEMP_FROM_REG(data->temp_max_add[nr-2]));
+       } else {        /* TEMP1 */
+               return sprintf(buf, "%ld\n",
+                       (long)TEMP_FROM_REG(data->temp_max));
+       }
 }
-store_temp_reg(OVER, max);
-store_temp_reg(HYST, max_hyst);
 
-#define sysfs_temp_offset(offset) \
-static ssize_t \
-show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_temp(dev, buf, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
+static ssize_t
+show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+                  char *buf)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       if (nr >= 2) {  /* TEMP2 and TEMP3 */
+               return sprintf(buf, "%ld\n",
+                       (long)LM75_TEMP_FROM_REG(data->temp_max_hyst_add[nr-2]));
+       } else {        /* TEMP1 */
+               return sprintf(buf, "%ld\n",
+                       (long)TEMP_FROM_REG(data->temp_max_hyst));
+       }
+}
 
-#define sysfs_temp_reg_offset(reg, offset) \
-static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_temp_##reg (dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \
-                             const char *buf, size_t count) \
-{ \
-       return store_temp_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
-                 show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
+static ssize_t
+store_temp_max(struct device *dev, struct device_attribute *devattr,
+              const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       long val = simple_strtol(buf, NULL, 10);
 
-#define sysfs_temp_offsets(offset) \
-sysfs_temp_offset(offset) \
-sysfs_temp_reg_offset(max, offset) \
-sysfs_temp_reg_offset(max_hyst, offset)
+       mutex_lock(&data->update_lock);
 
-sysfs_temp_offsets(1);
-sysfs_temp_offsets(2);
-sysfs_temp_offsets(3);
+       if (nr >= 2) {  /* TEMP2 and TEMP3 */
+               data->temp_max_add[nr-2] = LM75_TEMP_TO_REG(val);
+               w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
+                               data->temp_max_add[nr-2]);
+       } else {        /* TEMP1 */
+               data->temp_max = TEMP_TO_REG(val);
+               w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
+                       data->temp_max);
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+                   const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(devattr)->index;
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+
+       if (nr >= 2) {  /* TEMP2 and TEMP3 */
+               data->temp_max_hyst_add[nr-2] = LM75_TEMP_TO_REG(val);
+               w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
+                               data->temp_max_hyst_add[nr-2]);
+       } else {        /* TEMP1 */
+               data->temp_max_hyst = TEMP_TO_REG(val);
+               w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
+                       data->temp_max_hyst);
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+#define sysfs_temp_decl(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,               \
+                         show_temp, NULL, offset);                     \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR,         \
+                         show_temp_max, store_temp_max, offset);       \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR,    \
+                         show_temp_max_hyst, store_temp_max_hyst, offset);
+
+sysfs_temp_decl(1);
+sysfs_temp_decl(2);
+sysfs_temp_decl(3);
 
 static ssize_t
 show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -706,7 +718,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 static ssize_t
 show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct w83627hf_data *data = w83627hf_update_device(dev);
+       struct w83627hf_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 static ssize_t
@@ -791,20 +803,22 @@ sysfs_beep(ENABLE, enable);
 sysfs_beep(MASK, mask);
 
 static ssize_t
-show_fan_div_reg(struct device *dev, char *buf, int nr)
+show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = w83627hf_update_device(dev);
        return sprintf(buf, "%ld\n",
-                      (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+                      (long) DIV_FROM_REG(data->fan_div[nr]));
 }
-
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
    least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t
-store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_div(struct device *dev, struct device_attribute *devattr,
+             const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = dev_get_drvdata(dev);
        unsigned long min;
        u8 reg;
@@ -836,92 +850,72 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
        return count;
 }
 
-#define sysfs_fan_div(offset) \
-static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_fan_div_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \
-                           const char *buf, size_t count) \
-{ \
-       return store_fan_div_reg(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
-                 show_regs_fan_div_##offset, store_regs_fan_div_##offset);
-
-sysfs_fan_div(1);
-sysfs_fan_div(2);
-sysfs_fan_div(3);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
+                         show_fan_div, store_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
+                         show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
+                         show_fan_div, store_fan_div, 2);
 
 static ssize_t
-show_pwm_reg(struct device *dev, char *buf, int nr)
+show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = w83627hf_update_device(dev);
-       return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]);
+       return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
 }
 
 static ssize_t
-store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm(struct device *dev, struct device_attribute *devattr,
+         const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = dev_get_drvdata(dev);
-       u32 val;
-
-       val = simple_strtoul(buf, NULL, 10);
+       u32 val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
 
        if (data->type == w83627thf) {
                /* bits 0-3 are reserved  in 627THF */
-               data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
+               data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
                w83627hf_write_value(data,
                                     W836X7HF_REG_PWM(data->type, nr),
-                                    data->pwm[nr - 1] |
+                                    data->pwm[nr] |
                                     (w83627hf_read_value(data,
                                     W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
        } else {
-               data->pwm[nr - 1] = PWM_TO_REG(val);
+               data->pwm[nr] = PWM_TO_REG(val);
                w83627hf_write_value(data,
                                     W836X7HF_REG_PWM(data->type, nr),
-                                    data->pwm[nr - 1]);
+                                    data->pwm[nr]);
        }
 
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-#define sysfs_pwm(offset) \
-static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-       return show_pwm_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-       return store_pwm_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
-                 show_regs_pwm_##offset, store_regs_pwm_##offset);
-
-sysfs_pwm(1);
-sysfs_pwm(2);
-sysfs_pwm(3);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
 
 static ssize_t
-show_pwm_freq_reg(struct device *dev, char *buf, int nr)
+show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = w83627hf_update_device(dev);
        if (data->type == w83627hf)
                return sprintf(buf, "%ld\n",
-                       pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
+                       pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
        else
                return sprintf(buf, "%ld\n",
-                       pwm_freq_from_reg(data->pwm_freq[nr - 1]));
+                       pwm_freq_from_reg(data->pwm_freq[nr]));
 }
 
 static ssize_t
-store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm_freq(struct device *dev, struct device_attribute *devattr,
+              const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = dev_get_drvdata(dev);
        static const u8 mask[]={0xF8, 0x8F};
        u32 val;
@@ -931,50 +925,42 @@ store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
        mutex_lock(&data->update_lock);
 
        if (data->type == w83627hf) {
-               data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
+               data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
                w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
-                               (data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
+                               (data->pwm_freq[nr] << (nr*4)) |
                                (w83627hf_read_value(data,
-                               W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
+                               W83627HF_REG_PWM_FREQ) & mask[nr]));
        } else {
-               data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
-               w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
-                               data->pwm_freq[nr - 1]);
+               data->pwm_freq[nr] = pwm_freq_to_reg(val);
+               w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
+                               data->pwm_freq[nr]);
        }
 
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-#define sysfs_pwm_freq(offset) \
-static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
-               struct device_attribute *attr, char *buf) \
-{ \
-       return show_pwm_freq_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_pwm_freq_##offset(struct device *dev, \
-               struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-       return store_pwm_freq_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
-                 show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
-
-sysfs_pwm_freq(1);
-sysfs_pwm_freq(2);
-sysfs_pwm_freq(3);
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
+                         show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
+                         show_pwm_freq, store_pwm_freq, 1);
+static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
+                         show_pwm_freq, store_pwm_freq, 2);
 
 static ssize_t
-show_sensor_reg(struct device *dev, char *buf, int nr)
+show_temp_type(struct device *dev, struct device_attribute *devattr,
+              char *buf)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = w83627hf_update_device(dev);
-       return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
+       return sprintf(buf, "%ld\n", (long) data->sens[nr]);
 }
 
 static ssize_t
-store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_temp_type(struct device *dev, struct device_attribute *devattr,
+               const char *buf, size_t count)
 {
+       int nr = to_sensor_dev_attr(devattr)->index;
        struct w83627hf_data *data = dev_get_drvdata(dev);
        u32 val, tmp;
 
@@ -986,31 +972,35 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
        case 1:         /* PII/Celeron diode */
                tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
                w83627hf_write_value(data, W83781D_REG_SCFG1,
-                                   tmp | BIT_SCFG1[nr - 1]);
+                                   tmp | BIT_SCFG1[nr]);
                tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
                w83627hf_write_value(data, W83781D_REG_SCFG2,
-                                   tmp | BIT_SCFG2[nr - 1]);
-               data->sens[nr - 1] = val;
+                                   tmp | BIT_SCFG2[nr]);
+               data->sens[nr] = val;
                break;
        case 2:         /* 3904 */
                tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
                w83627hf_write_value(data, W83781D_REG_SCFG1,
-                                   tmp | BIT_SCFG1[nr - 1]);
+                                   tmp | BIT_SCFG1[nr]);
                tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
                w83627hf_write_value(data, W83781D_REG_SCFG2,
-                                   tmp & ~BIT_SCFG2[nr - 1]);
-               data->sens[nr - 1] = val;
+                                   tmp & ~BIT_SCFG2[nr]);
+               data->sens[nr] = val;
                break;
-       case W83781D_DEFAULT_BETA:      /* thermistor */
+       case W83781D_DEFAULT_BETA:
+               dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
+                        "instead\n", W83781D_DEFAULT_BETA);
+               /* fall through */
+       case 4:         /* thermistor */
                tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
                w83627hf_write_value(data, W83781D_REG_SCFG1,
-                                   tmp & ~BIT_SCFG1[nr - 1]);
-               data->sens[nr - 1] = val;
+                                   tmp & ~BIT_SCFG1[nr]);
+               data->sens[nr] = val;
                break;
        default:
                dev_err(dev,
-                      "Invalid sensor type %ld; must be 1, 2, or %d\n",
-                      (long) val, W83781D_DEFAULT_BETA);
+                      "Invalid sensor type %ld; must be 1, 2, or 4\n",
+                      (long) val);
                break;
        }
 
@@ -1018,25 +1008,16 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
        return count;
 }
 
-#define sysfs_sensor(offset) \
-static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-    return show_sensor_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-    return store_sensor_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
-                 show_regs_sensor_##offset, store_regs_sensor_##offset);
+#define sysfs_temp_type(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
+                         show_temp_type, store_temp_type, offset - 1);
 
-sysfs_sensor(1);
-sysfs_sensor(2);
-sysfs_sensor(3);
+sysfs_temp_type(1);
+sysfs_temp_type(2);
+sysfs_temp_type(3);
 
-static ssize_t show_name(struct device *dev, struct device_attribute
-                        *devattr, char *buf)
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
 {
        struct w83627hf_data *data = dev_get_drvdata(dev);
 
@@ -1118,49 +1099,44 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
        return err;
 }
 
+#define VIN_UNIT_ATTRS(_X_)    \
+       &sensor_dev_attr_in##_X_##_input.dev_attr.attr,         \
+       &sensor_dev_attr_in##_X_##_min.dev_attr.attr,           \
+       &sensor_dev_attr_in##_X_##_max.dev_attr.attr
+
+#define FAN_UNIT_ATTRS(_X_)    \
+       &sensor_dev_attr_fan##_X_##_input.dev_attr.attr,        \
+       &sensor_dev_attr_fan##_X_##_min.dev_attr.attr,          \
+       &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(_X_)   \
+       &sensor_dev_attr_temp##_X_##_input.dev_attr.attr,       \
+       &sensor_dev_attr_temp##_X_##_max.dev_attr.attr,         \
+       &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr,    \
+       &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
+
 static struct attribute *w83627hf_attributes[] = {
        &dev_attr_in0_input.attr,
        &dev_attr_in0_min.attr,
        &dev_attr_in0_max.attr,
-       &dev_attr_in2_input.attr,
-       &dev_attr_in2_min.attr,
-       &dev_attr_in2_max.attr,
-       &dev_attr_in3_input.attr,
-       &dev_attr_in3_min.attr,
-       &dev_attr_in3_max.attr,
-       &dev_attr_in4_input.attr,
-       &dev_attr_in4_min.attr,
-       &dev_attr_in4_max.attr,
-       &dev_attr_in7_input.attr,
-       &dev_attr_in7_min.attr,
-       &dev_attr_in7_max.attr,
-       &dev_attr_in8_input.attr,
-       &dev_attr_in8_min.attr,
-       &dev_attr_in8_max.attr,
-
-       &dev_attr_fan1_input.attr,
-       &dev_attr_fan1_min.attr,
-       &dev_attr_fan1_div.attr,
-       &dev_attr_fan2_input.attr,
-       &dev_attr_fan2_min.attr,
-       &dev_attr_fan2_div.attr,
-
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp1_max.attr,
-       &dev_attr_temp1_max_hyst.attr,
-       &dev_attr_temp1_type.attr,
-       &dev_attr_temp2_input.attr,
-       &dev_attr_temp2_max.attr,
-       &dev_attr_temp2_max_hyst.attr,
-       &dev_attr_temp2_type.attr,
+       VIN_UNIT_ATTRS(2),
+       VIN_UNIT_ATTRS(3),
+       VIN_UNIT_ATTRS(4),
+       VIN_UNIT_ATTRS(7),
+       VIN_UNIT_ATTRS(8),
+
+       FAN_UNIT_ATTRS(1),
+       FAN_UNIT_ATTRS(2),
+
+       TEMP_UNIT_ATTRS(1),
+       TEMP_UNIT_ATTRS(2),
 
        &dev_attr_alarms.attr,
        &dev_attr_beep_enable.attr,
        &dev_attr_beep_mask.attr,
 
-       &dev_attr_pwm1.attr,
-       &dev_attr_pwm2.attr,
-
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
        &dev_attr_name.attr,
        NULL
 };
@@ -1170,30 +1146,17 @@ static const struct attribute_group w83627hf_group = {
 };
 
 static struct attribute *w83627hf_attributes_opt[] = {
-       &dev_attr_in1_input.attr,
-       &dev_attr_in1_min.attr,
-       &dev_attr_in1_max.attr,
-       &dev_attr_in5_input.attr,
-       &dev_attr_in5_min.attr,
-       &dev_attr_in5_max.attr,
-       &dev_attr_in6_input.attr,
-       &dev_attr_in6_min.attr,
-       &dev_attr_in6_max.attr,
-
-       &dev_attr_fan3_input.attr,
-       &dev_attr_fan3_min.attr,
-       &dev_attr_fan3_div.attr,
-
-       &dev_attr_temp3_input.attr,
-       &dev_attr_temp3_max.attr,
-       &dev_attr_temp3_max_hyst.attr,
-       &dev_attr_temp3_type.attr,
-
-       &dev_attr_pwm3.attr,
-
-       &dev_attr_pwm1_freq.attr,
-       &dev_attr_pwm2_freq.attr,
-       &dev_attr_pwm3_freq.attr,
+       VIN_UNIT_ATTRS(1),
+       VIN_UNIT_ATTRS(5),
+       VIN_UNIT_ATTRS(6),
+
+       FAN_UNIT_ATTRS(3),
+       TEMP_UNIT_ATTRS(3),
+       &sensor_dev_attr_pwm3.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+       &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+       &sensor_dev_attr_pwm3_freq.dev_attr.attr,
        NULL
 };
 
@@ -1244,6 +1207,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
        data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
        data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
        data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
+       w83627hf_update_fan_div(data);
 
        /* Register common device attributes */
        if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
@@ -1251,27 +1215,45 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 
        /* Register chip-specific device attributes */
        if (data->type == w83627hf || data->type == w83697hf)
-               if ((err = device_create_file(dev, &dev_attr_in5_input))
-                || (err = device_create_file(dev, &dev_attr_in5_min))
-                || (err = device_create_file(dev, &dev_attr_in5_max))
-                || (err = device_create_file(dev, &dev_attr_in6_input))
-                || (err = device_create_file(dev, &dev_attr_in6_min))
-                || (err = device_create_file(dev, &dev_attr_in6_max))
-                || (err = device_create_file(dev, &dev_attr_pwm1_freq))
-                || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
+               if ((err = device_create_file(dev,
+                               &sensor_dev_attr_in5_input.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in5_min.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in5_max.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in6_input.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in6_min.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in6_max.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_pwm1_freq.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_pwm2_freq.dev_attr)))
                        goto ERROR4;
 
        if (data->type != w83697hf)
-               if ((err = device_create_file(dev, &dev_attr_in1_input))
-                || (err = device_create_file(dev, &dev_attr_in1_min))
-                || (err = device_create_file(dev, &dev_attr_in1_max))
-                || (err = device_create_file(dev, &dev_attr_fan3_input))
-                || (err = device_create_file(dev, &dev_attr_fan3_min))
-                || (err = device_create_file(dev, &dev_attr_fan3_div))
-                || (err = device_create_file(dev, &dev_attr_temp3_input))
-                || (err = device_create_file(dev, &dev_attr_temp3_max))
-                || (err = device_create_file(dev, &dev_attr_temp3_max_hyst))
-                || (err = device_create_file(dev, &dev_attr_temp3_type)))
+               if ((err = device_create_file(dev,
+                               &sensor_dev_attr_in1_input.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in1_min.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_in1_max.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_fan3_input.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_fan3_min.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_fan3_div.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_input.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_max.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_max_hyst.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_type.dev_attr)))
                        goto ERROR4;
 
        if (data->type != w83697hf && data->vid != 0xff) {
@@ -1285,18 +1267,22 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 
        if (data->type == w83627thf || data->type == w83637hf
         || data->type == w83687thf)
-               if ((err = device_create_file(dev, &dev_attr_pwm3)))
+               if ((err = device_create_file(dev,
+                               &sensor_dev_attr_pwm3.dev_attr)))
                        goto ERROR4;
 
        if (data->type == w83637hf || data->type == w83687thf)
-               if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
-                || (err = device_create_file(dev, &dev_attr_pwm2_freq))
-                || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
+               if ((err = device_create_file(dev,
+                               &sensor_dev_attr_pwm1_freq.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_pwm2_freq.dev_attr))
+                || (err = device_create_file(dev,
+                               &sensor_dev_attr_pwm3_freq.dev_attr)))
                        goto ERROR4;
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto ERROR4;
        }
 
@@ -1319,7 +1305,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
        struct w83627hf_data *data = platform_get_drvdata(pdev);
        struct resource *res;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
 
        sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
        sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
@@ -1333,6 +1319,24 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
 }
 
 
+/* Registers 0x50-0x5f are banked */
+static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
+{
+       if ((reg & 0x00f0) == 0x50) {
+               outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+               outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
+       }
+}
+
+/* Not strictly necessary, but play it safe for now */
+static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
+{
+       if (reg & 0xff00) {
+               outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+               outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
+       }
+}
+
 static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 {
        int res, word_sized;
@@ -1343,12 +1347,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
                  && (((reg & 0x00ff) == 0x50)
                   || ((reg & 0x00ff) == 0x53)
                   || ((reg & 0x00ff) == 0x55));
-       if (reg & 0xff00) {
-               outb_p(W83781D_REG_BANK,
-                      data->addr + W83781D_ADDR_REG_OFFSET);
-               outb_p(reg >> 8,
-                      data->addr + W83781D_DATA_REG_OFFSET);
-       }
+       w83627hf_set_bank(data, reg);
        outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
        res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
        if (word_sized) {
@@ -1358,11 +1357,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
                    (res << 8) + inb_p(data->addr +
                                       W83781D_DATA_REG_OFFSET);
        }
-       if (reg & 0xff00) {
-               outb_p(W83781D_REG_BANK,
-                      data->addr + W83781D_ADDR_REG_OFFSET);
-               outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
-       }
+       w83627hf_reset_bank(data, reg);
        mutex_unlock(&data->lock);
        return res;
 }
@@ -1433,12 +1428,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
                   || ((reg & 0xff00) == 0x200))
                  && (((reg & 0x00ff) == 0x53)
                   || ((reg & 0x00ff) == 0x55));
-       if (reg & 0xff00) {
-               outb_p(W83781D_REG_BANK,
-                      data->addr + W83781D_ADDR_REG_OFFSET);
-               outb_p(reg >> 8,
-                      data->addr + W83781D_DATA_REG_OFFSET);
-       }
+       w83627hf_set_bank(data, reg);
        outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
        if (word_sized) {
                outb_p(value >> 8,
@@ -1448,11 +1438,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
        }
        outb_p(value & 0xff,
               data->addr + W83781D_DATA_REG_OFFSET);
-       if (reg & 0xff00) {
-               outb_p(W83781D_REG_BANK,
-                      data->addr + W83781D_ADDR_REG_OFFSET);
-               outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
-       }
+       w83627hf_reset_bank(data, reg);
        mutex_unlock(&data->lock);
        return 0;
 }
@@ -1513,7 +1499,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
        tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
        for (i = 1; i <= 3; i++) {
                if (!(tmp & BIT_SCFG1[i - 1])) {
-                       data->sens[i - 1] = W83781D_DEFAULT_BETA;
+                       data->sens[i - 1] = 4;
                } else {
                        if (w83627hf_read_value
                            (data,
@@ -1556,6 +1542,24 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
                            | 0x01);
 }
 
+static void w83627hf_update_fan_div(struct w83627hf_data *data)
+{
+       int reg;
+
+       reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
+       data->fan_div[0] = (reg >> 4) & 0x03;
+       data->fan_div[1] = (reg >> 6) & 0x03;
+       if (data->type != w83697hf) {
+               data->fan_div[2] = (w83627hf_read_value(data,
+                                      W83781D_REG_PIN) >> 6) & 0x03;
+       }
+       reg = w83627hf_read_value(data, W83781D_REG_VBAT);
+       data->fan_div[0] |= (reg >> 3) & 0x04;
+       data->fan_div[1] |= (reg >> 4) & 0x04;
+       if (data->type != w83697hf)
+               data->fan_div[2] |= (reg >> 5) & 0x04;
+}
+
 static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 {
        struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -1587,15 +1591,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
                            w83627hf_read_value(data,
                                               W83781D_REG_FAN_MIN(i));
                }
-               for (i = 1; i <= 3; i++) {
+               for (i = 0; i <= 2; i++) {
                        u8 tmp = w83627hf_read_value(data,
                                W836X7HF_REG_PWM(data->type, i));
                        /* bits 0-3 are reserved  in 627THF */
                        if (data->type == w83627thf)
                                tmp &= 0xf0;
-                       data->pwm[i - 1] = tmp;
-                       if(i == 2 &&
-                          (data->type == w83627hf || data->type == w83697hf))
+                       data->pwm[i] = tmp;
+                       if (i == 1 &&
+                           (data->type == w83627hf || data->type == w83697hf))
                                break;
                }
                if (data->type == w83627hf) {
@@ -1633,18 +1637,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
                          w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
                }
 
-               i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
-               data->fan_div[0] = (i >> 4) & 0x03;
-               data->fan_div[1] = (i >> 6) & 0x03;
-               if (data->type != w83697hf) {
-                       data->fan_div[2] = (w83627hf_read_value(data,
-                                              W83781D_REG_PIN) >> 6) & 0x03;
-               }
-               i = w83627hf_read_value(data, W83781D_REG_VBAT);
-               data->fan_div[0] |= (i >> 3) & 0x04;
-               data->fan_div[1] |= (i >> 4) & 0x04;
-               if (data->type != w83697hf)
-                       data->fan_div[2] |= (i >> 5) & 0x04;
+               w83627hf_update_fan_div(data);
+
                data->alarms =
                    w83627hf_read_value(data, W83781D_REG_ALARM1) |
                    (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
index dcc941a5aaff6e06d286868b52b50f98126ffb84..a6a1edfe76141e8a9fb5fb058a13014d90787ac9 100644 (file)
@@ -220,7 +220,7 @@ DIV_TO_REG(long val, enum chips type)
    the driver field to differentiate between I2C and ISA chips. */
 struct w83781d_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex lock;
        enum chips type;
 
@@ -251,9 +251,7 @@ struct w83781d_data {
        u8 pwm2_enable;         /* Boolean */
        u16 sens[3];            /* 782D/783S only.
                                   1 = pentium diode; 2 = 3904 diode;
-                                  3000-5000 = thermistor beta.
-                                  Default = 3435. 
-                                  Other Betas unimplemented */
+                                  4 = thermistor */
        u8 vrm;
 };
 
@@ -410,7 +408,7 @@ static ssize_t store_temp_##reg (struct device *dev, \
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
        struct w83781d_data *data = dev_get_drvdata(dev); \
        int nr = attr->index; \
-       s32 val; \
+       long val; \
         \
        val = simple_strtol(buf, NULL, 10); \
         \
@@ -456,7 +454,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 static ssize_t
 show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct w83781d_data *data = w83781d_update_device(dev);
+       struct w83781d_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 
@@ -483,6 +481,39 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
 
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct w83781d_data *data = w83781d_update_device(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+/* The W83781D has a single alarm bit for temp2 and temp3 */
+static ssize_t show_temp3_alarm(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct w83781d_data *data = w83781d_update_device(dev);
+       int bitnr = (data->type == w83781d) ? 5 : 13;
+       return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
+
 static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct w83781d_data *data = w83781d_update_device(dev);
@@ -546,6 +577,100 @@ static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
 static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
                show_beep_enable, store_beep_enable);
 
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct w83781d_data *data = w83781d_update_device(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct w83781d_data *data = dev_get_drvdata(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       unsigned long bit;
+       u8 reg;
+
+       bit = simple_strtoul(buf, NULL, 10);
+       if (bit & ~1)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       if (bit)
+               data->beep_mask |= (1 << bitnr);
+       else
+               data->beep_mask &= ~(1 << bitnr);
+
+       if (bitnr < 8) {
+               reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
+               if (bit)
+                       reg |= (1 << bitnr);
+               else
+                       reg &= ~(1 << bitnr);
+               w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
+       } else if (bitnr < 16) {
+               reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
+               if (bit)
+                       reg |= (1 << (bitnr - 8));
+               else
+                       reg &= ~(1 << (bitnr - 8));
+               w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
+       } else {
+               reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
+               if (bit)
+                       reg |= (1 << (bitnr - 16));
+               else
+                       reg &= ~(1 << (bitnr - 16));
+               w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/* The W83781D has a single beep bit for temp2 and temp3 */
+static ssize_t show_temp3_beep(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct w83781d_data *data = w83781d_update_device(dev);
+       int bitnr = (data->type == w83781d) ? 5 : 13;
+       return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 3);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 8);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 9);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 10);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 16);
+static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 17);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 6);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 7);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 11);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 4);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
+                       show_beep, store_beep, 5);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
+                       show_temp3_beep, store_beep, 13);
+
 static ssize_t
 show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
 {
@@ -721,15 +846,19 @@ store_sensor(struct device *dev, struct device_attribute *da,
                                    tmp & ~BIT_SCFG2[nr]);
                data->sens[nr] = val;
                break;
-       case W83781D_DEFAULT_BETA:      /* thermistor */
+       case W83781D_DEFAULT_BETA:
+               dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
+                        "instead\n", W83781D_DEFAULT_BETA);
+               /* fall through */
+       case 4:         /* thermistor */
                tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
                w83781d_write_value(data, W83781D_REG_SCFG1,
                                    tmp & ~BIT_SCFG1[nr]);
                data->sens[nr] = val;
                break;
        default:
-               dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
-                      (long) val, W83781D_DEFAULT_BETA);
+               dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
+                      (long) val);
                break;
        }
 
@@ -875,17 +1004,23 @@ ERROR_SC_0:
 #define IN_UNIT_ATTRS(X)                                       \
        &sensor_dev_attr_in##X##_input.dev_attr.attr,           \
        &sensor_dev_attr_in##X##_min.dev_attr.attr,             \
-       &sensor_dev_attr_in##X##_max.dev_attr.attr
+       &sensor_dev_attr_in##X##_max.dev_attr.attr,             \
+       &sensor_dev_attr_in##X##_alarm.dev_attr.attr,           \
+       &sensor_dev_attr_in##X##_beep.dev_attr.attr
 
 #define FAN_UNIT_ATTRS(X)                                      \
        &sensor_dev_attr_fan##X##_input.dev_attr.attr,          \
        &sensor_dev_attr_fan##X##_min.dev_attr.attr,            \
-       &sensor_dev_attr_fan##X##_div.dev_attr.attr
+       &sensor_dev_attr_fan##X##_div.dev_attr.attr,            \
+       &sensor_dev_attr_fan##X##_alarm.dev_attr.attr,          \
+       &sensor_dev_attr_fan##X##_beep.dev_attr.attr
 
 #define TEMP_UNIT_ATTRS(X)                                     \
        &sensor_dev_attr_temp##X##_input.dev_attr.attr,         \
        &sensor_dev_attr_temp##X##_max.dev_attr.attr,           \
-       &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr
+       &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr,      \
+       &sensor_dev_attr_temp##X##_alarm.dev_attr.attr,         \
+       &sensor_dev_attr_temp##X##_beep.dev_attr.attr
 
 static struct attribute* w83781d_attributes[] = {
        IN_UNIT_ATTRS(0),
@@ -944,7 +1079,11 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
                    || (err = device_create_file(dev,
                                &sensor_dev_attr_in1_min.dev_attr))
                    || (err = device_create_file(dev,
-                               &sensor_dev_attr_in1_max.dev_attr)))
+                               &sensor_dev_attr_in1_max.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_in1_alarm.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_in1_beep.dev_attr)))
                        return err;
        }
        if (kind != as99127f && kind != w83781d && kind != w83783s) {
@@ -954,12 +1093,20 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
                                &sensor_dev_attr_in7_min.dev_attr))
                    || (err = device_create_file(dev,
                                &sensor_dev_attr_in7_max.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_in7_alarm.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_in7_beep.dev_attr))
                    || (err = device_create_file(dev,
                                &sensor_dev_attr_in8_input.dev_attr))
                    || (err = device_create_file(dev,
                                &sensor_dev_attr_in8_min.dev_attr))
                    || (err = device_create_file(dev,
-                               &sensor_dev_attr_in8_max.dev_attr)))
+                               &sensor_dev_attr_in8_max.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_in8_alarm.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_in8_beep.dev_attr)))
                        return err;
        }
        if (kind != w83783s) {
@@ -968,8 +1115,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
                    || (err = device_create_file(dev,
                                &sensor_dev_attr_temp3_max.dev_attr))
                    || (err = device_create_file(dev,
-                               &sensor_dev_attr_temp3_max_hyst.dev_attr)))
+                               &sensor_dev_attr_temp3_max_hyst.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_alarm.dev_attr))
+                   || (err = device_create_file(dev,
+                               &sensor_dev_attr_temp3_beep.dev_attr)))
                        return err;
+
+               if (kind != w83781d)
+                       err = sysfs_chmod_file(&dev->kobj,
+                               &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+                               S_IRUGO | S_IWUSR);
+                       if (err)
+                               return err;
        }
 
        if (kind != w83781d && kind != as99127f) {
@@ -1156,9 +1314,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
        if (err)
                goto ERROR4;
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto ERROR4;
        }
 
@@ -1192,7 +1350,7 @@ w83781d_detach_client(struct i2c_client *client)
 
        /* main client */
        if (data) {
-               hwmon_device_unregister(data->class_dev);
+               hwmon_device_unregister(data->hwmon_dev);
                sysfs_remove_group(&client->dev.kobj, &w83781d_group);
                sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
        }
@@ -1259,9 +1417,9 @@ w83781d_isa_probe(struct platform_device *pdev)
        if (err)
                goto exit_remove_files;
 
-       data->class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -1283,7 +1441,7 @@ w83781d_isa_remove(struct platform_device *pdev)
 {
        struct w83781d_data *data = platform_get_drvdata(pdev);
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
        sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
        device_remove_file(&pdev->dev, &dev_attr_name);
@@ -1485,7 +1643,7 @@ w83781d_init_device(struct device *dev)
                tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
                for (i = 1; i <= 3; i++) {
                        if (!(tmp & BIT_SCFG1[i - 1])) {
-                               data->sens[i - 1] = W83781D_DEFAULT_BETA;
+                               data->sens[i - 1] = 4;
                        } else {
                                if (w83781d_read_value
                                    (data,
index 9e5f885368b4e3f8e697be2ef0138f9bc8eb03f0..b6f2ebf9f9cf54e4648c8772856bbd4f0952d0a7 100644 (file)
@@ -2,7 +2,7 @@
     w83791d.c - Part of lm_sensors, Linux kernel modules for hardware
                 monitoring
 
-    Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com>
+    Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -247,7 +247,7 @@ static u8 div_to_reg(int nr, long val)
 
 struct w83791d_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
 
        char valid;                     /* !=0 if following fields are valid */
@@ -384,6 +384,85 @@ static struct sensor_device_attribute sda_in_max[] = {
        SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
 };
 
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr =
+                                               to_sensor_dev_attr(attr);
+       struct w83791d_data *data = w83791d_update_device(dev);
+       int bitnr = sensor_attr->index;
+
+       return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t store_beep(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr =
+                                               to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83791d_data *data = i2c_get_clientdata(client);
+       int bitnr = sensor_attr->index;
+       int bytenr = bitnr / 8;
+       long val = simple_strtol(buf, NULL, 10) ? 1 : 0;
+
+       mutex_lock(&data->update_lock);
+
+       data->beep_mask &= ~(0xff << (bytenr * 8));
+       data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr])
+               << (bytenr * 8);
+
+       data->beep_mask &= ~(1 << bitnr);
+       data->beep_mask |= val << bitnr;
+
+       w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr],
+               (data->beep_mask >> (bytenr * 8)) & 0xff);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct sensor_device_attribute *sensor_attr =
+                                               to_sensor_dev_attr(attr);
+       struct w83791d_data *data = w83791d_update_device(dev);
+       int bitnr = sensor_attr->index;
+
+       return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+/* Note: The bitmask for the beep enable/disable is different than
+   the bitmask for the alarm. */
+static struct sensor_device_attribute sda_in_beep[] = {
+       SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0),
+       SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13),
+       SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2),
+       SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3),
+       SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8),
+       SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9),
+       SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10),
+       SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16),
+       SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17),
+       SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14),
+};
+
+static struct sensor_device_attribute sda_in_alarm[] = {
+       SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
+       SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
+       SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
+       SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
+       SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
+       SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9),
+       SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10),
+       SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19),
+       SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20),
+       SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14),
+};
+
 #define show_fan_reg(reg) \
 static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
                                char *buf) \
@@ -536,6 +615,22 @@ static struct sensor_device_attribute sda_fan_div[] = {
                        show_fan_div, store_fan_div, 4),
 };
 
+static struct sensor_device_attribute sda_fan_beep[] = {
+       SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6),
+       SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7),
+       SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11),
+       SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21),
+       SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+       SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
+       SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
+       SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
+       SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21),
+       SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22),
+};
+
 /* read/write the temperature1, includes measured value and limits */
 static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
                                char *buf)
@@ -618,6 +713,19 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
                        show_temp23, store_temp23, 1, 2),
 };
 
+/* Note: The bitmask for the beep enable/disable is different than
+   the bitmask for the alarm. */
+static struct sensor_device_attribute sda_temp_beep[] = {
+       SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4),
+       SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5),
+       SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+       SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
+       SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
+       SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
 
 /* get reatime status of all sensors items: voltage, temp, fan */
 static ssize_t show_alarms_reg(struct device *dev,
@@ -724,7 +832,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 static ssize_t show_vrm_reg(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct w83791d_data *data = w83791d_update_device(dev);
+       struct w83791d_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", data->vrm);
 }
 
@@ -749,17 +857,23 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
 #define IN_UNIT_ATTRS(X) \
        &sda_in_input[X].dev_attr.attr, \
        &sda_in_min[X].dev_attr.attr,   \
-       &sda_in_max[X].dev_attr.attr
+       &sda_in_max[X].dev_attr.attr,   \
+       &sda_in_beep[X].dev_attr.attr,  \
+       &sda_in_alarm[X].dev_attr.attr
 
 #define FAN_UNIT_ATTRS(X) \
        &sda_fan_input[X].dev_attr.attr,        \
        &sda_fan_min[X].dev_attr.attr,          \
-       &sda_fan_div[X].dev_attr.attr
+       &sda_fan_div[X].dev_attr.attr,          \
+       &sda_fan_beep[X].dev_attr.attr,         \
+       &sda_fan_alarm[X].dev_attr.attr
 
 #define TEMP_UNIT_ATTRS(X) \
        &sda_temp_input[X].dev_attr.attr,       \
        &sda_temp_max[X].dev_attr.attr,         \
-       &sda_temp_max_hyst[X].dev_attr.attr
+       &sda_temp_max_hyst[X].dev_attr.attr,    \
+       &sda_temp_beep[X].dev_attr.attr,        \
+       &sda_temp_alarm[X].dev_attr.attr
 
 static struct attribute *w83791d_attributes[] = {
        IN_UNIT_ATTRS(0),
@@ -1017,9 +1131,9 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
                goto error3;
 
        /* Everything is ready, now register the working device */
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto error4;
        }
 
@@ -1051,7 +1165,7 @@ static int w83791d_detach_client(struct i2c_client *client)
 
        /* main client */
        if (data) {
-               hwmon_device_unregister(data->class_dev);
+               hwmon_device_unregister(data->hwmon_dev);
                sysfs_remove_group(&client->dev.kobj, &w83791d_group);
        }
 
index b0fa296740d1897ce6770f5b136914da1142d501..f836198b705c231ef9d7eda88b92079365c9bdc8 100644 (file)
@@ -267,7 +267,7 @@ DIV_TO_REG(long val)
 
 struct w83792d_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        enum chips type;
 
        struct mutex update_lock;
@@ -540,6 +540,15 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
        return sprintf(buf, "%d\n", data->alarms);
 }
 
+static ssize_t show_alarm(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       struct w83792d_data *data = w83792d_update_device(dev);
+       return sprintf(buf, "%d\n", (data->alarms >> nr) & 1);
+}
+
 static ssize_t
 show_pwm(struct device *dev, struct device_attribute *attr,
                char *buf)
@@ -1015,6 +1024,25 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
 static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
                        show_temp23, store_temp23, 1, 4);
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23);
 static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
 static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
                        show_chassis_clear, store_chassis_clear);
@@ -1123,26 +1151,30 @@ static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
 static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
                        show_fan_div, store_fan_div, 7);
 
-static struct attribute *w83792d_attributes_fan[4][4] = {
+static struct attribute *w83792d_attributes_fan[4][5] = {
        {
                &sensor_dev_attr_fan4_input.dev_attr.attr,
                &sensor_dev_attr_fan4_min.dev_attr.attr,
                &sensor_dev_attr_fan4_div.dev_attr.attr,
+               &sensor_dev_attr_fan4_alarm.dev_attr.attr,
                NULL
        }, {
                &sensor_dev_attr_fan5_input.dev_attr.attr,
                &sensor_dev_attr_fan5_min.dev_attr.attr,
                &sensor_dev_attr_fan5_div.dev_attr.attr,
+               &sensor_dev_attr_fan5_alarm.dev_attr.attr,
                NULL
        }, {
                &sensor_dev_attr_fan6_input.dev_attr.attr,
                &sensor_dev_attr_fan6_min.dev_attr.attr,
                &sensor_dev_attr_fan6_div.dev_attr.attr,
+               &sensor_dev_attr_fan6_alarm.dev_attr.attr,
                NULL
        }, {
                &sensor_dev_attr_fan7_input.dev_attr.attr,
                &sensor_dev_attr_fan7_min.dev_attr.attr,
                &sensor_dev_attr_fan7_div.dev_attr.attr,
+               &sensor_dev_attr_fan7_alarm.dev_attr.attr,
                NULL
        }
 };
@@ -1182,6 +1214,15 @@ static struct attribute *w83792d_attributes[] = {
        &sensor_dev_attr_in8_input.dev_attr.attr,
        &sensor_dev_attr_in8_max.dev_attr.attr,
        &sensor_dev_attr_in8_min.dev_attr.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
+       &sensor_dev_attr_in7_alarm.dev_attr.attr,
+       &sensor_dev_attr_in8_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
@@ -1191,6 +1232,9 @@ static struct attribute *w83792d_attributes[] = {
        &sensor_dev_attr_temp3_input.dev_attr.attr,
        &sensor_dev_attr_temp3_max.dev_attr.attr,
        &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_alarm.dev_attr.attr,
        &sensor_dev_attr_pwm1.dev_attr.attr,
        &sensor_dev_attr_pwm1_mode.dev_attr.attr,
        &sensor_dev_attr_pwm1_enable.dev_attr.attr,
@@ -1233,12 +1277,15 @@ static struct attribute *w83792d_attributes[] = {
        &sensor_dev_attr_fan1_input.dev_attr.attr,
        &sensor_dev_attr_fan1_min.dev_attr.attr,
        &sensor_dev_attr_fan1_div.dev_attr.attr,
+       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
        &sensor_dev_attr_fan2_input.dev_attr.attr,
        &sensor_dev_attr_fan2_min.dev_attr.attr,
        &sensor_dev_attr_fan2_div.dev_attr.attr,
+       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
        &sensor_dev_attr_fan3_input.dev_attr.attr,
        &sensor_dev_attr_fan3_min.dev_attr.attr,
        &sensor_dev_attr_fan3_div.dev_attr.attr,
+       &sensor_dev_attr_fan3_alarm.dev_attr.attr,
        NULL
 };
 
@@ -1396,9 +1443,9 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
                                              &w83792d_group_fan[3])))
                        goto exit_remove_files;
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove_files;
        }
 
@@ -1433,7 +1480,7 @@ w83792d_detach_client(struct i2c_client *client)
 
        /* main client */
        if (data) {
-               hwmon_device_unregister(data->class_dev);
+               hwmon_device_unregister(data->hwmon_dev);
                sysfs_remove_group(&client->dev.kobj, &w83792d_group);
                for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
                        sysfs_remove_group(&client->dev.kobj,
index 253ffaf1568a7baefdeb86468b3467ae23d5466c..48599e1cc554a829826939cc0285bbe58d1a751a 100644 (file)
@@ -179,7 +179,7 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
 struct w83793_data {
        struct i2c_client client;
        struct i2c_client *lm75[2];
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -1075,7 +1075,7 @@ static int w83793_detach_client(struct i2c_client *client)
 
        /* main client */
        if (data) {
-               hwmon_device_unregister(data->class_dev);
+               hwmon_device_unregister(data->hwmon_dev);
 
                for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
                        device_remove_file(dev,
@@ -1434,9 +1434,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
                }
        }
 
-       data->class_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
index a3fcace412f0c41099f243e7349b07932515d84d..b5db354e2f198952a095d4ccf8e7632f9d591dc6 100644 (file)
@@ -107,7 +107,7 @@ static struct i2c_driver w83l785ts_driver = {
 
 struct w83l785ts_data {
        struct i2c_client client;
-       struct class_device *class_dev;
+       struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
@@ -247,9 +247,9 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
                goto exit_remove;
 
        /* Register sysfs hooks */
-       data->class_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->class_dev)) {
-               err = PTR_ERR(data->class_dev);
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
                goto exit_remove;
        }
 
@@ -272,7 +272,7 @@ static int w83l785ts_detach_client(struct i2c_client *client)
        struct w83l785ts_data *data = i2c_get_clientdata(client);
        int err;
 
-       hwmon_device_unregister(data->class_dev);
+       hwmon_device_unregister(data->hwmon_dev);
        device_remove_file(&client->dev,
                           &sensor_dev_attr_temp1_input.dev_attr);
        device_remove_file(&client->dev,
index 9f3a4cd0b07f7468db3f086022e108bd86516805..de95c75efb41e71d2796107331913adb0f0a0d61 100644 (file)
@@ -75,11 +75,19 @@ config I2C_AMD8111
 
 config I2C_AT91
        tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
-       depends on ARCH_AT91 && EXPERIMENTAL
+       depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
        help
          This supports the use of the I2C interface on Atmel AT91
          processors.
 
+         This driver is BROKEN because the controller which it uses
+         will easily trigger RX overrun and TX underrun errors.  Using
+         low I2C clock rates may partially work around those issues
+         on some systems.  Another serious problem is that there is no
+         documented way to issue repeated START conditions, as needed
+         to support combined I2C messages.  Use the i2c-gpio driver
+         unless your system can cope with those limitations.
+
 config I2C_AU1550
        tristate "Au1550/Au1200 SMBus interface"
        depends on SOC_AU1550 || SOC_AU1200
@@ -106,6 +114,19 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
        help
          The unit of the TWI clock is kHz.
 
+config I2C_DAVINCI
+       tristate "DaVinci I2C driver"
+       depends on ARCH_DAVINCI
+       help
+         Support for TI DaVinci I2C controller driver.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-davinci.
+
+         Please note that this driver might be needed to bring up other
+         devices such as DaVinci NIC.
+         For details please see http://www.ti.com/davinci
+
 config I2C_ELEKTOR
        tristate "Elektor ISA card"
        depends on ISA && BROKEN_ON_SMP
index 5b752e4e19184b3306edee362873b2bebb4b29f6..81d43c27cf935bdd6f7e1c06a7fe59725509bd90 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD8111)     += i2c-amd8111.o
 obj-$(CONFIG_I2C_AT91)         += i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)       += i2c-au1550.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_DAVINCI)      += i2c-davinci.o
 obj-$(CONFIG_I2C_ELEKTOR)      += i2c-elektor.o
 obj-$(CONFIG_I2C_GPIO)         += i2c-gpio.o
 obj-$(CONFIG_I2C_HYDRA)                += i2c-hydra.o
index c9fca7b492675a7c765635761602562eca7b024a..5d1a27ef250450bc76457c8f34b48484beba5e54 100644 (file)
@@ -326,7 +326,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
                I2C_FUNC_SMBUS_BYTE_DATA |
                I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
                I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
-               I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
+               I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC;
 }
 
 static const struct i2c_algorithm smbus_algorithm = {
index d7e7c359fc364831a9ad1a0bed6001f2e88d9b41..2f684166c43de49b19a9369651a63f36b901c005 100644 (file)
@@ -48,17 +48,14 @@ wait_xfer_done(struct i2c_au1550_data *adap)
 
        sp = (volatile psc_smb_t *)(adap->psc_base);
 
-       /* Wait for Tx FIFO Underflow.
+       /* Wait for Tx Buffer Empty
        */
        for (i = 0; i < adap->xfer_timeout; i++) {
-               stat = sp->psc_smbevnt;
+               stat = sp->psc_smbstat;
                au_sync();
-               if ((stat & PSC_SMBEVNT_TU) != 0) {
-                       /* Clear it.  */
-                       sp->psc_smbevnt = PSC_SMBEVNT_TU;
-                       au_sync();
+               if ((stat & PSC_SMBSTAT_TE) != 0)
                        return 0;
-               }
+
                udelay(1);
        }
 
index 6311039dfe601ff0bd4b0b280acb6a3cef76c7e9..67224a424aba4cbf659cb969b57d9fb24c1e1d81 100644 (file)
@@ -44,7 +44,6 @@
 #define TWI_I2C_MODE_COMBINED          0x04
 
 struct bfin_twi_iface {
-       struct mutex            twi_lock;
        int                     irq;
        spinlock_t              lock;
        char                    read_write;
@@ -228,12 +227,8 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
        if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
                return -ENXIO;
 
-       mutex_lock(&iface->twi_lock);
-
        while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
-               mutex_unlock(&iface->twi_lock);
                yield();
-               mutex_lock(&iface->twi_lock);
        }
 
        ret = 0;
@@ -310,9 +305,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
                        break;
        }
 
-       /* Release mutex */
-       mutex_unlock(&iface->twi_lock);
-
        return ret;
 }
 
@@ -330,12 +322,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
                return -ENXIO;
 
-       mutex_lock(&iface->twi_lock);
-
        while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
-               mutex_unlock(&iface->twi_lock);
                yield();
-               mutex_lock(&iface->twi_lock);
        }
 
        iface->writeNum = 0;
@@ -502,9 +490,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 
        rc = (iface->result >= 0) ? 0 : -1;
 
-       /* Release mutex */
-       mutex_unlock(&iface->twi_lock);
-
        return rc;
 }
 
@@ -555,7 +540,6 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
        struct i2c_adapter *p_adap;
        int rc;
 
-       mutex_init(&(iface->twi_lock));
        spin_lock_init(&(iface->lock));
        init_completion(&(iface->complete));
        iface->irq = IRQ_TWI;
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
new file mode 100644 (file)
index 0000000..bd7aaff
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ *
+ * Updated by Vinod & Sudhakar Feb 2005
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/i2c.h>
+
+/* ----- global defines ----------------------------------------------- */
+
+#define DAVINCI_I2C_TIMEOUT    (1*HZ)
+#define I2C_DAVINCI_INTR_ALL    (DAVINCI_I2C_IMR_AAS | \
+                                DAVINCI_I2C_IMR_SCD | \
+                                DAVINCI_I2C_IMR_ARDY | \
+                                DAVINCI_I2C_IMR_NACK | \
+                                DAVINCI_I2C_IMR_AL)
+
+#define DAVINCI_I2C_OAR_REG    0x00
+#define DAVINCI_I2C_IMR_REG    0x04
+#define DAVINCI_I2C_STR_REG    0x08
+#define DAVINCI_I2C_CLKL_REG   0x0c
+#define DAVINCI_I2C_CLKH_REG   0x10
+#define DAVINCI_I2C_CNT_REG    0x14
+#define DAVINCI_I2C_DRR_REG    0x18
+#define DAVINCI_I2C_SAR_REG    0x1c
+#define DAVINCI_I2C_DXR_REG    0x20
+#define DAVINCI_I2C_MDR_REG    0x24
+#define DAVINCI_I2C_IVR_REG    0x28
+#define DAVINCI_I2C_EMDR_REG   0x2c
+#define DAVINCI_I2C_PSC_REG    0x30
+
+#define DAVINCI_I2C_IVR_AAS    0x07
+#define DAVINCI_I2C_IVR_SCD    0x06
+#define DAVINCI_I2C_IVR_XRDY   0x05
+#define DAVINCI_I2C_IVR_RDR    0x04
+#define DAVINCI_I2C_IVR_ARDY   0x03
+#define DAVINCI_I2C_IVR_NACK   0x02
+#define DAVINCI_I2C_IVR_AL     0x01
+
+#define DAVINCI_I2C_STR_BB     (1 << 12)
+#define DAVINCI_I2C_STR_RSFULL (1 << 11)
+#define DAVINCI_I2C_STR_SCD    (1 << 5)
+#define DAVINCI_I2C_STR_ARDY   (1 << 2)
+#define DAVINCI_I2C_STR_NACK   (1 << 1)
+#define DAVINCI_I2C_STR_AL     (1 << 0)
+
+#define DAVINCI_I2C_MDR_NACK   (1 << 15)
+#define DAVINCI_I2C_MDR_STT    (1 << 13)
+#define DAVINCI_I2C_MDR_STP    (1 << 11)
+#define DAVINCI_I2C_MDR_MST    (1 << 10)
+#define DAVINCI_I2C_MDR_TRX    (1 << 9)
+#define DAVINCI_I2C_MDR_XA     (1 << 8)
+#define DAVINCI_I2C_MDR_IRS    (1 << 5)
+
+#define DAVINCI_I2C_IMR_AAS    (1 << 6)
+#define DAVINCI_I2C_IMR_SCD    (1 << 5)
+#define DAVINCI_I2C_IMR_XRDY   (1 << 4)
+#define DAVINCI_I2C_IMR_RRDY   (1 << 3)
+#define DAVINCI_I2C_IMR_ARDY   (1 << 2)
+#define DAVINCI_I2C_IMR_NACK   (1 << 1)
+#define DAVINCI_I2C_IMR_AL     (1 << 0)
+
+#define MOD_REG_BIT(val, mask, set) do { \
+       if (set) { \
+               val |= mask; \
+       } else { \
+               val &= ~mask; \
+       } \
+} while (0)
+
+struct davinci_i2c_dev {
+       struct device           *dev;
+       void __iomem            *base;
+       struct completion       cmd_complete;
+       struct clk              *clk;
+       int                     cmd_err;
+       u8                      *buf;
+       size_t                  buf_len;
+       int                     irq;
+       struct i2c_adapter      adapter;
+};
+
+/* default platform data to use if not supplied in the platform_device */
+static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = {
+       .bus_freq       = 100,
+       .bus_delay      = 0,
+};
+
+static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev,
+                                        int reg, u16 val)
+{
+       __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
+{
+       return __raw_readw(i2c_dev->base + reg);
+}
+
+/*
+ * This functions configures I2C and brings I2C out of reset.
+ * This function is called during I2C init function. This function
+ * also gets called if I2C encounters any errors.
+ */
+static int i2c_davinci_init(struct davinci_i2c_dev *dev)
+{
+       struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+       u16 psc;
+       u32 clk;
+       u32 clkh;
+       u32 clkl;
+       u32 input_clock = clk_get_rate(dev->clk);
+       u16 w;
+
+       if (!pdata)
+               pdata = &davinci_i2c_platform_data_default;
+
+       /* put I2C into reset */
+       w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+       MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0);
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+       /* NOTE: I2C Clock divider programming info
+        * As per I2C specs the following formulas provide prescaler
+        * and low/high divider values
+        * input clk --> PSC Div -----------> ICCL/H Div --> output clock
+        *                       module clk
+        *
+        * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ]
+        *
+        * Thus,
+        * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d;
+        *
+        * where if PSC == 0, d = 7,
+        *       if PSC == 1, d = 6
+        *       if PSC > 1 , d = 5
+        */
+
+       psc = 26; /* To get 1MHz clock */
+
+       clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - 10;
+       clkh = (50 * clk) / 100;
+       clkl = clk - clkh;
+
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
+
+       dev_dbg(dev->dev, "CLK  = %d\n", clk);
+       dev_dbg(dev->dev, "PSC  = %d\n",
+               davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
+       dev_dbg(dev->dev, "CLKL = %d\n",
+               davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
+       dev_dbg(dev->dev, "CLKH = %d\n",
+               davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
+
+       /* Take the I2C module out of reset: */
+       w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+       MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1);
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+       /* Enable interrupts */
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
+
+       return 0;
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
+                                        char allow_sleep)
+{
+       unsigned long timeout;
+
+       timeout = jiffies + DAVINCI_I2C_TIMEOUT;
+       while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
+              & DAVINCI_I2C_STR_BB) {
+               if (time_after(jiffies, timeout)) {
+                       dev_warn(dev->dev,
+                                "timeout waiting for bus ready\n");
+                       return -ETIMEDOUT;
+               }
+               if (allow_sleep)
+                       schedule_timeout(1);
+       }
+
+       return 0;
+}
+
+/*
+ * Low level master read/write transaction. This function is called
+ * from i2c_davinci_xfer.
+ */
+static int
+i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
+{
+       struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+       struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+       u32 flag;
+       u32 stat;
+       u16 w;
+       int r;
+
+       if (msg->len == 0)
+               return -EINVAL;
+
+       if (!pdata)
+               pdata = &davinci_i2c_platform_data_default;
+       /* Introduce a delay, required for some boards (e.g Davinci EVM) */
+       if (pdata->bus_delay)
+               udelay(pdata->bus_delay);
+
+       /* set the slave address */
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr);
+
+       dev->buf = msg->buf;
+       dev->buf_len = msg->len;
+
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
+
+       init_completion(&dev->cmd_complete);
+       dev->cmd_err = 0;
+
+       /* Clear any pending interrupts by reading the IVR */
+       stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG);
+
+       /* Take I2C out of reset, configure it as master and set the
+        * start bit */
+       flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST | DAVINCI_I2C_MDR_STT;
+
+       /* if the slave address is ten bit address, enable XA bit */
+       if (msg->flags & I2C_M_TEN)
+               flag |= DAVINCI_I2C_MDR_XA;
+       if (!(msg->flags & I2C_M_RD))
+               flag |= DAVINCI_I2C_MDR_TRX;
+       if (stop)
+               flag |= DAVINCI_I2C_MDR_STP;
+
+       /* Enable receive or transmit interrupts */
+       w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
+       if (msg->flags & I2C_M_RD)
+               MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 1);
+       else
+               MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1);
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
+
+       /* write the data into mode register */
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+       r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+                                                     DAVINCI_I2C_TIMEOUT);
+       dev->buf_len = 0;
+       if (r < 0)
+               return r;
+
+       if (r == 0) {
+               dev_err(dev->dev, "controller timed out\n");
+               i2c_davinci_init(dev);
+               return -ETIMEDOUT;
+       }
+
+       /* no error */
+       if (likely(!dev->cmd_err))
+               return msg->len;
+
+       /* We have an error */
+       if (dev->cmd_err & DAVINCI_I2C_STR_AL) {
+               i2c_davinci_init(dev);
+               return -EIO;
+       }
+
+       if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
+               if (msg->flags & I2C_M_IGNORE_NAK)
+                       return msg->len;
+               if (stop) {
+                       w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+                       MOD_REG_BIT(w, DAVINCI_I2C_MDR_STP, 1);
+                       davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+               }
+               return -EREMOTEIO;
+       }
+       return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_davinci_xfer_msg
+ */
+static int
+i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+       struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+       int i;
+       int ret;
+
+       dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num);
+
+       ret = i2c_davinci_wait_bus_not_busy(dev, 1);
+       if (ret < 0) {
+               dev_warn(dev->dev, "timeout waiting for bus ready\n");
+               return ret;
+       }
+
+       for (i = 0; i < num; i++) {
+               ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+               if (ret < 0)
+                       return ret;
+       }
+
+       dev_dbg(dev->dev, "%s:%d ret: %d\n", __FUNCTION__, __LINE__, ret);
+
+       return num;
+}
+
+static u32 i2c_davinci_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
+{
+       struct davinci_i2c_dev *dev = dev_id;
+       u32 stat;
+       int count = 0;
+       u16 w;
+
+       while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
+               dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat);
+               if (count++ == 100) {
+                       dev_warn(dev->dev, "Too much work in one IRQ\n");
+                       break;
+               }
+
+               switch (stat) {
+               case DAVINCI_I2C_IVR_AL:
+                       dev->cmd_err |= DAVINCI_I2C_STR_AL;
+                       complete(&dev->cmd_complete);
+                       break;
+
+               case DAVINCI_I2C_IVR_NACK:
+                       dev->cmd_err |= DAVINCI_I2C_STR_NACK;
+                       complete(&dev->cmd_complete);
+                       break;
+
+               case DAVINCI_I2C_IVR_ARDY:
+                       w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG);
+                       MOD_REG_BIT(w, DAVINCI_I2C_STR_ARDY, 1);
+                       davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w);
+                       complete(&dev->cmd_complete);
+                       break;
+
+               case DAVINCI_I2C_IVR_RDR:
+                       if (dev->buf_len) {
+                               *dev->buf++ =
+                                   davinci_i2c_read_reg(dev,
+                                                        DAVINCI_I2C_DRR_REG);
+                               dev->buf_len--;
+                               if (dev->buf_len)
+                                       continue;
+
+                               w = davinci_i2c_read_reg(dev,
+                                                        DAVINCI_I2C_STR_REG);
+                               MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 0);
+                               davinci_i2c_write_reg(dev,
+                                                     DAVINCI_I2C_STR_REG,
+                                                     w);
+                       } else
+                               dev_err(dev->dev, "RDR IRQ while no"
+                                       "data requested\n");
+                       break;
+
+               case DAVINCI_I2C_IVR_XRDY:
+                       if (dev->buf_len) {
+                               davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,
+                                                     *dev->buf++);
+                               dev->buf_len--;
+                               if (dev->buf_len)
+                                       continue;
+
+                               w = davinci_i2c_read_reg(dev,
+                                                        DAVINCI_I2C_IMR_REG);
+                               MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 0);
+                               davinci_i2c_write_reg(dev,
+                                                     DAVINCI_I2C_IMR_REG,
+                                                     w);
+                       } else
+                               dev_err(dev->dev, "TDR IRQ while no data to"
+                                       "send\n");
+                       break;
+
+               case DAVINCI_I2C_IVR_SCD:
+                       w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG);
+                       MOD_REG_BIT(w, DAVINCI_I2C_STR_SCD, 1);
+                       davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w);
+                       complete(&dev->cmd_complete);
+                       break;
+
+               case DAVINCI_I2C_IVR_AAS:
+                       dev_warn(dev->dev, "Address as slave interrupt\n");
+               }/* switch */
+       }/* while */
+
+       return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static struct i2c_algorithm i2c_davinci_algo = {
+       .master_xfer    = i2c_davinci_xfer,
+       .functionality  = i2c_davinci_func,
+};
+
+static int davinci_i2c_probe(struct platform_device *pdev)
+{
+       struct davinci_i2c_dev *dev;
+       struct i2c_adapter *adap;
+       struct resource *mem, *irq, *ioarea;
+       int r;
+
+       /* NOTE: driver uses the static register mapping */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               return -ENODEV;
+       }
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               return -ENODEV;
+       }
+
+       ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+                                   pdev->name);
+       if (!ioarea) {
+               dev_err(&pdev->dev, "I2C region already claimed\n");
+               return -EBUSY;
+       }
+
+       dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);
+       if (!dev) {
+               r = -ENOMEM;
+               goto err_release_region;
+       }
+
+       dev->dev = get_device(&pdev->dev);
+       dev->irq = irq->start;
+       platform_set_drvdata(pdev, dev);
+
+       dev->clk = clk_get(&pdev->dev, "I2CCLK");
+       if (IS_ERR(dev->clk)) {
+               r = -ENODEV;
+               goto err_free_mem;
+       }
+       clk_enable(dev->clk);
+
+       dev->base = (void __iomem *)IO_ADDRESS(mem->start);
+       i2c_davinci_init(dev);
+
+       r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
+       if (r) {
+               dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+               goto err_unuse_clocks;
+       }
+
+       adap = &dev->adapter;
+       i2c_set_adapdata(adap, dev);
+       adap->owner = THIS_MODULE;
+       adap->class = I2C_CLASS_HWMON;
+       strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
+       adap->algo = &i2c_davinci_algo;
+       adap->dev.parent = &pdev->dev;
+
+       /* FIXME */
+       adap->timeout = 1;
+       adap->retries = 1;
+
+       adap->nr = pdev->id;
+       r = i2c_add_numbered_adapter(adap);
+       if (r) {
+               dev_err(&pdev->dev, "failure adding adapter\n");
+               goto err_free_irq;
+       }
+
+       return 0;
+
+err_free_irq:
+       free_irq(dev->irq, dev);
+err_unuse_clocks:
+       clk_disable(dev->clk);
+       clk_put(dev->clk);
+       dev->clk = NULL;
+err_free_mem:
+       platform_set_drvdata(pdev, NULL);
+       put_device(&pdev->dev);
+       kfree(dev);
+err_release_region:
+       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+       return r;
+}
+
+static int davinci_i2c_remove(struct platform_device *pdev)
+{
+       struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+       struct resource *mem;
+
+       platform_set_drvdata(pdev, NULL);
+       i2c_del_adapter(&dev->adapter);
+       put_device(&pdev->dev);
+
+       clk_disable(dev->clk);
+       clk_put(dev->clk);
+       dev->clk = NULL;
+
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+       free_irq(IRQ_I2C, dev);
+       kfree(dev);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       return 0;
+}
+
+static struct platform_driver davinci_i2c_driver = {
+       .probe          = davinci_i2c_probe,
+       .remove         = davinci_i2c_remove,
+       .driver         = {
+               .name   = "i2c_davinci",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init davinci_i2c_init_driver(void)
+{
+       return platform_driver_register(&davinci_i2c_driver);
+}
+subsys_initcall(davinci_i2c_init_driver);
+
+static void __exit davinci_i2c_exit_driver(void)
+{
+       platform_driver_unregister(&davinci_i2c_driver);
+}
+module_exit(davinci_i2c_exit_driver);
+
+MODULE_AUTHOR("Texas Instruments India");
+MODULE_DESCRIPTION("TI DaVinci I2C bus adapter");
+MODULE_LICENSE("GPL");
index 289816db52aed4b956dd515238f65a8fda481597..ac27e5f84ebe2ef60aef3fb40427ec7232ef744a 100644 (file)
@@ -34,6 +34,7 @@
     ESB2               269B
     ICH8               283E
     ICH9               2930
+    Tolapai            5032
     This driver supports several versions of Intel's I/O Controller Hubs (ICH).
     For SMBus support, they are similar to the PIIX4 and are part
     of Intel's '810' and other chipsets.
@@ -515,7 +516,7 @@ static u32 i801_func(struct i2c_adapter *adapter)
        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
            I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
-            | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
+            | (isich4 ? I2C_FUNC_SMBUS_PEC : 0);
 }
 
 static const struct i2c_algorithm smbus_algorithm = {
@@ -543,6 +544,7 @@ static struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
        { 0, }
 };
 
@@ -563,6 +565,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
        case PCI_DEVICE_ID_INTEL_ESB2_17:
        case PCI_DEVICE_ID_INTEL_ICH8_5:
        case PCI_DEVICE_ID_INTEL_ICH9_6:
+       case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
                isich4 = 1;
                break;
        default:
index 8b14d14e60cad3e3cd1099df6d221dc6ab1b475e..e08bacadd6bc2ae7adc0445341d8996eff6ddee5 100644 (file)
@@ -738,7 +738,14 @@ static int __devinit iic_probe(struct ocp_device *ocp){
        adap->timeout = 1;
        adap->retries = 1;
 
-       if ((ret = i2c_add_adapter(adap)) != 0){
+       /*
+        * If "dev->idx" is negative we consider it as zero.
+        * The reason to do so is to avoid sysfs names that only make
+        * sense when there are multiple adapters.
+        */
+       adap->nr = dev->idx >= 0 ? dev->idx : 0;
+
+       if ((ret = i2c_add_numbered_adapter(adap)) < 0) {
                printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
                        dev->idx);
                goto fail;
index ace644e21b14380585f05103028a133b02a904af..c70146e4c2c026726b5cdb1c64f9785c4e8a9d91 100644 (file)
@@ -389,13 +389,6 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
        return im;   
 }
 
-static int 
-iop3xx_i2c_algo_control(struct i2c_adapter *adapter, unsigned int cmd,
-                       unsigned long arg)
-{
-       return 0;
-}
-
 static u32 
 iop3xx_i2c_func(struct i2c_adapter *adap)
 {
@@ -404,7 +397,6 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
 
 static const struct i2c_algorithm iop3xx_i2c_algo = {
        .master_xfer    = iop3xx_i2c_master_xfer,
-       .algo_control   = iop3xx_i2c_algo_control,
        .functionality  = iop3xx_i2c_func,
 };
 
index c48140f782d09c276dcb4c6b31d5201dd213b6dd..1bf590c741660a752d6f69e5592a20b5c94eadf9 100644 (file)
@@ -62,6 +62,7 @@ struct nforce2_smbus {
        int base;
        int size;
        int blockops;
+       int can_abort;
 };
 
 
@@ -83,7 +84,14 @@ struct nforce2_smbus {
 #define NVIDIA_SMB_DATA                (smbus->base + 0x04)    /* 32 data registers */
 #define NVIDIA_SMB_BCNT                (smbus->base + 0x24)    /* number of data
                                                           bytes */
-
+#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c)    /* register used to
+                                                          check the status of
+                                                          the abort command */
+#define NVIDIA_SMB_CTRL                (smbus->base + 0x3e)    /* control register */
+
+#define NVIDIA_SMB_STATUS_ABRT_STS     0x01            /* Bit to notify that
+                                                          abort succeeded */
+#define NVIDIA_SMB_CTRL_ABORT  0x20
 #define NVIDIA_SMB_STS_DONE    0x80
 #define NVIDIA_SMB_STS_ALRM    0x40
 #define NVIDIA_SMB_STS_RES     0x20
@@ -98,15 +106,61 @@ struct nforce2_smbus {
 #define NVIDIA_SMB_PRTCL_BLOCK_DATA            0x0a
 #define NVIDIA_SMB_PRTCL_PEC                   0x80
 
+/* Misc definitions */
+#define MAX_TIMEOUT    100
+
 static struct pci_driver nforce2_driver;
 
+static void nforce2_abort(struct i2c_adapter *adap)
+{
+       struct nforce2_smbus *smbus = adap->algo_data;
+       int timeout = 0;
+       unsigned char temp;
+
+       dev_dbg(&adap->dev, "Aborting current transaction\n");
+
+       outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
+       do {
+               msleep(1);
+               temp = inb_p(NVIDIA_SMB_STATUS_ABRT);
+       } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
+                       (timeout++ < MAX_TIMEOUT));
+       if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
+               dev_err(&adap->dev, "Can't reset the smbus\n");
+       outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
+}
+
+static int nforce2_check_status(struct i2c_adapter *adap)
+{
+       struct nforce2_smbus *smbus = adap->algo_data;
+       int timeout = 0;
+       unsigned char temp;
+
+       do {
+               msleep(1);
+               temp = inb_p(NVIDIA_SMB_STS);
+       } while ((!temp) && (timeout++ < MAX_TIMEOUT));
+
+       if (timeout >= MAX_TIMEOUT) {
+               dev_dbg(&adap->dev, "SMBus Timeout!\n");
+               if (smbus->can_abort)
+                       nforce2_abort(adap);
+               return -1;
+       }
+       if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+               dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
+               return -1;
+       }
+       return 0;
+}
+
 /* Return -1 on error */
 static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
                unsigned short flags, char read_write,
                u8 command, int size, union i2c_smbus_data * data)
 {
        struct nforce2_smbus *smbus = adap->algo_data;
-       unsigned char protocol, pec, temp;
+       unsigned char protocol, pec;
        u8 len;
        int i;
 
@@ -170,21 +224,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
        outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
        outb_p(protocol, NVIDIA_SMB_PRTCL);
 
-       temp = inb_p(NVIDIA_SMB_STS);
-
-       if (~temp & NVIDIA_SMB_STS_DONE) {
-               udelay(500);
-               temp = inb_p(NVIDIA_SMB_STS);
-       }
-       if (~temp & NVIDIA_SMB_STS_DONE) {
-               msleep(10);
-               temp = inb_p(NVIDIA_SMB_STS);
-       }
-
-       if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
-               dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp);
+       if (nforce2_check_status(adap))
                return -1;
-       }
 
        if (read_write == I2C_SMBUS_WRITE)
                return 0;
@@ -202,7 +243,12 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
 
                case I2C_SMBUS_BLOCK_DATA:
                        len = inb_p(NVIDIA_SMB_BCNT);
-                       len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+                       if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+                               dev_err(&adap->dev, "Transaction failed "
+                                       "(received block size: 0x%02x)\n",
+                                       len);
+                               return -1;
+                       }
                        for (i = 0; i < len; i++)
                                data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
                        data->block[0] = len;
@@ -218,6 +264,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
        /* other functionality might be possible, but is not tested */
        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+              I2C_FUNC_SMBUS_PEC |
               (((struct nforce2_smbus*)adapter->algo_data)->blockops ?
                I2C_FUNC_SMBUS_BLOCK_DATA : 0);
 }
@@ -308,6 +355,8 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
        case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
                smbuses[0].blockops = 1;
                smbuses[1].blockops = 1;
+               smbuses[0].can_abort = 1;
+               smbuses[1].can_abort = 1;
        }
 
        /* SMBus adapter 1 */
index a54adc50d162a5a580ae60a709b87bb802280c75..84df29da1ddc1c2f79d3dec90984ee343696f387 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 
-static unsigned short chip_addr;
-module_param(chip_addr, ushort, S_IRUGO);
-MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
+#define MAX_CHIPS 10
 
-static u8  stub_pointer;
-static u8  stub_bytes[256];
-static u16 stub_words[256];
+static unsigned short chip_addr[MAX_CHIPS];
+module_param_array(chip_addr, ushort, NULL, S_IRUGO);
+MODULE_PARM_DESC(chip_addr,
+                "Chip addresses (up to 10, between 0x03 and 0x77)\n");
+
+struct stub_chip {
+       u8 pointer;
+       u8 bytes[256];
+       u16 words[256];
+};
+
+static struct stub_chip *stub_chips;
 
 /* Return -1 on error. */
 static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
        char read_write, u8 command, int size, union i2c_smbus_data * data)
 {
        s32 ret;
-
-       if (addr != chip_addr)
+       int i;
+       struct stub_chip *chip = NULL;
+
+       /* Search for the right chip */
+       for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+               if (addr == chip_addr[i]) {
+                       chip = stub_chips + i;
+                       break;
+               }
+       }
+       if (!chip)
                return -ENODEV;
 
        switch (size) {
@@ -53,12 +70,12 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
 
        case I2C_SMBUS_BYTE:
                if (read_write == I2C_SMBUS_WRITE) {
-                       stub_pointer = command;
+                       chip->pointer = command;
                        dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
                                        "wrote 0x%02x.\n",
                                        addr, command);
                } else {
-                       data->byte = stub_bytes[stub_pointer++];
+                       data->byte = chip->bytes[chip->pointer++];
                        dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
                                        "read  0x%02x.\n",
                                        addr, data->byte);
@@ -69,29 +86,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
 
        case I2C_SMBUS_BYTE_DATA:
                if (read_write == I2C_SMBUS_WRITE) {
-                       stub_bytes[command] = data->byte;
+                       chip->bytes[command] = data->byte;
                        dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
                                        "wrote 0x%02x at 0x%02x.\n",
                                        addr, data->byte, command);
                } else {
-                       data->byte = stub_bytes[command];
+                       data->byte = chip->bytes[command];
                        dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
                                        "read  0x%02x at 0x%02x.\n",
                                        addr, data->byte, command);
                }
-               stub_pointer = command + 1;
+               chip->pointer = command + 1;
 
                ret = 0;
                break;
 
        case I2C_SMBUS_WORD_DATA:
                if (read_write == I2C_SMBUS_WRITE) {
-                       stub_words[command] = data->word;
+                       chip->words[command] = data->word;
                        dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
                                        "wrote 0x%04x at 0x%02x.\n",
                                        addr, data->word, command);
                } else {
-                       data->word = stub_words[command];
+                       data->word = chip->words[command];
                        dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
                                        "read  0x%04x at 0x%02x.\n",
                                        addr, data->word, command);
@@ -129,23 +146,41 @@ static struct i2c_adapter stub_adapter = {
 
 static int __init i2c_stub_init(void)
 {
-       if (!chip_addr) {
+       int i, ret;
+
+       if (!chip_addr[0]) {
                printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
                return -ENODEV;
        }
-       if (chip_addr < 0x03 || chip_addr > 0x77) {
-               printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
-                      chip_addr);
-               return -EINVAL;
+
+       for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+               if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
+                       printk(KERN_ERR "i2c-stub: Invalid chip address "
+                              "0x%02x\n", chip_addr[i]);
+                       return -EINVAL;
+               }
+
+               printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
+                      chip_addr[i]);
        }
 
-       printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
-       return i2c_add_adapter(&stub_adapter);
+       /* Allocate memory for all chips at once */
+       stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
+       if (!stub_chips) {
+               printk(KERN_ERR "i2c-stub: Out of memory\n");
+               return -ENOMEM;
+       }
+
+       ret = i2c_add_adapter(&stub_adapter);
+       if (ret)
+               kfree(stub_chips);
+       return ret;
 }
 
 static void __exit i2c_stub_exit(void)
 {
        i2c_del_adapter(&stub_adapter);
+       kfree(stub_chips);
 }
 
 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
index 32b25427eaba6e54ecc0a6674ab60a0a18f2c297..21c6dd69193c21804ab55ced727ff412df9f48ce 100644 (file)
@@ -48,14 +48,11 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
 
-/* Initial values */
-#define PCF8574_INIT 255       /* All outputs on (input mode) */
-
 /* Each client has this additional data */
 struct pcf8574_data {
        struct i2c_client client;
 
-       u8 write;                       /* Remember last written value */
+       int write;                      /* Remember last written value */
 };
 
 static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
@@ -85,7 +82,11 @@ static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
 static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev));
-       return sprintf(buf, "%u\n", data->write);
+
+       if (data->write < 0)
+               return data->write;
+
+       return sprintf(buf, "%d\n", data->write);
 }
 
 static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf,
@@ -206,8 +207,7 @@ static int pcf8574_detach_client(struct i2c_client *client)
 static void pcf8574_init_client(struct i2c_client *client)
 {
        struct pcf8574_data *data = i2c_get_clientdata(client);
-       data->write = PCF8574_INIT;
-       i2c_smbus_write_byte(client, data->write);
+       data->write = -EAGAIN;
 }
 
 static int __init pcf8574_init(void)
index 503ffec2ce07c4f78ad04013b36d35c88d7d68ee..e320994b981cdd1b7f08f52f79ca5208298c9e0b 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
-#include <linux/suspend.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
 
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
 #include <asm/arch/tps65010.h>
 
 /*-------------------------------------------------------------------------*/
 MODULE_DESCRIPTION("TPS6501x Power Management Driver");
 MODULE_LICENSE("GPL");
 
-static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static struct i2c_driver tps65010_driver;
 
 /*-------------------------------------------------------------------------*/
@@ -79,9 +68,8 @@ enum tps_model {
 };
 
 struct tps65010 {
-       struct i2c_client       client;
+       struct i2c_client       *client;
        struct mutex            lock;
-       int                     irq;
        struct delayed_work     work;
        struct dentry           *file;
        unsigned                charging:1;
@@ -229,22 +217,22 @@ static int dbg_show(struct seq_file *s, void *_)
        /* registers for monitoring battery charging and status; note
         * that reading chgstat and regstat may ack IRQs...
         */
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG);
        dbg_chgconf(tps->por, buf, sizeof buf, value);
        seq_printf(s, "chgconfig %s", buf);
 
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS);
        dbg_chgstat(buf, sizeof buf, value);
        seq_printf(s, "chgstat   %s", buf);
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_MASK1);
        dbg_chgstat(buf, sizeof buf, value);
        seq_printf(s, "mask1     %s", buf);
        /* ignore ackint1 */
 
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS);
        dbg_regstat(buf, sizeof buf, value);
        seq_printf(s, "regstat   %s", buf);
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_MASK2);
        dbg_regstat(buf, sizeof buf, value);
        seq_printf(s, "mask2     %s\n", buf);
        /* ignore ackint2 */
@@ -253,21 +241,21 @@ static int dbg_show(struct seq_file *s, void *_)
 
 
        /* VMAIN voltage, enable lowpower, etc */
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1);
        seq_printf(s, "vdcdc1    %02x\n", value);
 
        /* VCORE voltage, vibrator on/off */
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC2);
        seq_printf(s, "vdcdc2    %02x\n", value);
 
        /* both LD0s, and their lowpower behavior */
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_VREGS1);
        seq_printf(s, "vregs1    %02x\n\n", value);
 
 
        /* LEDs and GPIOs */
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON);
-       v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_LED1_ON);
+       v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED1_PER);
        seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n",
                (value & 0x80)
                        ? ((v2 & 0x80) ? "on" : "off")
@@ -275,8 +263,8 @@ static int dbg_show(struct seq_file *s, void *_)
                value, v2,
                (value & 0x7f) * 10, (v2 & 0x7f) * 100);
 
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON);
-       v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_LED2_ON);
+       v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED2_PER);
        seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n",
                (value & 0x80)
                        ? ((v2 & 0x80) ? "on" : "off")
@@ -284,8 +272,8 @@ static int dbg_show(struct seq_file *s, void *_)
                value, v2,
                (value & 0x7f) * 10, (v2 & 0x7f) * 100);
 
-       value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO);
-       v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3);
+       value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
+       v2 = i2c_smbus_read_byte_data(tps->client, TPS_MASK3);
        seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2);
 
        for (i = 0; i < 4; i++) {
@@ -335,7 +323,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
 
        /* regstatus irqs */
        if (tps->nmask2) {
-               tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+               tmp = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS);
                mask = tmp ^ tps->regstatus;
                tps->regstatus = tmp;
                mask &= tps->nmask2;
@@ -362,7 +350,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
 
        /* chgstatus irqs */
        if (tps->nmask1) {
-               tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+               tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS);
                mask = tmp ^ tps->chgstatus;
                tps->chgstatus = tmp;
                mask &= tps->nmask1;
@@ -426,7 +414,7 @@ static void tps65010_work(struct work_struct *work)
                int     status;
                u8      chgconfig, tmp;
 
-               chgconfig = i2c_smbus_read_byte_data(&tps->client,
+               chgconfig = i2c_smbus_read_byte_data(tps->client,
                                        TPS_CHGCONFIG);
                chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING);
                if (tps->vbus == 500)
@@ -434,17 +422,17 @@ static void tps65010_work(struct work_struct *work)
                else if (tps->vbus >= 100)
                        chgconfig |= TPS_VBUS_CHARGING;
 
-               status = i2c_smbus_write_byte_data(&tps->client,
+               status = i2c_smbus_write_byte_data(tps->client,
                                TPS_CHGCONFIG, chgconfig);
 
                /* vbus update fails unless VBUS is connected! */
-               tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+               tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG);
                tps->chgconf = tmp;
                show_chgconfig(tps->por, "update vbus", tmp);
        }
 
        if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags))
-               enable_irq(tps->irq);
+               enable_irq(tps->client->irq);
 
        mutex_unlock(&tps->lock);
 }
@@ -463,114 +451,75 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
 
 static struct tps65010 *the_tps;
 
-static int __exit tps65010_detach_client(struct i2c_client *client)
+static int __exit tps65010_remove(struct i2c_client *client)
 {
-       struct tps65010         *tps;
+       struct tps65010         *tps = i2c_get_clientdata(client);
 
-       tps = container_of(client, struct tps65010, client);
-       free_irq(tps->irq, tps);
-#ifdef CONFIG_ARM
-       if (machine_is_omap_h2())
-               omap_free_gpio(58);
-       if (machine_is_omap_osk())
-               omap_free_gpio(OMAP_MPUIO(1));
-#endif
+       if (client->irq > 0)
+               free_irq(client->irq, tps);
        cancel_delayed_work(&tps->work);
        flush_scheduled_work();
        debugfs_remove(tps->file);
-       if (i2c_detach_client(client) == 0)
-               kfree(tps);
+       kfree(tps);
        the_tps = NULL;
        return 0;
 }
 
-static int tps65010_noscan(struct i2c_adapter *bus)
-{
-       /* pure paranoia, in case someone adds another i2c bus
-        * after our init section's gone...
-        */
-       return -ENODEV;
-}
-
-/* no error returns, they'd just make bus scanning stop */
-static int __init
-tps65010_probe(struct i2c_adapter *bus, int address, int kind)
+static int tps65010_probe(struct i2c_client *client)
 {
        struct tps65010         *tps;
        int                     status;
-       unsigned long           irqflags;
 
        if (the_tps) {
-               dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME);
-               return 0;
+               dev_dbg(&client->dev, "only one tps6501x chip allowed\n");
+               return -ENODEV;
        }
 
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EINVAL;
+
        tps = kzalloc(sizeof *tps, GFP_KERNEL);
        if (!tps)
-               return 0;
+               return -ENOMEM;
 
        mutex_init(&tps->lock);
        INIT_DELAYED_WORK(&tps->work, tps65010_work);
-       tps->irq = -1;
-       tps->client.addr = address;
-       tps->client.adapter = bus;
-       tps->client.driver = &tps65010_driver;
-       strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE);
-
-       status = i2c_attach_client(&tps->client);
-       if (status < 0) {
-               dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
-                               DRIVER_NAME, address, status);
-               goto fail1;
-       }
+       tps->client = client;
 
-       /* the IRQ is active low, but many gpio lines can't support that
-        * so this driver can use falling-edge triggers instead.
-        */
-       irqflags = IRQF_SAMPLE_RANDOM;
-#ifdef CONFIG_ARM
-       if (machine_is_omap_h2()) {
-               tps->model = TPS65010;
-               omap_cfg_reg(W4_GPIO58);
-               tps->irq = OMAP_GPIO_IRQ(58);
-               omap_request_gpio(58);
-               omap_set_gpio_direction(58, 1);
-               irqflags |= IRQF_TRIGGER_FALLING;
-       }
-       if (machine_is_omap_osk()) {
+       if (strcmp(client->name, "tps65010") == 0)
                tps->model = TPS65010;
-               // omap_cfg_reg(U19_1610_MPUIO1);
-               tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
-               omap_request_gpio(OMAP_MPUIO(1));
-               omap_set_gpio_direction(OMAP_MPUIO(1), 1);
-               irqflags |= IRQF_TRIGGER_FALLING;
-       }
-       if (machine_is_omap_h3()) {
+       else if (strcmp(client->name, "tps65011") == 0)
+               tps->model = TPS65011;
+       else if (strcmp(client->name, "tps65012") == 0)
+               tps->model = TPS65012;
+       else if (strcmp(client->name, "tps65013") == 0)
                tps->model = TPS65013;
-
-               // FIXME set up this board's IRQ ...
+       else {
+               dev_warn(&client->dev, "unknown chip '%s'\n", client->name);
+               status = -ENODEV;
+               goto fail1;
        }
-#endif
 
-       if (tps->irq > 0) {
-               status = request_irq(tps->irq, tps65010_irq,
-                       irqflags, DRIVER_NAME, tps);
+       /* the IRQ is active low, but many gpio lines can't support that
+        * so this driver uses falling-edge triggers instead.
+        */
+       if (client->irq > 0) {
+               status = request_irq(client->irq, tps65010_irq,
+                       IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+                       DRIVER_NAME, tps);
                if (status < 0) {
-                       dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n",
-                                       tps->irq, status);
-                       i2c_detach_client(&tps->client);
+                       dev_dbg(&client->dev, "can't get IRQ %d, err %d\n",
+                                       client->irq, status);
                        goto fail1;
                }
-#ifdef CONFIG_ARM
                /* annoying race here, ideally we'd have an option
                 * to claim the irq now and enable it later.
+                * FIXME genirq IRQF_NOAUTOEN now solves that ...
                 */
-               disable_irq(tps->irq);
+               disable_irq(client->irq);
                set_bit(FLAG_IRQ_ENABLE, &tps->flags);
-#endif
        } else
-               printk(KERN_WARNING "%s: IRQ not configured!\n",
-                               DRIVER_NAME);
+               dev_warn(&client->dev, "IRQ not configured!\n");
 
 
        switch (tps->model) {
@@ -583,23 +532,22 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
                break;
        /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */
        }
-       tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+       tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG);
        show_chgconfig(tps->por, "conf/init", tps->chgconf);
 
        show_chgstatus("chg/init",
-               i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS));
+               i2c_smbus_read_byte_data(client, TPS_CHGSTATUS));
        show_regstatus("reg/init",
-               i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS));
+               i2c_smbus_read_byte_data(client, TPS_REGSTATUS));
 
        pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME,
-               i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1),
-               i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2),
-               i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1));
+               i2c_smbus_read_byte_data(client, TPS_VDCDC1),
+               i2c_smbus_read_byte_data(client, TPS_VDCDC2),
+               i2c_smbus_read_byte_data(client, TPS_VREGS1));
        pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME,
-               i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO),
-               i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+               i2c_smbus_read_byte_data(client, TPS_DEFGPIO),
+               i2c_smbus_read_byte_data(client, TPS_MASK3));
 
-       tps65010_driver.attach_adapter = tps65010_noscan;
        the_tps = tps;
 
 #if    defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG)
@@ -615,15 +563,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
         * registers, and maybe disable VBUS draw.
         */
        tps->nmask1 = ~0;
-       (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1);
+       (void) i2c_smbus_write_byte_data(client, TPS_MASK1, ~tps->nmask1);
 
        tps->nmask2 = TPS_REG_ONOFF;
        if (tps->model == TPS65013)
                tps->nmask2 |= TPS_REG_NO_CHG;
-       (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2);
+       (void) i2c_smbus_write_byte_data(client, TPS_MASK2, ~tps->nmask2);
 
-       (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f
-               | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+       (void) i2c_smbus_write_byte_data(client, TPS_MASK3, 0x0f
+               | i2c_smbus_read_byte_data(client, TPS_MASK3));
 
        tps65010_work(&tps->work.work);
 
@@ -632,22 +580,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
        return 0;
 fail1:
        kfree(tps);
-       return 0;
-}
-
-static int __init tps65010_scan_bus(struct i2c_adapter *bus)
-{
-       if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -EINVAL;
-       return i2c_probe(bus, &addr_data, tps65010_probe);
+       return status;
 }
 
 static struct i2c_driver tps65010_driver = {
        .driver = {
                .name   = "tps65010",
        },
-       .attach_adapter = tps65010_scan_bus,
-       .detach_client  = __exit_p(tps65010_detach_client),
+       .probe  = tps65010_probe,
+       .remove = __exit_p(tps65010_remove),
 };
 
 /*-------------------------------------------------------------------------*/
@@ -702,7 +643,7 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
 
        mutex_lock(&the_tps->lock);
 
-       defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO);
+       defgpio = i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO);
 
        /* Configure GPIO for output */
        defgpio |= 1 << (gpio + 3);
@@ -718,12 +659,12 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
                break;
        }
 
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                TPS_DEFGPIO, defgpio);
 
        pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME,
                gpio, value ? "high" : "low",
-               i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO));
+               i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO));
 
        mutex_unlock(&the_tps->lock);
        return status;
@@ -753,11 +694,11 @@ int tps65010_set_led(unsigned led, unsigned mode)
        mutex_lock(&the_tps->lock);
 
        pr_debug("%s: led%i_on   0x%02x\n", DRIVER_NAME, led,
-               i2c_smbus_read_byte_data(&the_tps->client,
+               i2c_smbus_read_byte_data(the_tps->client,
                                TPS_LED1_ON + offs));
 
        pr_debug("%s: led%i_per  0x%02x\n", DRIVER_NAME, led,
-               i2c_smbus_read_byte_data(&the_tps->client,
+               i2c_smbus_read_byte_data(the_tps->client,
                                TPS_LED1_PER + offs));
 
        switch (mode) {
@@ -780,7 +721,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
                return -EINVAL;
        }
 
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                        TPS_LED1_ON + offs, led_on);
 
        if (status != 0) {
@@ -791,9 +732,9 @@ int tps65010_set_led(unsigned led, unsigned mode)
        }
 
        pr_debug("%s: led%i_on   0x%02x\n", DRIVER_NAME, led,
-               i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
+               i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs));
 
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                        TPS_LED1_PER + offs, led_per);
 
        if (status != 0) {
@@ -804,7 +745,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
        }
 
        pr_debug("%s: led%i_per  0x%02x\n", DRIVER_NAME, led,
-               i2c_smbus_read_byte_data(&the_tps->client,
+               i2c_smbus_read_byte_data(the_tps->client,
                                TPS_LED1_PER + offs));
 
        mutex_unlock(&the_tps->lock);
@@ -827,11 +768,11 @@ int tps65010_set_vib(unsigned value)
 
        mutex_lock(&the_tps->lock);
 
-       vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2);
+       vdcdc2 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC2);
        vdcdc2 &= ~(1 << 1);
        if (value)
                vdcdc2 |= (1 << 1);
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                TPS_VDCDC2, vdcdc2);
 
        pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off");
@@ -857,9 +798,9 @@ int tps65010_set_low_pwr(unsigned mode)
 
        pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME,
                mode ? "enable" : "disable",
-               i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+               i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
 
-       vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+       vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1);
 
        switch (mode) {
        case OFF:
@@ -871,7 +812,7 @@ int tps65010_set_low_pwr(unsigned mode)
                break;
        }
 
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                        TPS_VDCDC1, vdcdc1);
 
        if (status != 0)
@@ -879,7 +820,7 @@ int tps65010_set_low_pwr(unsigned mode)
                        DRIVER_NAME);
        else
                pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
-                       i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+                       i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
 
        mutex_unlock(&the_tps->lock);
 
@@ -902,9 +843,9 @@ int tps65010_config_vregs1(unsigned value)
        mutex_lock(&the_tps->lock);
 
        pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
-                       i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+                       i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1));
 
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                        TPS_VREGS1, value);
 
        if (status != 0)
@@ -912,7 +853,7 @@ int tps65010_config_vregs1(unsigned value)
                        DRIVER_NAME);
        else
                pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
-                       i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+                       i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1));
 
        mutex_unlock(&the_tps->lock);
 
@@ -941,11 +882,11 @@ int tps65013_set_low_pwr(unsigned mode)
        pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n",
                DRIVER_NAME,
                mode ? "enable" : "disable",
-               i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG),
-               i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+               i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG),
+               i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
 
-       chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
-       vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+       chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG);
+       vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1);
 
        switch (mode) {
        case OFF:
@@ -959,7 +900,7 @@ int tps65013_set_low_pwr(unsigned mode)
                break;
        }
 
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                        TPS_CHGCONFIG, chgconfig);
        if (status != 0) {
                printk(KERN_ERR "%s: Failed to write chconfig register\n",
@@ -968,11 +909,11 @@ int tps65013_set_low_pwr(unsigned mode)
                return status;
        }
 
-       chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
+       chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG);
        the_tps->chgconf = chgconfig;
        show_chgconfig(0, "chgconf", chgconfig);
 
-       status = i2c_smbus_write_byte_data(&the_tps->client,
+       status = i2c_smbus_write_byte_data(the_tps->client,
                        TPS_VDCDC1, vdcdc1);
 
        if (status != 0)
@@ -980,7 +921,7 @@ int tps65013_set_low_pwr(unsigned mode)
         DRIVER_NAME);
        else
                pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
-                       i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+                       i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
 
        mutex_unlock(&the_tps->lock);
 
@@ -1011,52 +952,6 @@ static int __init tps_init(void)
                msleep(10);
        }
 
-#ifdef CONFIG_ARM
-       if (machine_is_omap_osk()) {
-
-               // FIXME: More should be placed in the initialization code
-               //        of the submodules (DSP, ethernet, power management,
-               //        board-osk.c). Careful: I2C is initialized "late".
-
-               /* Let LED1 (D9) blink */
-               tps65010_set_led(LED1, BLINK);
-
-               /* Disable LED 2 (D2) */
-               tps65010_set_led(LED2, OFF);
-
-               /* Set GPIO 1 HIGH to disable VBUS power supply;
-                * OHCI driver powers it up/down as needed.
-                */
-               tps65010_set_gpio_out_value(GPIO1, HIGH);
-
-               /* Set GPIO 2 low to turn on LED D3 */
-               tps65010_set_gpio_out_value(GPIO2, HIGH);
-
-               /* Set GPIO 3 low to take ethernet out of reset */
-               tps65010_set_gpio_out_value(GPIO3, LOW);
-
-               /* gpio4 for VDD_DSP */
-
-               /* Enable LOW_PWR */
-               tps65010_set_low_pwr(ON);
-
-               /* Switch VLDO2 to 3.0V for AIC23 */
-               tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE);
-
-       } else if (machine_is_omap_h2()) {
-               /* gpio3 for SD, gpio4 for VDD_DSP */
-
-               /* Enable LOW_PWR */
-               tps65010_set_low_pwr(ON);
-       } else if (machine_is_omap_h3()) {
-               /* gpio4 for SD, gpio3 for VDD_DSP */
-#ifdef CONFIG_PM
-               /* Enable LOW_PWR */
-               tps65013_set_low_pwr(ON);
-#endif
-       }
-#endif
-
        return status;
 }
 /* NOTE:  this MUST be initialized before the other parts of the system
index 910a62de190d4e00e5320fcfaa5a8b1c2d26c9a6..e73d58c43f386a349856cdb95f2935510c2a79fe 100644 (file)
@@ -186,7 +186,7 @@ static struct device_attribute i2c_dev_attrs[] = {
        { },
 };
 
-struct bus_type i2c_bus_type = {
+static struct bus_type i2c_bus_type = {
        .name           = "i2c",
        .dev_attrs      = i2c_dev_attrs,
        .match          = i2c_device_match,
@@ -197,7 +197,6 @@ struct bus_type i2c_bus_type = {
        .suspend        = i2c_device_suspend,
        .resume         = i2c_device_resume,
 };
-EXPORT_SYMBOL_GPL(i2c_bus_type);
 
 /**
  * i2c_new_device - instantiate an i2c device for use with a new style driver
@@ -226,7 +225,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->adapter = adap;
 
        client->dev.platform_data = info->platform_data;
-       client->flags = info->flags;
+       device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);
+
+       client->flags = info->flags & ~I2C_CLIENT_WAKE;
        client->addr = info->addr;
        client->irq = info->irq;
 
@@ -279,7 +280,7 @@ EXPORT_SYMBOL_GPL(i2c_unregister_device);
 
 /* I2C bus adapters -- one roots each I2C or SMBUS segment */
 
-void i2c_adapter_dev_release(struct device *dev)
+static void i2c_adapter_dev_release(struct device *dev)
 {
        struct i2c_adapter *adap = to_i2c_adapter(dev);
        complete(&adap->dev_released);
@@ -297,7 +298,7 @@ static struct device_attribute i2c_adapter_attrs[] = {
        { },
 };
 
-struct class i2c_adapter_class = {
+static struct class i2c_adapter_class = {
        .owner                  = THIS_MODULE,
        .name                   = "i2c-adapter",
        .dev_attrs              = i2c_adapter_attrs,
@@ -930,28 +931,6 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
 }
 EXPORT_SYMBOL(i2c_master_recv);
 
-int i2c_control(struct i2c_client *client,
-       unsigned int cmd, unsigned long arg)
-{
-       int ret = 0;
-       struct i2c_adapter *adap = client->adapter;
-
-       dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);
-       switch (cmd) {
-               case I2C_RETRIES:
-                       adap->retries = arg;
-                       break;
-               case I2C_TIMEOUT:
-                       adap->timeout = arg;
-                       break;
-               default:
-                       if (adap->algo->algo_control!=NULL)
-                               ret = adap->algo->algo_control(adap,cmd,arg);
-       }
-       return ret;
-}
-EXPORT_SYMBOL(i2c_control);
-
 /* ----------------------------------------------------
  * the i2c address scanning function
  * Will not work for 10-bit addresses!
@@ -1306,7 +1285,22 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
 }
 EXPORT_SYMBOL(i2c_smbus_write_word_data);
 
-/* Returns the number of read bytes */
+/**
+ * i2c_smbus_read_block_data - SMBus block read request
+ * @client: Handle to slave device
+ * @command: Command byte issued to let the slave know what data should
+ *     be returned
+ * @values: Byte array into which data will be read; big enough to hold
+ *     the data returned by the slave.  SMBus allows at most 32 bytes.
+ *
+ * Returns the number of bytes read in the slave's response, else a
+ * negative number to indicate some kind of error.
+ *
+ * Note that using this function requires that the client's adapter support
+ * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality.  Not all adapter drivers
+ * support this; its emulation through I2C messaging relies on a specific
+ * mechanism (I2C_M_RECV_LEN) which may not be implemented.
+ */
 s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
                              u8 *values)
 {
index 64eee9551b2203f73654890921e766c4a7608c31..5a15e50748de11076202b2c91bc8c0afc9974701 100644 (file)
@@ -226,8 +226,10 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
 
                res = 0;
                for( i=0; i<rdwr_arg.nmsgs; i++ ) {
-                       /* Limit the size of the message to a sane amount */
-                       if (rdwr_pa[i].len > 8192) {
+                       /* Limit the size of the message to a sane amount;
+                        * and don't let length change either. */
+                       if ((rdwr_pa[i].len > 8192) ||
+                           (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
                                res = -EINVAL;
                                break;
                        }
@@ -352,9 +354,19 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
                                return -EFAULT;
                }
                return res;
-
+       case I2C_RETRIES:
+               client->adapter->retries = arg;
+               break;
+       case I2C_TIMEOUT:
+               client->adapter->timeout = arg;
+               break;
        default:
-               return i2c_control(client,cmd,arg);
+               /* NOTE:  returning a fault code here could cause trouble
+                * in buggy userspace code.  Some old kernel bugs returned
+                * zero in this case, and userspace code might accidentally
+                * have depended on that bug.
+                */
+               return -ENOTTY;
        }
        return 0;
 }
index aa0e0c9f74c5a132c043b1c6efd82e9e19bf1a94..8982c093243845ca4046529cbc3e3f6ac6d00b78 100644 (file)
@@ -1074,22 +1074,6 @@ endif
 config BLK_DEV_IDEDMA
        def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 
-config IDEDMA_IVB
-       bool "IGNORE word93 Validation BITS"
-       depends on BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS
-       ---help---
-         There are unclear terms in ATA-4 and ATA-5 standards how certain
-         hardware (an 80c ribbon) should be detected. Different interpretations
-         of the standards have been released in hardware. This causes problems:
-         for example, a host with Ultra Mode 4 (or higher) will not run
-         in that mode with an 80c ribbon.
-
-         If you are experiencing compatibility or performance problems, you
-         MAY try to answer Y here. However, it does not necessarily solve
-         any of your problems, it could even cause more of them.
-
-         It is normally safe to answer Y; however, the default is N.
-
 endif
 
 config BLK_DEV_HD_ONLY
index 7912a471f10daaa8e69cec965db3a0b3f819ee89..bd1f5b6703784463df33404a74cd4fe12dc6ebdf 100644 (file)
@@ -248,7 +248,7 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
  *     MW1     80      50      50      150     C
  *     MW2     70      25      25      120     C
  */
-static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
+static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
 {
        int cycle_time, use_dma_info = 0;
 
@@ -273,7 +273,7 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
                cycle_time = 480;
                break;
        default:
-               return 1;
+               return;
        }
 
        /*
@@ -287,8 +287,6 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
 
        printk("%s: %s selected (peak %dMB/s)\n", drive->name,
                ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
-
-       return ide_config_drive_speed(drive, xfer_mode);
 }
 
 static void icside_dma_host_off(ide_drive_t *drive)
@@ -313,41 +311,10 @@ static int icside_dma_on(ide_drive_t *drive)
 
 static int icside_dma_check(ide_drive_t *drive)
 {
-       struct hd_driveid *id = drive->id;
-       ide_hwif_t *hwif = HWIF(drive);
-       int xfer_mode = 0;
-
-       if (!(id->capability & 1) || !hwif->autodma)
-               goto out;
-
-       /*
-        * Consult the list of known "bad" drives
-        */
-       if (__ide_dma_bad_drive(drive))
-               goto out;
-
-       /*
-        * Enable DMA on any drive that has multiword DMA
-        */
-       if (id->field_valid & 2) {
-               xfer_mode = ide_max_dma_mode(drive);
-               goto out;
-       }
-
-       /*
-        * Consult the list of known "good" drives
-        */
-       if (__ide_dma_good_drive(drive)) {
-               if (id->eide_dma_time > 150)
-                       goto out;
-               xfer_mode = XFER_MW_DMA_1;
-       }
-
-out:
-       if (xfer_mode == 0)
-               return -1;
+       if (ide_tune_dma(drive))
+               return 0;
 
-       return icside_set_speed(drive, xfer_mode) ? -1 : 0;
+       return -1;
 }
 
 static int icside_dma_end(ide_drive_t *drive)
@@ -464,7 +431,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
 
        hwif->dmatable_cpu      = NULL;
        hwif->dmatable_dma      = 0;
-       hwif->speedproc         = icside_set_speed;
+       hwif->set_dma_mode      = icside_set_dma_mode;
        hwif->autodma           = 1;
 
        hwif->ide_dma_check     = icside_dma_check;
index 4bb42b30bfc0d34874d5549abbb37b33b4c833ee..2b4d2a0ae5c26e1d7bf7f42b1630b0c36a6332ab 100644 (file)
@@ -716,11 +716,9 @@ static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio)
        }
 
        cris_ide_set_speed(TYPE_PIO, setup, strobe, hold);
-
-       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static int speed_cris_ide(ide_drive_t *drive, const u8 speed)
+static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        int cyc = 0, dvs = 0, strobe = 0, hold = 0;
 
@@ -759,8 +757,6 @@ static int speed_cris_ide(ide_drive_t *drive, const u8 speed)
                cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0);
        else
                cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 void __init
@@ -791,7 +787,7 @@ init_e100_ide (void)
                hwif->mmio = 1;
                hwif->chipset = ide_etrax100;
                hwif->set_pio_mode = &cris_set_pio_mode;
-               hwif->speedproc = &speed_cris_ide;
+               hwif->set_dma_mode = &cris_set_dma_mode;
                hwif->ata_input_data = &cris_ide_input_data;
                hwif->ata_output_data = &cris_ide_output_data;
                hwif->atapi_input_bytes = &cris_atapi_input_bytes;
index 6bff81a58bf3ab7b3baac75b3d6b1691ce29b255..1d5f6823101c26c2e73980c6705878956e68be85 100644 (file)
@@ -649,7 +649,6 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
        if (!on)
                acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
 }
-EXPORT_SYMBOL_GPL(ide_acpi_set_state);
 
 /**
  * ide_acpi_init - initialize the ACPI link for an IDE interface
index 6000c08f51ba30741f8451daeb35e6289ec4d8c3..b453211ee0fc1364cebe09be3bd0296bf6500207 100644 (file)
@@ -169,6 +169,11 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 
 EXPORT_SYMBOL_GPL(ide_dma_intr);
 
+static int ide_dma_good_drive(ide_drive_t *drive)
+{
+       return ide_in_drive_list(drive->id, drive_whitelist);
+}
+
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     ide_build_sglist        -       map IDE scatter gather for DMA I/O
@@ -357,7 +362,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
                                return 0;
 
                /* Consult the list of known "good" drives */
-               if (__ide_dma_good_drive(drive))
+               if (ide_dma_good_drive(drive))
                        return 0;
        }
 
@@ -639,14 +644,6 @@ int __ide_dma_bad_drive (ide_drive_t *drive)
 
 EXPORT_SYMBOL(__ide_dma_bad_drive);
 
-int __ide_dma_good_drive (ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
-       return ide_in_drive_list(id, drive_whitelist);
-}
-
-EXPORT_SYMBOL(__ide_dma_good_drive);
-
 static const u8 xfer_mode_bases[] = {
        XFER_UDMA_0,
        XFER_MW_DMA_0,
@@ -746,6 +743,14 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
                }
        }
 
+       if (hwif->chipset == ide_acorn && mode == 0) {
+               /*
+                * is this correct?
+                */
+               if (ide_dma_good_drive(drive) && drive->id->eide_dma_time < 150)
+                       mode = XFER_MW_DMA_1;
+       }
+
        printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
 
        return min(mode, req_mode);
@@ -769,7 +774,10 @@ int ide_tune_dma(ide_drive_t *drive)
        if (!speed)
                return 0;
 
-       if (drive->hwif->speedproc(drive, speed))
+       if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+               return 0;
+
+       if (ide_set_dma_mode(drive, speed))
                return 0;
 
        return 1;
index 9560a8f4a86c853832d45b71ff09ca55994367dd..4cece930114cf637cbacfc239b0a6aa3f083e5b6 100644 (file)
@@ -836,9 +836,17 @@ static ide_startstop_t do_special (ide_drive_t *drive)
                if (set_pio_mode_abuse(drive->hwif, req_pio)) {
                        if (hwif->set_pio_mode)
                                hwif->set_pio_mode(drive, req_pio);
-               } else
+               } else {
+                       int keep_dma = drive->using_dma;
+
                        ide_set_pio(drive, req_pio);
 
+                       if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+                               if (keep_dma)
+                                       hwif->ide_dma_on(drive);
+                       }
+               }
+
                return ide_stopped;
        } else {
                if (drive->media == ide_disk)
index cf0678b6116183ebf14e6108154b94955a4d4862..aa738833bed587f9fef45f9c65dc37a15d0d3ce5 100644 (file)
@@ -472,58 +472,23 @@ int drive_is_ready (ide_drive_t *drive)
 
 EXPORT_SYMBOL(drive_is_ready);
 
-/*
- * Global for All, and taken from ide-pmac.c. Can be called
- * with spinlock held & IRQs disabled, so don't schedule !
- */
-int wait_for_ready (ide_drive_t *drive, int timeout)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 stat                 = 0;
-
-       while(--timeout) {
-               stat = hwif->INB(IDE_STATUS_REG);
-               if (!(stat & BUSY_STAT)) {
-                       if (drive->ready_stat == 0)
-                               break;
-                       else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
-                               break;
-               }
-               mdelay(1);
-       }
-       if ((stat & ERR_STAT) || timeout <= 0) {
-               if (stat & ERR_STAT) {
-                       printk(KERN_ERR "%s: wait_for_ready, "
-                               "error status: %x\n", drive->name, stat);
-               }
-               return 1;
-       }
-       return 0;
-}
-
 /*
  * This routine busy-waits for the drive status to be not "busy".
  * It then checks the status for all of the "good" bits and none
  * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after invoking ide_error() -- caller should just return.
+ * cases return error -- caller may then invoke ide_error().
  *
  * This routine should get fixed to not hog the cpu during extra long waits..
  * That could be done by busy-waiting for the first jiffy or two, and then
  * setting a timer to wake up at half second intervals thereafter,
  * until timeout is achieved, before timing out.
  */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       u8 stat;
-       int i;
+       ide_hwif_t *hwif = drive->hwif;
        unsigned long flags;
-       /* bail early if we've exceeded max_failures */
-       if (drive->max_failures && (drive->failures > drive->max_failures)) {
-               *startstop = ide_stopped;
-               return 1;
-       }
+       int i;
+       u8 stat;
 
        udelay(1);      /* spec allows drive 400ns to assert "BUSY" */
        if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
@@ -541,8 +506,8 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
                                        break;
 
                                local_irq_restore(flags);
-                               *startstop = ide_error(drive, "status timeout", stat);
-                               return 1;
+                               *rstat = stat;
+                               return -EBUSY;
                        }
                }
                local_irq_restore(flags);
@@ -556,11 +521,39 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
         */
        for (i = 0; i < 10; i++) {
                udelay(1);
-               if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+               if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) {
+                       *rstat = stat;
                        return 0;
+               }
        }
-       *startstop = ide_error(drive, "status error", stat);
-       return 1;
+       *rstat = stat;
+       return -EFAULT;
+}
+
+/*
+ * In case of error returns error value after doing "*startstop = ide_error()".
+ * The caller should return the updated value of "startstop" in this case,
+ * "startstop" is unchanged when the function returns 0.
+ */
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+       int err;
+       u8 stat;
+
+       /* bail early if we've exceeded max_failures */
+       if (drive->max_failures && (drive->failures > drive->max_failures)) {
+               *startstop = ide_stopped;
+               return 1;
+       }
+
+       err = __ide_wait_stat(drive, good, bad, timeout, &stat);
+
+       if (err) {
+               char *s = (err == -EBUSY) ? "status timeout" : "status error";
+               *startstop = ide_error(drive, s, stat);
+       }
+
+       return err;
 }
 
 EXPORT_SYMBOL(ide_wait_stat);
@@ -620,15 +613,10 @@ u8 eighty_ninty_three (ide_drive_t *drive)
 
        /*
         * FIXME:
-        * - change master/slave IDENTIFY order
         * - force bit13 (80c cable present) check also for !ivb devices
         *   (unless the slave device is pre-ATA3)
         */
-#ifndef CONFIG_IDEDMA_IVB
        if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000)))
-#else
-       if (id->hw_config & 0x6000)
-#endif
                return 1;
 
 no_80w:
@@ -778,15 +766,10 @@ int ide_driveid_update (ide_drive_t *drive)
 #endif
 }
 
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       int     i, error        = 1;
+       ide_hwif_t *hwif = drive->hwif;
+       int error;
        u8 stat;
 
 //     while (HWGROUP(drive)->busy)
@@ -826,35 +809,10 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
        hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
        if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
                hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-       udelay(1);
-       /*
-        * Wait for drive to become non-BUSY
-        */
-       if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
-               unsigned long flags, timeout;
-               local_irq_set(flags);
-               timeout = jiffies + WAIT_CMD;
-               while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
-                       if (time_after(jiffies, timeout))
-                               break;
-               }
-               local_irq_restore(flags);
-       }
 
-       /*
-        * Allow status to settle, then read it again.
-        * A few rare drives vastly violate the 400ns spec here,
-        * so we'll wait up to 10usec for a "good" status
-        * rather than expensively fail things immediately.
-        * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-        */
-       for (i = 0; i < 10; i++) {
-               udelay(1);
-               if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
-                       error = 0;
-                       break;
-               }
-       }
+       error = __ide_wait_stat(drive, drive->ready_stat,
+                               BUSY_STAT|DRQ_STAT|ERR_STAT,
+                               WAIT_CMD, &stat);
 
        SELECT_MASK(drive, 0);
 
@@ -899,9 +857,6 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
        return error;
 }
 
-EXPORT_SYMBOL(ide_config_drive_speed);
-
-
 /*
  * This should get invoked any time we exit the driver to
  * wait for an interrupt response from a drive.  handler() points
index d97390c0543b823e4da4176e158f8a0061b6ebb9..0e2562f0f74ec55f8455b04f322ba866cea8a06b 100644 (file)
@@ -349,7 +349,7 @@ void ide_set_pio(ide_drive_t *drive, u8 req_pio)
                          drive->name, host_pio, req_pio,
                          req_pio == 255 ? "(auto-tune)" : "", pio);
 
-       hwif->set_pio_mode(drive, pio);
+       (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
 }
 
 EXPORT_SYMBOL_GPL(ide_set_pio);
@@ -378,39 +378,83 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
                blk_queue_bounce_limit(drive->queue, addr);
 }
 
+int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       if (hwif->set_pio_mode == NULL)
+               return -1;
+
+       /*
+        * TODO: temporary hack for some legacy host drivers that didn't
+        * set transfer mode on the device in ->set_pio_mode method...
+        */
+       if (hwif->set_dma_mode == NULL) {
+               hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+               return 0;
+       }
+
+       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+               if (ide_config_drive_speed(drive, mode))
+                       return -1;
+               hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+               return 0;
+       } else {
+               hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+               return ide_config_drive_speed(drive, mode);
+       }
+}
+
+int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       if (hwif->set_dma_mode == NULL)
+               return -1;
+
+       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+               if (ide_config_drive_speed(drive, mode))
+                       return -1;
+               hwif->set_dma_mode(drive, mode);
+               return 0;
+       } else {
+               hwif->set_dma_mode(drive, mode);
+               return ide_config_drive_speed(drive, mode);
+       }
+}
+
+EXPORT_SYMBOL_GPL(ide_set_dma_mode);
+
 /**
  *     ide_set_xfer_rate       -       set transfer rate
  *     @drive: drive to set
- *     @speed: speed to attempt to set
+ *     @rate: speed to attempt to set
  *     
  *     General helper for setting the speed of an IDE device. This
  *     function knows about user enforced limits from the configuration
- *     which speedproc() does not.  High level drivers should never
- *     invoke speedproc() directly.
+ *     which ->set_pio_mode/->set_dma_mode does not.
  */
+
 int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 {
        ide_hwif_t *hwif = drive->hwif;
 
-       if (hwif->speedproc == NULL)
+       if (hwif->set_dma_mode == NULL)
                return -1;
 
        rate = ide_rate_filter(drive, rate);
 
-       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) {
-               if (hwif->set_pio_mode)
-                       hwif->set_pio_mode(drive, rate - XFER_PIO_0);
+       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+               return ide_set_pio_mode(drive, rate);
 
-               /*
-                * FIXME: this is incorrect to return zero here but
-                * since all users of ide_set_xfer_rate() ignore
-                * the return value it is not a problem currently
-                */
-               return 0;
-       }
+       /*
+        * TODO: transfer modes 0x00-0x07 passed from the user-space are
+        * currently handled here which needs fixing (please note that such
+        * case could happen iff the transfer mode has already been set on
+        * the device by ide-proc.c::set_xfer_rate()).
+        */
 
-       return hwif->speedproc(drive, rate);
+       return ide_set_dma_mode(drive, rate);
 }
 
 static void ide_dump_opcode(ide_drive_t *drive)
index b4c9f63a38544b68123a03ab9fc44947530c623b..d1011712601c9a01913d143200c615d713d4bae2 100644 (file)
@@ -719,9 +719,9 @@ EXPORT_SYMBOL_GPL(ide_undecoded_slave);
  */
 static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
 {
-       unsigned int unit;
        unsigned long flags;
        unsigned int irqd;
+       int unit;
 
        if (hwif->noprobe)
                return;
@@ -777,10 +777,9 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
                printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
 
        /*
-        * Second drive should only exist if first drive was found,
-        * but a lot of cdrom drives are configured as single slaves.
+        * Need to probe slave device first to make it release PDIAG-.
         */
-       for (unit = 0; unit < MAX_DRIVES; ++unit) {
+       for (unit = MAX_DRIVES - 1; unit >= 0; unit--) {
                ide_drive_t *drive = &hwif->drives[unit];
                drive->dn = (hwif->channel ? 2 : 0) + unit;
                (void) probe_for_drive(drive);
index a96a8b1b3539b8bdec2972fc0f07eeca21f4f420..5c0e4078b5cbf7dbbb398998fff7b08a3310b2c0 100644 (file)
@@ -397,7 +397,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 #endif
 
        hwif->set_pio_mode              = tmp_hwif->set_pio_mode;
-       hwif->speedproc                 = tmp_hwif->speedproc;
+       hwif->set_dma_mode              = tmp_hwif->set_dma_mode;
        hwif->mdma_filter               = tmp_hwif->mdma_filter;
        hwif->udma_filter               = tmp_hwif->udma_filter;
        hwif->selectproc                = tmp_hwif->selectproc;
index ccfb9893a467047ff6db738a14f8df772ffec545..b992b2b91fe2ba684dadbc7345ffb96d4161f8bc 100644 (file)
@@ -65,7 +65,7 @@ found:
        hwif->hw.irq = hwif->irq = irq;
 
        hwif->hw.dma = NO_DMA;
-       hwif->hw.chipset = ide_generic;
+       hwif->chipset = hwif->hw.chipset = ide_generic;
 
        if (mmio) {
                hwif->mmio = 1;
index 85819ae20602e9c5696f78642e9032944680d4e0..aebde49365d16a68b28fdce811a95052c3262e1b 100644 (file)
@@ -101,12 +101,7 @@ void auide_outsw(unsigned long port, void *addr, u32 count)
 
 static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       int mem_sttime;
-       int mem_stcfg;
-       u8 speed;
-
-       mem_sttime = 0;
-       mem_stcfg  = au_readl(MEM_STCFG2);
+       int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
 
        /* set pio mode! */
        switch(pio) {
@@ -164,18 +159,11 @@ static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 
        au_writel(mem_sttime,MEM_STTIME2);
        au_writel(mem_stcfg,MEM_STCFG2);
-
-       speed = pio + XFER_PIO_0;
-       ide_config_drive_speed(drive, speed);
 }
 
-static int auide_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
-       int mem_sttime;
-       int mem_stcfg;
-
-       mem_sttime = 0;
-       mem_stcfg  = au_readl(MEM_STCFG2);
+       int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
 
        switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -211,16 +199,11 @@ static int auide_tune_chipset(ide_drive_t *drive, const u8 speed)
                break;
 #endif
        default:
-               return 1;
+               return;
        }
 
-       if (ide_config_drive_speed(drive, speed))
-               return 1;
-
        au_writel(mem_sttime,MEM_STTIME2);
        au_writel(mem_stcfg,MEM_STCFG2);
-
-       return 0;
 }
 
 /*
@@ -682,6 +665,7 @@ static int au_ide_probe(struct device *dev)
 #endif
 
        hwif->pio_mask = ATA_PIO4;
+       hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
 
        hwif->noprobe = 0;
        hwif->drives[0].unmask          = 1;
@@ -702,7 +686,7 @@ static int au_ide_probe(struct device *dev)
 #endif
 
        hwif->set_pio_mode              = &au1xxx_set_pio_mode;
-       hwif->speedproc                 = &auide_tune_chipset;
+       hwif->set_dma_mode              = &auide_set_dma_mode;
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
        hwif->dma_off_quietly           = &auide_dma_off_quietly;
index 0d5f62c5dfaee248398be6e3a153b9d1e5eb7264..d6cb2d5143c8812151084e3640375f22ede8a7ec 100644 (file)
@@ -87,7 +87,7 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
        return chipset_table->ultra_settings;
 }
 
-static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -111,10 +111,9 @@ static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed)
        tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
        pci_write_config_byte(dev, 0x54, tmp2);
        local_irq_restore(flags);
-       return(ide_config_drive_speed(drive, speed));
 }
 
-static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -135,12 +134,11 @@ static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed)
        tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
        pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
        local_irq_restore(flags);
-       return(ide_config_drive_speed(drive, speed));
 }
 
 static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
+       drive->hwif->set_dma_mode(drive, pio + XFER_PIO_0);
 }
 
 static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
@@ -205,9 +203,9 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
        if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
                if(hwif->mate)
                        hwif->mate->serialized = hwif->serialized = 1;
-               hwif->speedproc = &aec6210_tune_chipset;
+               hwif->set_dma_mode = &aec6210_set_mode;
        } else
-               hwif->speedproc = &aec6260_tune_chipset;
+               hwif->set_dma_mode = &aec6260_set_mode;
 
        if (!hwif->dma_base) {
                hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
index d04b966b4347a4288dba72e4584cd807f8852492..0b83443bf250f3111af476d732f0a938c9c7135a 100644 (file)
@@ -283,14 +283,14 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 /**
- *     ali_tune_pio    -       set host controller for PIO mode
+ *     ali_set_pio_mode        -       set host controller for PIO mode
  *     @drive: drive
  *     @pio: PIO mode number
  *
  *     Program the controller for the given PIO mode.
  */
 
-static void ali_tune_pio(ide_drive_t *drive, const u8 pio)
+static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = HWIF(drive);
        struct pci_dev *dev = hwif->pci_dev;
@@ -357,21 +357,6 @@ static void ali_tune_pio(ide_drive_t *drive, const u8 pio)
         */
 }
 
-/**
- *     ali_set_pio_mode        -       set up drive for PIO mode
- *     @drive: drive to tune
- *     @pio: desired mode
- *
- *     Program the controller with the desired PIO timing for the given drive.
- *     Then set up the drive itself.
- */
-
-static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       ali_tune_pio(drive, pio);
-       (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
 /**
  *     ali_udma_filter         -       compute UDMA mask
  *     @drive: IDE device
@@ -401,15 +386,14 @@ static u8 ali_udma_filter(ide_drive_t *drive)
 }
 
 /**
- *     ali15x3_tune_chipset    -       set up chipset/drive for new speed
- *     @drive: drive to configure for
- *     @speed: desired speed
+ *     ali_set_dma_mode        -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
  *     Configure the hardware for the desired IDE transfer mode.
- *     We also do the needed drive configuration through helpers
  */
 
-static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -419,7 +403,7 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
        int m5229_udma          = (hwif->channel) ? 0x57 : 0x56;
 
        if (speed < XFER_PIO_0)
-               return 1;
+               return;
 
        if (speed == XFER_UDMA_6)
                speed1 = 0x47;
@@ -450,7 +434,6 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
                        pci_write_config_byte(dev, 0x4b, tmpbyte);
                }
        }
-       return (ide_config_drive_speed(drive, speed));
 }
 
 /**
@@ -699,7 +682,7 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
 {
        hwif->autodma = 0;
        hwif->set_pio_mode = &ali_set_pio_mode;
-       hwif->speedproc = &ali15x3_tune_chipset;
+       hwif->set_dma_mode = &ali_set_dma_mode;
        hwif->udma_filter = &ali_udma_filter;
 
        /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
@@ -711,6 +694,10 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
                return;
        }
 
+       /*
+        * check in ->init_dma guarantees m5229_revision >= 0x20 here
+        */
+
        if (m5229_revision > 0x20)
                hwif->atapi_dma = 1;
 
@@ -728,18 +715,15 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
-        if (m5229_revision >= 0x20) {
-                /*
-                 * M1543C or newer for DMAing
-                 */
-                hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
-               hwif->dma_setup = &ali15x3_dma_setup;
-               if (!noautodma)
-                       hwif->autodma = 1;
-
-               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-                       hwif->cbl = ata66_ali15x3(hwif);
-       }
+       hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
+       hwif->dma_setup = &ali15x3_dma_setup;
+
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = ata66_ali15x3(hwif);
+
+       if (!noautodma)
+               hwif->autodma = 1;
+
        hwif->drives[0].autodma = hwif->autodma;
        hwif->drives[1].autodma = hwif->autodma;
 }
index 513205e52ad2f0b6a9ff8e68974502ad5b47293c..6ff4089a23793b8de6327cc1e2ec6ea3e50cbdc3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Version 2.22
+ * Version 2.23
  *
  * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
  * IDE driver for Linux.
@@ -229,20 +229,16 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
 }
 
 /*
- * amd_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
+ * amd_set_drive() computes timing values and configures the chipset
+ * to a desired transfer mode.  It also can be called by upper layers.
  */
 
-static int amd_set_drive(ide_drive_t *drive, const u8 speed)
+static void amd_set_drive(ide_drive_t *drive, const u8 speed)
 {
        ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
        struct ide_timing t, p;
        int T, UT;
 
-       if (speed != XFER_PIO_SLOW)
-               ide_config_drive_speed(drive, speed);
-
        T = 1000000000 / amd_clock;
        UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2);
 
@@ -257,12 +253,6 @@ static int amd_set_drive(ide_drive_t *drive, const u8 speed)
        if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
 
        amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
-
-       if (!drive->init_speed) 
-               drive->init_speed = speed;
-       drive->current_speed = speed;
-
-       return 0;
 }
 
 /*
@@ -399,7 +389,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
        hwif->autodma = 0;
 
        hwif->set_pio_mode = &amd_set_pio_mode;
-       hwif->speedproc = &amd_set_drive;
+       hwif->set_dma_mode = &amd_set_drive;
 
        for (i = 0; i < 2; i++) {
                hwif->drives[i].io_32bit = 1;
@@ -441,7 +431,8 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
                .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
                .bootable       = ON_BOARD,                             \
                .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST            \
-                               | IDE_HFLAG_PIO_NO_DOWNGRADE,           \
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE            \
+                               | IDE_HFLAG_POST_SET_MODE,              \
                .pio_mask       = ATA_PIO5,                             \
        }
 
@@ -454,7 +445,8 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
                .enablebits     = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
                .bootable       = ON_BOARD,                             \
                .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST            \
-                               | IDE_HFLAG_PIO_NO_DOWNGRADE,           \
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE            \
+                               | IDE_HFLAG_POST_SET_MODE,              \
                .pio_mask       = ATA_PIO5,                             \
        }
 
index 178876a3afca7d50d94b4c802b61cd67c83913b5..0eb97f021d3982617b33e9e19529e966a912ec20 100644 (file)
@@ -122,14 +122,14 @@ static void atiixp_dma_host_off(ide_drive_t *drive)
 }
 
 /**
- *     atiixp_tune_pio -       tune a drive attached to a ATIIXP
- *     @drive: drive to tune
- *     @pio: desired PIO mode
+ *     atiixp_set_pio_mode     -       set host controller for PIO mode
+ *     @drive: drive
+ *     @pio: PIO mode number
  *
  *     Set the interface PIO mode.
  */
 
-static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
+static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        struct pci_dev *dev = drive->hwif->pci_dev;
        unsigned long flags;
@@ -153,23 +153,16 @@ static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
        spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
-static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       atiixp_tune_pio(drive, pio);
-       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
 /**
- *     atiixp_tune_chipset     -       tune a ATIIXP interface
- *     @drive: IDE drive to tune
- *     @speed: speed to configure
+ *     atiixp_set_dma_mode     -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
- *     Set a ATIIXP interface channel to the desired speeds. This involves
- *     requires the right timing data into the ATIIXP configuration space
- *     then setting the drive parameters appropriately
+ *     Set a ATIIXP host controller to the desired DMA mode.  This involves
+ *     programming the right timing data into the PCI configuration space.
  */
 
-static int atiixp_speedproc(ide_drive_t *drive, const u8 speed)
+static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        struct pci_dev *dev = drive->hwif->pci_dev;
        unsigned long flags;
@@ -204,9 +197,7 @@ static int atiixp_speedproc(ide_drive_t *drive, const u8 speed)
        else
                pio = speed - XFER_PIO_0;
 
-       atiixp_tune_pio(drive, pio);
-
-       return ide_config_drive_speed(drive, speed);
+       atiixp_set_pio_mode(drive, pio);
 }
 
 /**
@@ -249,7 +240,7 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
 
        hwif->autodma = 0;
        hwif->set_pio_mode = &atiixp_set_pio_mode;
-       hwif->speedproc = &atiixp_speedproc;
+       hwif->set_dma_mode = &atiixp_set_dma_mode;
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
 
index 0b568c60f9263767d0936a32a94efeb4c7c72e16..d50f15e34b80fb6a63fc6997a89074b59509145a 100644 (file)
@@ -280,10 +280,9 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
                return;
 
        cmd64x_tune_pio(drive, pio);
-       (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -324,13 +323,11 @@ static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed)
                program_cycle_times(drive, 480, 215);
                break;
        default:
-               return 1;
+               return;
        }
 
        if (speed >= XFER_SW_DMA_0)
                (void) pci_write_config_byte(dev, pciU, regU);
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
@@ -524,7 +521,7 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
        pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
 
        hwif->set_pio_mode = &cmd64x_set_pio_mode;
-       hwif->speedproc = &cmd64x_tune_chipset;
+       hwif->set_dma_mode = &cmd64x_set_dma_mode;
 
        hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
index 1217d2a747fbbee24c305471dfe6e0113b66b1f4..fbce90048aecfc0ad1389c7503ab4159cef4a409 100644 (file)
@@ -96,22 +96,13 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
        reg = inb(hwif->dma_base + 0x02 + 8*controller);
        reg |= 1<<((drive->dn&1)+5);
        outb(reg, hwif->dma_base + 0x02 + 8*controller);
-
-       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        printk(KERN_ERR "cs55x0: bad ide timing.\n");
 
        cs5520_set_pio_mode(drive, 0);
-
-       /*
-        * FIXME: this is incorrect to return zero here but
-        * since all users of ide_set_xfer_rate() ignore
-        * the return value it is not a problem currently
-        */
-       return 0;
 }
 
 static int cs5520_config_drive_xfer_rate(ide_drive_t *drive)
@@ -150,26 +141,25 @@ static int cs5520_dma_on(ide_drive_t *drive)
 static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
 {
        hwif->set_pio_mode = &cs5520_set_pio_mode;
-       hwif->speedproc = &cs5520_tune_chipset;
-       hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
-       hwif->ide_dma_on = &cs5520_dma_on;
+       hwif->set_dma_mode = &cs5520_set_dma_mode;
 
-       if(!noautodma)
-               hwif->autodma = 1;
-       
-       if(!hwif->dma_base)
-       {
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
+       if (hwif->dma_base == 0) {
+               hwif->drives[1].autotune = hwif->drives[0].autotune = 1;
                return;
        }
 
+       hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
+       hwif->ide_dma_on = &cs5520_dma_on;
+
        /* ATAPI is harder so leave it for now */
        hwif->atapi_dma = 0;
        hwif->ultra_mask = 0;
        hwif->swdma_mask = 0;
        hwif->mwdma_mask = 0;
-       
+
+       if (!noautodma)
+               hwif->autodma = 1;
+
        hwif->drives[0].autodma = hwif->autodma;
        hwif->drives[1].autodma = hwif->autodma;
 }
index 741507b4cd93b0c789599fec220240c8424e7c92..e4121577cef0291e71abb435cd88b7ab21b51ecb 100644 (file)
 #include <asm/io.h>
 #include <asm/irq.h>
 
-/**
- *     cs5530_xfer_set_mode    -       set a new transfer mode at the drive
- *     @drive: drive to tune
- *     @mode: new mode
- *
- *     Logging wrapper to the IDE driver speed configuration. This can
- *     probably go away now.
- */
-static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
-{
-       printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
-               drive->name, ide_xfer_verbose(mode));
-       return (ide_config_drive_speed(drive, mode));
-}
-
 /*
  * Here are the standard PIO mode 0-4 timings for each "format".
  * Format-0 uses fast data reg timings, with slower command reg timings.
@@ -62,20 +46,12 @@ static unsigned int cs5530_pio_timings[2][5] = {
 #define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
 #define CS5530_BASEREG(hwif)   (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
 
-static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
-{
-       unsigned long basereg = CS5530_BASEREG(drive->hwif);
-       unsigned int format = (inl(basereg + 4) >> 31) & 1;
-
-       outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
-}
-
 /**
- *     cs5530_set_pio_mode     -       set PIO mode
+ *     cs5530_set_pio_mode     -       set host controller for PIO mode
  *     @drive: drive
  *     @pio: PIO mode number
  *
- *     Handles setting of PIO mode for both the chipset and drive.
+ *     Handles setting of PIO mode for the chipset.
  *
  *     The init_hwif_cs5530() routine guarantees that all drives
  *     will have valid default PIO timings set up before we get here.
@@ -83,8 +59,10 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
 
 static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
-               cs5530_tunepio(drive, pio);
+       unsigned long basereg = CS5530_BASEREG(drive->hwif);
+       unsigned int format = (inl(basereg + 4) >> 31) & 1;
+
+       outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
 }
 
 /**
@@ -142,20 +120,11 @@ static int cs5530_config_dma(ide_drive_t *drive)
        return 1;
 }
 
-static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode)
+static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
        unsigned long basereg;
        unsigned int reg, timings = 0;
 
-       /*
-        * Tell the drive to switch to the new mode; abort on failure.
-        */
-       if (cs5530_set_xfer_mode(drive, mode))
-               return 1;       /* failure */
-
-       /*
-        * Now tune the chipset to match the drive:
-        */
        switch (mode) {
                case XFER_UDMA_0:       timings = 0x00921250; break;
                case XFER_UDMA_1:       timings = 0x00911140; break;
@@ -180,8 +149,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode)
                outl(reg, basereg + 4);         /* write drive0 config register */
                outl(timings, basereg + 12);    /* write drive1 config register */
        }
-
-       return 0;       /* success */
 }
 
 /**
@@ -299,7 +266,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
                hwif->serialized = hwif->mate->serialized = 1;
 
        hwif->set_pio_mode = &cs5530_set_pio_mode;
-       hwif->speedproc = &cs5530_tune_chipset;
+       hwif->set_dma_mode = &cs5530_set_dma_mode;
 
        basereg = CS5530_BASEREG(hwif);
        d0_timings = inl(basereg + 0);
@@ -340,6 +307,7 @@ static ide_pci_device_t cs5530_chipset __devinitdata = {
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
        .pio_mask       = ATA_PIO4,
+       .host_flags     = IDE_HFLAG_POST_SET_MODE,
 };
 
 static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 383b7eccbcbbc63ccb25392f5d1175862b4588c5..257865778f923ce628b673bf52f9eb4e292bd10e 100644 (file)
@@ -131,24 +131,21 @@ static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
        }
 }
 
-/****
- *     cs5535_set_drive         -     Configure the drive to the new speed
- *     @drive: Drive to set up
- *     @speed: desired speed
+/**
+ *     cs5535_set_dma_mode     -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
- *     cs5535_set_drive() configures the drive and the chipset to a
- *     new speed. It also can be called by upper layers.
+ *     Programs the chipset for DMA mode.
  */
-static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
+
+static void cs5535_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
-       ide_config_drive_speed(drive, speed);
        cs5535_set_speed(drive, speed);
-
-       return 0;
 }
 
 /**
- *     cs5535_set_pio_mode     -       PIO setup
+ *     cs5535_set_pio_mode     -       set host controller for PIO mode
  *     @drive: drive
  *     @pio: PIO mode number
  *
@@ -157,7 +154,6 @@ static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
 
 static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       ide_config_drive_speed(drive, XFER_PIO_0 + pio);
        cs5535_set_speed(drive, XFER_PIO_0 + pio);
 }
 
@@ -194,12 +190,16 @@ static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
  */
 static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
 {
-       int i;
-
        hwif->autodma = 0;
 
        hwif->set_pio_mode = &cs5535_set_pio_mode;
-       hwif->speedproc = &cs5535_set_drive;
+       hwif->set_dma_mode = &cs5535_set_dma_mode;
+
+       hwif->drives[1].autotune = hwif->drives[0].autotune = 1;
+
+       if (hwif->dma_base == 0)
+               return;
+
        hwif->ide_dma_check = &cs5535_dma_check;
 
        hwif->atapi_dma = 1;
@@ -211,11 +211,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
        if (!noautodma)
                hwif->autodma = 1;
 
-       /* just setting autotune and not worrying about bios timings */
-       for (i = 0; i < 2; i++) {
-               hwif->drives[i].autotune = 1;
-               hwif->drives[i].autodma = hwif->autodma;
-       }
+       hwif->drives[1].autodma = hwif->drives[0].autodma = hwif->autodma;
 }
 
 static ide_pci_device_t cs5535_chipset __devinitdata = {
@@ -223,7 +219,7 @@ static ide_pci_device_t cs5535_chipset __devinitdata = {
        .init_hwif      = init_hwif_cs5535,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
-       .host_flags     = IDE_HFLAG_SINGLE,
+       .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE,
        .pio_mask       = ATA_PIO4,
 };
 
index a1bb10188fe54da2e84b190745b009083305aea7..218852aaf22aa11329dae8d320f3b6be1ba091c2 100644 (file)
@@ -43,7 +43,7 @@
 
 #define HPT343_DEBUG_DRIVE_INFO                0
 
-static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed)
 {
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
        u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
@@ -73,13 +73,11 @@ static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed)
                drive->dn, reg1, tmp1, reg2, tmp2,
                hi_speed, lo_speed);
 #endif /* HPT343_DEBUG_DRIVE_INFO */
-
-       return(ide_config_drive_speed(drive, speed));
 }
 
 static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
+       hpt34x_set_mode(drive, XFER_PIO_0 + pio);
 }
 
 static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
@@ -145,7 +143,8 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
        hwif->autodma = 0;
 
        hwif->set_pio_mode = &hpt34x_set_pio_mode;
-       hwif->speedproc = &hpt34x_tune_chipset;
+       hwif->set_dma_mode = &hpt34x_set_mode;
+
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
 
index 0e7d3b60d43c324353c8dd8d8e449739da6fad33..8812a9bb032ff6f77f45334b984b2a6d37f71f6a 100644 (file)
@@ -600,7 +600,7 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
        return (*info->settings)[i];
 }
 
-static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev  *dev    = hwif->pci_dev;
@@ -623,11 +623,9 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed)
        new_itr &= ~0xc0000000;
 
        pci_write_config_dword(dev, itr_addr, new_itr);
-
-       return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev  *dev    = hwif->pci_dev;
@@ -647,24 +645,22 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed)
        if (speed < XFER_MW_DMA_0)
                new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
        pci_write_config_dword(dev, itr_addr, new_itr);
-
-       return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
+static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct hpt_info *info   = pci_get_drvdata(hwif->pci_dev);
 
        if (info->chip_type >= HPT370)
-               return hpt37x_tune_chipset(drive, speed);
+               hpt37x_set_mode(drive, speed);
        else    /* hpt368: hpt_minimum_revision(dev, 2) */
-               return hpt36x_tune_chipset(drive, speed);
+               hpt36x_set_mode(drive, speed);
 }
 
 static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
+       hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
 static int hpt3xx_quirkproc(ide_drive_t *drive)
@@ -1257,7 +1253,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        hwif->select_data       = hwif->channel ? 0x54 : 0x50;
 
        hwif->set_pio_mode      = &hpt3xx_set_pio_mode;
-       hwif->speedproc         = &hpt3xx_tune_chipset;
+       hwif->set_dma_mode      = &hpt3xx_set_mode;
        hwif->quirkproc         = &hpt3xx_quirkproc;
        hwif->intrproc          = &hpt3xx_intrproc;
        hwif->maskproc          = &hpt3xx_maskproc;
index 76e91ff9420b87221b144c4042dbe85d34452da5..ecf4ce078dce601863cf0d6cf18ff51e08cf9d71 100644 (file)
@@ -48,15 +48,15 @@ static u8 it8213_dma_2_pio (u8 xfer_rate) {
        }
 }
 
-/*
- *     it8213_tune_pio -       tune a drive
- *     @drive: drive to tune
- *     @pio: desired PIO mode
+/**
+ *     it8213_set_pio_mode     -       set host controller for PIO mode
+ *     @drive: drive
+ *     @pio: PIO mode number
  *
  *     Set the interface PIO mode.
  */
 
-static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
+static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -105,21 +105,15 @@ static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
        spin_unlock_irqrestore(&tune_lock, flags);
 }
 
-static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       it8213_tune_pio(drive, pio);
-       ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
 /**
- *     it8213_tune_chipset     -       set controller timings
- *     @drive: Drive to set up
- *     @speed: speed we want to achieve
+ *     it8213_set_dma_mode     -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
- *     Tune the ITE chipset for the desired mode.
+ *     Tune the ITE chipset for the DMA mode.
  */
 
-static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -152,7 +146,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
                case XFER_SW_DMA_2:
                        break;
                default:
-                       return -1;
+                       return;
        }
 
        if (speed >= XFER_UDMA_0) {
@@ -182,9 +176,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
                        pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
        }
 
-       it8213_tune_pio(drive, it8213_dma_2_pio(speed));
-
-       return ide_config_drive_speed(drive, speed);
+       it8213_set_pio_mode(drive, it8213_dma_2_pio(speed));
 }
 
 /**
@@ -220,7 +212,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
 {
        u8 reg42h = 0;
 
-       hwif->speedproc = &it8213_tune_chipset;
+       hwif->set_dma_mode = &it8213_set_dma_mode;
        hwif->set_pio_mode = &it8213_set_pio_mode;
 
        hwif->autodma = 0;
index 758a98230cc5fcf8183499c4fa74d24f12bdc685..1b69d82478c6b4942e34a4fcbb30630837585a65 100644 (file)
@@ -229,24 +229,24 @@ static void it821x_clock_strategy(ide_drive_t *drive)
 }
 
 /**
- *     it821x_tunepio  -       tune a drive
- *     @drive: drive to tune
- *     @pio: the desired PIO mode
+ *     it821x_set_pio_mode     -       set host controller for PIO mode
+ *     @drive: drive
+ *     @pio: PIO mode number
  *
- *     Try to tune the drive/host to the desired PIO mode taking into
- *     the consideration the maximum PIO mode supported by the other
- *     device on the cable.
+ *     Tune the host to the desired PIO mode taking into the consideration
+ *     the maximum PIO mode supported by the other device on the cable.
  */
 
-static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
+static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = drive->hwif;
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
        int unit = drive->select.b.unit;
        ide_drive_t *pair = &hwif->drives[1 - unit];
+       u8 set_pio = pio;
 
        /* Spec says 89 ref driver uses 88 */
-       static u16 pio[]        = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+       static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
        static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
 
        /*
@@ -261,22 +261,12 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
                        set_pio = pair_pio;
        }
 
-       if (itdev->smart)
-               return 0;
-
        /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
        itdev->want[unit][1] = pio_want[set_pio];
        itdev->want[unit][0] = 1;       /* PIO is lowest priority */
-       itdev->pio[unit] = pio[set_pio];
+       itdev->pio[unit] = pio_timings[set_pio];
        it821x_clock_strategy(drive);
        it821x_program(drive, itdev->pio[unit]);
-
-       return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
-}
-
-static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       (void)it821x_tunepio(drive, pio);
 }
 
 /**
@@ -405,47 +395,24 @@ static int it821x_dma_end(ide_drive_t *drive)
 }
 
 /**
- *     it821x_tune_chipset     -       set controller timings
- *     @drive: Drive to set up
- *     @speed: speed we want to achieve
+ *     it821x_set_dma_mode     -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
- *     Tune the ITE chipset for the desired mode.
+ *     Tune the ITE chipset for the desired DMA mode.
  */
 
-static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
-
-       ide_hwif_t *hwif        = drive->hwif;
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-
-       if (itdev->smart == 0) {
-               switch (speed) {
-                       /* MWDMA tuning is really hard because our MWDMA and PIO
-                          timings are kept in the same place. We can switch in the
-                          host dma on/off callbacks */
-                       case XFER_MW_DMA_2:
-                       case XFER_MW_DMA_1:
-                       case XFER_MW_DMA_0:
-                               it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0));
-                               break;
-                       case XFER_UDMA_6:
-                       case XFER_UDMA_5:
-                       case XFER_UDMA_4:
-                       case XFER_UDMA_3:
-                       case XFER_UDMA_2:
-                       case XFER_UDMA_1:
-                       case XFER_UDMA_0:
-                               it821x_tune_udma(drive, (speed - XFER_UDMA_0));
-                               break;
-                       default:
-                               return 1;
-               }
-
-               return ide_config_drive_speed(drive, speed);
-       }
-
-       /* don't touch anything in the smart mode */
-       return 0;
+       /*
+        * MWDMA tuning is really hard because our MWDMA and PIO
+        * timings are kept in the same place.  We can switch in the
+        * host dma on/off callbacks.
+        */
+       if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6)
+               it821x_tune_udma(drive, speed - XFER_UDMA_0);
+       else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+               it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0);
 }
 
 /**
@@ -629,14 +596,15 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
                        printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n");
        }
 
-       hwif->speedproc = &it821x_tune_chipset;
-       hwif->set_pio_mode = &it821x_set_pio_mode;
+       if (idev->smart == 0) {
+               hwif->set_pio_mode = &it821x_set_pio_mode;
+               hwif->set_dma_mode = &it821x_set_dma_mode;
 
-       /* MWDMA/PIO clock switching for pass through mode */
-       if(!idev->smart) {
+               /* MWDMA/PIO clock switching for pass through mode */
                hwif->dma_start = &it821x_dma_start;
                hwif->ide_dma_end = &it821x_dma_end;
-       }
+       } else
+               hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
 
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
index d379fbaf67434535a7162a4ef5acbd8c97b66876..582b4cae2b5358ebb2b150e0b2a5ebefbd15df32 100644 (file)
@@ -85,21 +85,18 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
 
 static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 /**
- *     jmicron_tune_chipset    -       set controller timings
- *     @drive: Drive to set up
- *     @speed: speed we want to achieve
+ *     jmicron_set_dma_mode    -       set host controller for DMA mode
+ *     @drive: drive
+ *     @mode: DMA mode
  *
- *     As the JMicron snoops for timings all we actually need to do is
- *     set the transfer mode on the device.
+ *     As the JMicron snoops for timings we don't need to do anything here.
  */
 
-static int jmicron_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void jmicron_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
-       return ide_config_drive_speed(drive, speed);
 }
 
 /**
@@ -129,8 +126,8 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive)
 
 static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
 {
-       hwif->speedproc = &jmicron_tune_chipset;
        hwif->set_pio_mode = &jmicron_set_pio_mode;
+       hwif->set_dma_mode = &jmicron_set_dma_mode;
 
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
index 5fb1eedc819426773cc735e7571989926be69b22..ad0bdcb0c02b97371ee1f8ccb9419c5775976d02 100644 (file)
@@ -146,19 +146,16 @@ static struct udma_timing {
        { 0x1a, 0x01, 0xcb },   /* UDMA mode 6 */
 };
 
-static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        u8 adj                  = (drive->dn & 1) ? 0x08 : 0x00;
-       int                     err;
 
        /*
-        * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
+        * IDE core issues SETFEATURES_XFER to the drive first (thanks to
+        * IDE_HFLAG_POST_SET_MODE in ->host_flags).  PDC202xx hardware will
         * automatically set the timing registers based on 100 MHz PLL output.
-        */
-       err = ide_config_drive_speed(drive, speed);
-
-       /*
+        *
         * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
         * chips, we must override the default register settings...
         */
@@ -211,13 +208,11 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed)
 
                set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
        }
-
-       return err;
 }
 
 static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
+       pdcnew_set_mode(drive, XFER_PIO_0 + pio);
 }
 
 static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
@@ -490,9 +485,9 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        hwif->autodma = 0;
 
        hwif->set_pio_mode = &pdcnew_set_pio_mode;
+       hwif->set_dma_mode = &pdcnew_set_mode;
 
        hwif->quirkproc = &pdcnew_quirkproc;
-       hwif->speedproc = &pdcnew_tune_chipset;
        hwif->resetproc = &pdcnew_reset;
 
        hwif->err_stops_fifo = 1;
@@ -583,6 +578,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .bootable       = OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
+               .host_flags     = IDE_HFLAG_POST_SET_MODE,
        },{     /* 1 */
                .name           = "PDC20269",
                .init_setup     = init_setup_pdcnew,
@@ -592,6 +588,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .bootable       = OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
+               .host_flags     = IDE_HFLAG_POST_SET_MODE,
        },{     /* 2 */
                .name           = "PDC20270",
                .init_setup     = init_setup_pdc20270,
@@ -601,6 +598,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .bootable       = OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
+               .host_flags     = IDE_HFLAG_POST_SET_MODE,
        },{     /* 3 */
                .name           = "PDC20271",
                .init_setup     = init_setup_pdcnew,
@@ -610,6 +608,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .bootable       = OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
+               .host_flags     = IDE_HFLAG_POST_SET_MODE,
        },{     /* 4 */
                .name           = "PDC20275",
                .init_setup     = init_setup_pdcnew,
@@ -619,6 +618,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .bootable       = OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
+               .host_flags     = IDE_HFLAG_POST_SET_MODE,
        },{     /* 5 */
                .name           = "PDC20276",
                .init_setup     = init_setup_pdc20276,
@@ -628,6 +628,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .bootable       = OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
+               .host_flags     = IDE_HFLAG_POST_SET_MODE,
        },{     /* 6 */
                .name           = "PDC20277",
                .init_setup     = init_setup_pdcnew,
@@ -637,6 +638,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .bootable       = OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
+               .host_flags     = IDE_HFLAG_POST_SET_MODE,
        }
 };
 
index b578307fad51a3a1b1dd9320a14ccc35de015ee0..8c3e8cf36ec9da78e5dcbe7ba210ad9eb6a3fd37 100644 (file)
@@ -63,7 +63,7 @@ static const char *pdc_quirk_drives[] = {
 
 static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
 
-static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -138,13 +138,11 @@ static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed)
        pci_read_config_dword(dev, drive_pci, &drive_conf);
        printk("0x%08x\n", drive_conf);
 #endif
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
+       pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
 static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
@@ -330,14 +328,13 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
        hwif->autodma = 0;
 
        hwif->set_pio_mode = &pdc202xx_set_pio_mode;
+       hwif->set_dma_mode = &pdc202xx_set_mode;
 
        hwif->quirkproc = &pdc202xx_quirkproc;
 
        if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
                hwif->resetproc = &pdc202xx_reset;
 
-       hwif->speedproc = &pdc202xx_tune_chipset;
-
        hwif->err_stops_fifo = 1;
 
        hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
index fd8214a7ab9877e2a7d73045df361ffb30fe911e..38c91ba6497b30252796f4020b5af9293535438b 100644 (file)
@@ -137,13 +137,14 @@ static u8 piix_dma_2_pio (u8 xfer_rate) {
 }
 
 /**
- *     piix_tune_pio           -       tune PIIX for PIO mode
- *     @drive: drive to tune
- *     @pio: desired PIO mode
+ *     piix_set_pio_mode       -       set host controller for PIO mode
+ *     @drive: drive
+ *     @pio: PIO mode number
  *
  *     Set the interface PIO mode based upon the settings done by AMI BIOS.
  */
-static void piix_tune_pio (ide_drive_t *drive, u8 pio)
+
+static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -204,31 +205,15 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio)
 }
 
 /**
- *     piix_set_pio_mode       -       set PIO mode
- *     @drive: drive to tune
- *     @pio: desired PIO mode
- *
- *     Set the drive's PIO mode (might be useful if drive is not registered
- *     in CMOS for any reason).
- */
-
-static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       piix_tune_pio(drive, pio);
-       (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-/**
- *     piix_tune_chipset       -       tune a PIIX interface
- *     @drive: IDE drive to tune
- *     @speed: speed to configure
+ *     piix_set_dma_mode       -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
- *     Set a PIIX interface channel to the desired speeds. This involves
- *     requires the right timing data into the PIIX configuration space
- *     then setting the drive parameters appropriately
+ *     Set a PIIX host controller to the desired DMA mode.  This involves
+ *     programming the right timing data into the PCI configuration space.
  */
 
-static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -259,7 +244,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
                case XFER_MW_DMA_2:
                case XFER_MW_DMA_1:
                case XFER_SW_DMA_2:     break;
-               default:                return -1;
+               default:                return;
        }
 
        if (speed >= XFER_UDMA_0) {
@@ -288,9 +273,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
                        pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
        }
 
-       piix_tune_pio(drive, piix_dma_2_pio(speed));
-
-       return ide_config_drive_speed(drive, speed);
+       piix_set_pio_mode(drive, piix_dma_2_pio(speed));
 }
 
 /**
@@ -448,7 +431,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
        hwif->autodma = 0;
 
        hwif->set_pio_mode = &piix_set_pio_mode;
-       hwif->speedproc = &piix_tune_chipset;
+       hwif->set_dma_mode = &piix_set_dma_mode;
+
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
 
index 79ecab6894891de0480349cd3f98268ba3f2a24e..ee0e3f554d9abe2eb68cf58d22408d264eea5482 100644 (file)
@@ -68,17 +68,6 @@ static unsigned short sc1200_get_pci_clock (void)
        return pci_clock;
 }
 
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Set a new transfer mode at the drive
- */
-static int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
-       printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
-       return ide_config_drive_speed(drive, mode);
-}
-
 /*
  * Here are the standard PIO mode 0-4 timings for each "format".
  * Format-0 uses fast data reg timings, with slower command reg timings.
@@ -138,7 +127,7 @@ out:
        return mask;
 }
 
-static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
+static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
        ide_hwif_t              *hwif = HWIF(drive);
        int                     unit = drive->select.b.unit;
@@ -146,17 +135,9 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
        unsigned short          pci_clock;
        unsigned int            basereg = hwif->channel ? 0x50 : 0x40;
 
-       /*
-        * Tell the drive to switch to the new mode; abort on failure.
-        */
-       if (sc1200_set_xfer_mode(drive, mode))
-               return 1;       /* failure */
-
        pci_clock = sc1200_get_pci_clock();
 
        /*
-        * Now tune the chipset to match the drive:
-        *
         * Note that each DMA mode has several timings associated with it.
         * The correct timing depends on the fast PCI clock freq.
         */
@@ -216,8 +197,6 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
        } else {
                pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
        }
-
-       return 0;       /* success */
 }
 
 /*
@@ -286,13 +265,12 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
        if (mode != -1) {
                printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
                hwif->dma_off_quietly(drive);
-               if (sc1200_tune_chipset(drive, mode) == 0)
+               if (ide_set_dma_mode(drive, mode) == 0)
                        hwif->dma_host_on(drive);
                return;
        }
 
-       if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
-               sc1200_tunepio(drive, pio);
+       sc1200_tunepio(drive, pio);
 }
 
 #ifdef CONFIG_PM
@@ -400,16 +378,20 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
        if (hwif->mate)
                hwif->serialized = hwif->mate->serialized = 1;
        hwif->autodma = 0;
-       if (hwif->dma_base) {
-               hwif->udma_filter = sc1200_udma_filter;
-               hwif->ide_dma_check = &sc1200_config_dma;
-               hwif->ide_dma_end   = &sc1200_ide_dma_end;
-               if (!noautodma)
-                       hwif->autodma = 1;
-
-               hwif->set_pio_mode = &sc1200_set_pio_mode;
-               hwif->speedproc = &sc1200_tune_chipset;
-       }
+
+       hwif->set_pio_mode = &sc1200_set_pio_mode;
+       hwif->set_dma_mode = &sc1200_set_dma_mode;
+
+       if (hwif->dma_base == 0)
+               return;
+
+       hwif->udma_filter = sc1200_udma_filter;
+       hwif->ide_dma_check = &sc1200_config_dma;
+       hwif->ide_dma_end   = &sc1200_ide_dma_end;
+
+       if (!noautodma)
+               hwif->autodma = 1;
+
         hwif->atapi_dma = 1;
         hwif->ultra_mask = 0x07;
         hwif->mwdma_mask = 0x07;
@@ -423,7 +405,7 @@ static ide_pci_device_t sc1200_chipset __devinitdata = {
        .init_hwif      = init_hwif_sc1200,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
-       .host_flags     = IDE_HFLAG_ABUSE_DMA_MODES,
+       .host_flags     = IDE_HFLAG_ABUSE_DMA_MODES | IDE_HFLAG_POST_SET_MODE,
        .pio_mask       = ATA_PIO4,
 };
 
index 66a526e0ece4bd4e1fbd127bde869b5b7cfc76b5..67f06dd11b341c7a840b9b3e5b95d6563c3e4326 100644 (file)
@@ -190,15 +190,15 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count)
 }
 
 /**
- *     scc_tune_pio    -       tune a drive PIO mode
- *     @drive: drive to tune
- *     @mode_wanted: the target operating mode
+ *     scc_set_pio_mode        -       set host controller for PIO mode
+ *     @drive: drive
+ *     @pio: PIO mode number
  *
  *     Load the timing settings for this device mode into the
  *     controller.
  */
 
-static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
+static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = HWIF(drive);
        struct scc_ports *ports = ide_get_hwifdata(hwif);
@@ -221,22 +221,16 @@ static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
        out_be32((void __iomem *)pioct_port, reg);
 }
 
-static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       scc_tune_pio(drive, pio);
-       ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
 /**
- *     scc_tune_chipset        -       tune a drive DMA mode
- *     @drive: Drive to set up
- *     @speed: speed we want to achieve
+ *     scc_set_dma_mode        -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
  *     Load the timing settings for this device mode into the
  *     controller.
  */
 
-static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif = HWIF(drive);
        struct scc_ports *ports = ide_get_hwifdata(hwif);
@@ -271,7 +265,7 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
                idx = speed - XFER_UDMA_0;
                break;
        default:
-               return 1;
+               return;
        }
 
        jcactsel = JCACTSELtbl[offset][idx];
@@ -287,8 +281,6 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
        }
        reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
        out_be32((void __iomem *)udenvt_port, reg);
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 /**
@@ -708,8 +700,8 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
 
        hwif->dma_setup = scc_dma_setup;
        hwif->ide_dma_end = scc_ide_dma_end;
-       hwif->speedproc = scc_tune_chipset;
        hwif->set_pio_mode = scc_set_pio_mode;
+       hwif->set_dma_mode = scc_set_dma_mode;
        hwif->ide_dma_check = scc_config_drive_for_dma;
        hwif->ide_dma_test_irq = scc_dma_test_irq;
        hwif->udma_filter = scc_udma_filter;
index 0351cf2104271bbdecb2869d46a8451bdf18d554..49ec0ac64a4beb6ce0f3e4a94cf80383ef921cb1 100644 (file)
@@ -124,7 +124,7 @@ static u8 svwks_csb_check (struct pci_dev *dev)
        return 0;
 }
 
-static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
+static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
        static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
@@ -145,7 +145,7 @@ static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
        }
 }
 
-static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        static const u8 udma_modes[]            = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
        static const u8 dma_modes[]             = { 0x77, 0x21, 0x20 };
@@ -193,14 +193,6 @@ static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed)
        pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
        pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
        pci_write_config_byte(dev, 0x54, ultra_enable);
-
-       return (ide_config_drive_speed(drive, speed));
-}
-
-static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       svwks_tune_pio(drive, pio);
-       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
@@ -384,7 +376,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
                hwif->irq = hwif->channel ? 15 : 14;
 
        hwif->set_pio_mode = &svwks_set_pio_mode;
-       hwif->speedproc = &svwks_tune_chipset;
+       hwif->set_dma_mode = &svwks_set_dma_mode;
        hwif->udma_filter = &svwks_udma_filter;
 
        hwif->atapi_dma = 1;
index c292e1de1d56aba4bd574eb4ed03fb7cbc521733..85ffaaa39b1b87eecc84e1f87a4d8911fdfa2dfd 100644 (file)
@@ -291,12 +291,8 @@ static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
        drive->hwif->dma_host_off(drive);
 }
 
-static int sgiioc4_speedproc(ide_drive_t *drive, const u8 speed)
+static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
-       if (speed != XFER_MW_DMA_2)
-               return 1;
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 static int sgiioc4_ide_dma_check(ide_drive_t *drive)
@@ -591,11 +587,9 @@ static void __devinit
 ide_init_sgiioc4(ide_hwif_t * hwif)
 {
        hwif->mmio = 1;
-       hwif->atapi_dma = 1;
-       hwif->mwdma_mask = 0x04;
        hwif->pio_mask = 0x00;
        hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
-       hwif->speedproc = &sgiioc4_speedproc;
+       hwif->set_dma_mode = &sgiioc4_set_dma_mode;
        hwif->selectproc = NULL;/* Use the default routine to select drive */
        hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
        hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
@@ -606,6 +600,14 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->quirkproc = NULL;
        hwif->busproc = NULL;
 
+       hwif->INB = &sgiioc4_INB;
+
+       if (hwif->dma_base == 0)
+               return;
+
+       hwif->atapi_dma = 1;
+       hwif->mwdma_mask = 0x04;
+
        hwif->dma_setup = &sgiioc4_ide_dma_setup;
        hwif->dma_start = &sgiioc4_ide_dma_start;
        hwif->ide_dma_end = &sgiioc4_ide_dma_end;
@@ -617,8 +619,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->dma_host_off = &sgiioc4_dma_host_off;
        hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
        hwif->dma_timeout = &ide_dma_timeout;
-
-       hwif->INB = &sgiioc4_INB;
 }
 
 static int __devinit
@@ -688,8 +688,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        /* Initializing chipset IRQ Registers */
        writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
 
-       ide_init_sgiioc4(hwif);
-
        hwif->autodma = 0;
 
        if (dma_base && ide_dma_sgiioc4(hwif, dma_base) == 0) {
@@ -699,6 +697,8 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
                printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
                                 hwif->name, DRV_NAME);
 
+       ide_init_sgiioc4(hwif);
+
        if (probe_hwif_init(hwif))
                return -EIO;
 
index 5d1e5e52a0447a02ebd481639fdd541b9cbc7912..ce7784996d12c09c747ecc11af7f3789649a2cae 100644 (file)
@@ -165,16 +165,16 @@ out:
 }
 
 /**
- *     sil_tune_pio    -       tune a drive
- *     @drive: drive to tune
- *     @pio: the desired PIO mode
+ *     sil_set_pio_mode        -       set host controller for PIO mode
+ *     @drive: drive
+ *     @pio: PIO mode number
  *
  *     Load the timing settings for this device mode into the
  *     controller. If we are in PIO mode 3 or 4 turn on IORDY
  *     monitoring (bit 9). The TF timing is bits 31:16
  */
 
-static void sil_tune_pio(ide_drive_t *drive, u8 pio)
+static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
 {
        const u16 tf_speed[]    = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
        const u16 data_speed[]  = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
@@ -234,21 +234,15 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio)
        }
 }
 
-static void sil_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       sil_tune_pio(drive, pio);
-       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
 /**
- *     siimage_tune_chipset    -       set controller timings
- *     @drive: Drive to set up
- *     @speed: speed we want to achieve
+ *     sil_set_dma_mode        -       set host controller for DMA mode
+ *     @drive: drive
+ *     @speed: DMA mode
  *
- *     Tune the SII chipset for the desired mode.
+ *     Tune the SiI chipset for the desired DMA mode.
  */
 
-static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        u8 ultra6[]             = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
        u8 ultra5[]             = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
@@ -303,7 +297,7 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
                        mode |= ((unit) ? 0x30 : 0x03);
                        break;
                default:
-                       return 1;
+                       return;
        }
 
        if (hwif->mmio) {
@@ -315,7 +309,6 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
                pci_write_config_word(hwif->pci_dev, ma, multi);
                pci_write_config_word(hwif->pci_dev, ua, ultra);
        }
-       return (ide_config_drive_speed(drive, speed));
 }
 
 /**
@@ -904,8 +897,8 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
        hwif->autodma = 0;
        
        hwif->resetproc = &siimage_reset;
-       hwif->speedproc = &siimage_tune_chipset;
        hwif->set_pio_mode = &sil_set_pio_mode;
+       hwif->set_dma_mode = &sil_set_dma_mode;
        hwif->reset_poll = &siimage_reset_poll;
        hwif->pre_reset = &siimage_pre_reset;
        hwif->udma_filter = &sil_udma_filter;
index 3e18899de631450ac6c1dec6ae8158b7646f0df0..b375ee53d66d61997fd35bd4e49c395658b80bed 100644 (file)
@@ -451,7 +451,7 @@ static void config_drive_art_rwp (ide_drive_t *drive)
 }
 
 /* Set per-drive active and recovery time */
-static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -519,20 +519,14 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
        }
 }
 
-static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       config_art_rwp_pio(drive, pio);
-       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        u32 regdw;
        u8 drive_pci, reg;
 
-       /* See config_art_rwp_pio for drive pci config registers */
+       /* See sis_set_pio_mode() for drive PCI config registers */
        drive_pci = 0x40;
        if (chipset_family >= ATA_133) {
                u32 reg54h;
@@ -600,8 +594,6 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed)
                        BUG();
                        break;
        }
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 static int sis5513_config_xfer_rate(ide_drive_t *drive)
@@ -841,7 +833,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
                hwif->irq = hwif->channel ? 15 : 14;
 
        hwif->set_pio_mode = &sis_set_pio_mode;
-       hwif->speedproc = &sis5513_tune_chipset;
+       hwif->set_dma_mode = &sis_set_dma_mode;
 
        if (chipset_family >= ATA_133)
                hwif->udma_filter = sis5513_ata133_udma_filter;
index f492318ba79724b0b702c9bb4fd794cc66aaf5f5..2ef26e3f7be4752e1b6d2e8331abd53cb5feb6db 100644 (file)
@@ -75,7 +75,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
 /*
  * Configure the chipset for PIO mode.
  */
-static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio)
+static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
        int reg                 = 0x44 + drive->dn * 4;
@@ -105,9 +105,9 @@ static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio)
 }
 
 /*
- * Configure the drive and chipset for a new transfer speed.
+ * Configure the chipset for DMA mode.
  */
-static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
        u16 drv_ctrl;
@@ -140,10 +140,8 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed)
                }
                break;
        default:
-               return -1;
+               return;
        }
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 /*
@@ -306,17 +304,6 @@ static void sl82c105_resetproc(ide_drive_t *drive)
        pci_read_config_dword(dev, 0x40, &val);
        pci_set_drvdata(dev, (void *)val);
 }
-       
-/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
- */
-static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       sl82c105_tune_pio(drive, pio);
-
-       (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
 
 /*
  * Return the revision of the Winbond bridge
@@ -383,7 +370,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
        DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
 
        hwif->set_pio_mode      = &sl82c105_set_pio_mode;
-       hwif->speedproc         = &sl82c105_tune_chipset;
+       hwif->set_dma_mode      = &sl82c105_set_dma_mode;
        hwif->selectproc        = &sl82c105_selectproc;
        hwif->resetproc         = &sl82c105_resetproc;
 
index ae8e9132457773130336b02ac9110227bc595110..ebac87f7200a0d4af94199cc30bed6d95528217f 100644 (file)
@@ -42,7 +42,7 @@ static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
        }
 }
 
-static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
+static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -95,13 +95,7 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
        spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
-       slc90e66_tune_pio(drive, pio);
-       (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -125,7 +119,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
                case XFER_MW_DMA_2:
                case XFER_MW_DMA_1:
                case XFER_SW_DMA_2:     break;
-               default:                return -1;
+               default:                return;
        }
 
        if (speed >= XFER_UDMA_0) {
@@ -144,9 +138,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
                        pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
        }
 
-       slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed));
-
-       return ide_config_drive_speed(drive, speed);
+       slc90e66_set_pio_mode(drive, slc90e66_dma_2_pio(speed));
 }
 
 static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
@@ -172,8 +164,8 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
        if (!hwif->irq)
                hwif->irq = hwif->channel ? 15 : 14;
 
-       hwif->speedproc = &slc90e66_tune_chipset;
        hwif->set_pio_mode = &slc90e66_set_pio_mode;
+       hwif->set_dma_mode = &slc90e66_set_dma_mode;
 
        pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
 
index e23b9cfb6eb49816ad156f95ad0f5b4aaf78d983..840415d68d38e56482e24f5e9a61809d12db7a56 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/pci.h>
 #include <linux/ide.h>
 
-static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        unsigned long scr_port  = hwif->config_data + (drive->dn ? 0x02 : 0x00);
@@ -39,13 +39,11 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed)
        scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
        scr |= mode;
        outw(scr, scr_port);
-
-       return ide_config_drive_speed(drive, speed);
 }
 
 static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+       tc86c001_set_mode(drive, XFER_PIO_0 + pio);
 }
 
 /*
@@ -193,7 +191,8 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
        hwif->config_data = sc_base;
 
        hwif->set_pio_mode = &tc86c001_set_pio_mode;
-       hwif->speedproc = &tc86c001_tune_chipset;
+       hwif->set_dma_mode = &tc86c001_set_mode;
+
        hwif->busproc   = &tc86c001_busproc;
 
        hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
index c3ff066eea5a1a4290a6cd3708e1d399d9acc4f5..54e411d4e56cfe5d2c538c85946b1651828fb1d4 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/ide.h>
 #include <linux/init.h>
 
-static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif = HWIF(drive);
        struct pci_dev *dev = hwif->pci_dev;
@@ -82,20 +82,18 @@ static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed)
                        timing = 0x0808;
                        break;
                default:
-                       return -1;
+                       return;
        }
 
        triflex_timings &= ~(0xFFFF << (16 * unit));
        triflex_timings |= (timing << (16 * unit));
        
        pci_write_config_dword(dev, channel_offset, triflex_timings);
-       
-       return (ide_config_drive_speed(drive, speed));
 }
 
 static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       (void)triflex_tune_chipset(drive, XFER_PIO_0 + pio);
+       triflex_set_mode(drive, XFER_PIO_0 + pio);
 }
 
 static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
@@ -111,7 +109,7 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
 static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
 {
        hwif->set_pio_mode = &triflex_set_pio_mode;
-       hwif->speedproc = &triflex_tune_chipset;
+       hwif->set_dma_mode = &triflex_set_mode;
 
        if (hwif->dma_base == 0)
                return;
index 378feb491ec46a7c394d42d9f99a3ea752f98fcf..479e4966103290cb1e18c2438ca2fbd7b1e27c45 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * Version 3.48
+ * Version 3.49
  *
  * VIA IDE driver for Linux. Supported southbridges:
  *
@@ -153,21 +153,17 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
  *     @drive: Drive to set up
  *     @speed: desired speed
  *
- *     via_set_drive() computes timing values configures the drive and
- *     the chipset to a desired transfer mode. It also can be called
- *     by upper layers.
+ *     via_set_drive() computes timing values configures the chipset to
+ *     a desired transfer mode.  It also can be called by upper layers.
  */
 
-static int via_set_drive(ide_drive_t *drive, const u8 speed)
+static void via_set_drive(ide_drive_t *drive, const u8 speed)
 {
        ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
        struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
        struct ide_timing t, p;
        unsigned int T, UT;
 
-       if (speed != XFER_PIO_SLOW)
-               ide_config_drive_speed(drive, speed);
-
        T = 1000000000 / via_clock;
 
        switch (vdev->via_config->udma_mask) {
@@ -186,16 +182,10 @@ static int via_set_drive(ide_drive_t *drive, const u8 speed)
        }
 
        via_set_speed(HWIF(drive), drive->dn, &t);
-
-       if (!drive->init_speed)
-               drive->init_speed = speed;
-       drive->current_speed = speed;
-
-       return 0;
 }
 
 /**
- *     via_set_pio_mode        -       PIO setup
+ *     via_set_pio_mode        -       set host controller for PIO mode
  *     @drive: drive
  *     @pio: PIO mode number
  *
@@ -456,8 +446,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
        hwif->autodma = 0;
 
        hwif->set_pio_mode = &via_set_pio_mode;
-       hwif->speedproc = &via_set_drive;
-
+       hwif->set_dma_mode = &via_set_drive;
 
 #ifdef CONFIG_PPC_CHRP
        if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) {
@@ -500,7 +489,8 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
                .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
                .bootable       = ON_BOARD,
                .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST
-                               | IDE_HFLAG_PIO_NO_DOWNGRADE,
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE
+                               | IDE_HFLAG_POST_SET_MODE,
                .pio_mask       = ATA_PIO5,
        },{     /* 1 */
                .name           = "VP_IDE",
@@ -510,7 +500,8 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
                .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
                .bootable       = ON_BOARD,
                .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST
-                               | IDE_HFLAG_PIO_NO_DOWNGRADE,
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE
+                               | IDE_HFLAG_POST_SET_MODE,
                .pio_mask       = ATA_PIO5,
        }
 };
index f759a53978651b82c28f0cd257f865ee8f7febfe..7d8873839e2103d8af49c7dd0fe73260c23af88a 100644 (file)
@@ -392,6 +392,7 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
        for (i=0; table[i].cycle_time; i++)
                if (cycle_time > table[i+1].cycle_time)
                        return table[i].timing_reg;
+       BUG();
        return 0;
 }
 
@@ -528,98 +529,13 @@ pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
        tmp = readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
 }
 
-/*
- * Send the SET_FEATURE IDE command to the drive and update drive->id with
- * the new state. We currently don't use the generic routine as it used to
- * cause various trouble, especially with older mediabays.
- * This code is sometimes triggering a spurrious interrupt though, I need
- * to sort that out sooner or later and see if I can finally get the
- * common version to work properly in all cases
- */
-static int
-pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
-{
-       ide_hwif_t *hwif = HWIF(drive);
-       int result = 1;
-       
-       disable_irq_nosync(hwif->irq);
-       udelay(1);
-       SELECT_DRIVE(drive);
-       SELECT_MASK(drive, 0);
-       udelay(1);
-       /* Get rid of pending error state */
-       (void) hwif->INB(IDE_STATUS_REG);
-       /* Timeout bumped for some powerbooks */
-       if (wait_for_ready(drive, 2000)) {
-               /* Timeout bumped for some powerbooks */
-               printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
-                       "before SET_FEATURE!\n", drive->name);
-               goto out;
-       }
-       udelay(10);
-       hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
-       hwif->OUTB(command, IDE_NSECTOR_REG);
-       hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
-       hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
-       udelay(1);
-       /* Timeout bumped for some powerbooks */
-       result = wait_for_ready(drive, 2000);
-       hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-       if (result)
-               printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
-                       "after SET_FEATURE !\n", drive->name);
-out:
-       SELECT_MASK(drive, 0);
-       if (result == 0) {
-               drive->id->dma_ultra &= ~0xFF00;
-               drive->id->dma_mword &= ~0x0F00;
-               drive->id->dma_1word &= ~0x0F00;
-               switch(command) {
-                       case XFER_UDMA_7:
-                               drive->id->dma_ultra |= 0x8080; break;
-                       case XFER_UDMA_6:
-                               drive->id->dma_ultra |= 0x4040; break;
-                       case XFER_UDMA_5:
-                               drive->id->dma_ultra |= 0x2020; break;
-                       case XFER_UDMA_4:
-                               drive->id->dma_ultra |= 0x1010; break;
-                       case XFER_UDMA_3:
-                               drive->id->dma_ultra |= 0x0808; break;
-                       case XFER_UDMA_2:
-                               drive->id->dma_ultra |= 0x0404; break;
-                       case XFER_UDMA_1:
-                               drive->id->dma_ultra |= 0x0202; break;
-                       case XFER_UDMA_0:
-                               drive->id->dma_ultra |= 0x0101; break;
-                       case XFER_MW_DMA_2:
-                               drive->id->dma_mword |= 0x0404; break;
-                       case XFER_MW_DMA_1:
-                               drive->id->dma_mword |= 0x0202; break;
-                       case XFER_MW_DMA_0:
-                               drive->id->dma_mword |= 0x0101; break;
-                       case XFER_SW_DMA_2:
-                               drive->id->dma_1word |= 0x0404; break;
-                       case XFER_SW_DMA_1:
-                               drive->id->dma_1word |= 0x0202; break;
-                       case XFER_SW_DMA_0:
-                               drive->id->dma_1word |= 0x0101; break;
-                       default: break;
-               }
-               if (!drive->init_speed)
-                       drive->init_speed = command;
-               drive->current_speed = command;
-       }
-       enable_irq(hwif->irq);
-       return result;
-}
-
 /*
  * Old tuning functions (called on hdparm -p), sets up drive PIO timings
  */
 static void
 pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       u32 *timings;
+       u32 *timings, t;
        unsigned accessTicks, recTicks;
        unsigned accessTime, recTime;
        pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
@@ -630,6 +546,7 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
                
        /* which drive is it ? */
        timings = &pmif->timings[drive->select.b.unit & 0x01];
+       t = *timings;
 
        cycle_time = ide_pio_cycle_time(drive, pio);
 
@@ -637,18 +554,14 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
        case controller_sh_ata6: {
                /* 133Mhz cell */
                u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
-               if (tr == 0)
-                       return;
-               *timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
+               t = (t & ~TR_133_PIOREG_PIO_MASK) | tr;
                break;
                }
        case controller_un_ata6:
        case controller_k2_ata6: {
                /* 100Mhz cell */
                u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
-               if (tr == 0)
-                       return;
-               *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
+               t = (t & ~TR_100_PIOREG_PIO_MASK) | tr;
                break;
                }
        case controller_kl_ata4:
@@ -662,9 +575,9 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
                accessTicks = min(accessTicks, 0x1fU);
                recTicks = SYSCLK_TICKS_66(recTime);
                recTicks = min(recTicks, 0x1fU);
-               *timings = ((*timings) & ~TR_66_PIO_MASK) |
-                               (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
-                               (recTicks << TR_66_PIO_RECOVERY_SHIFT);
+               t = (t & ~TR_66_PIO_MASK) |
+                       (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+                       (recTicks << TR_66_PIO_RECOVERY_SHIFT);
                break;
        default: {
                /* 33Mhz cell */
@@ -684,11 +597,11 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
                        recTicks--; /* guess, but it's only for PIO0, so... */
                        ebit = 1;
                }
-               *timings = ((*timings) & ~TR_33_PIO_MASK) |
+               t = (t & ~TR_33_PIO_MASK) |
                                (accessTicks << TR_33_PIO_ACCESS_SHIFT) |
                                (recTicks << TR_33_PIO_RECOVERY_SHIFT);
                if (ebit)
-                       *timings |= TR_33_PIO_E;
+                       t |= TR_33_PIO_E;
                break;
                }
        }
@@ -698,9 +611,7 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
                drive->name, pio,  *timings);
 #endif 
 
-       if (pmac_ide_do_setfeature(drive, XFER_PIO_0 + pio))
-               return;
-
+       *timings = t;
        pmac_ide_do_update_timings(drive);
 }
 
@@ -746,8 +657,6 @@ set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
        if (speed > XFER_UDMA_5 || t == NULL)
                return 1;
        tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma);
-       if (tr == 0)
-               return 1;
        *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr;
        *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN;
 
@@ -766,8 +675,6 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
        if (speed > XFER_UDMA_6 || t == NULL)
                return 1;
        tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
-       if (tr == 0)
-               return 1;
        *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
        *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
 
@@ -777,12 +684,13 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
 /*
  * Calculate MDMA timings for all cells
  */
-static int
+static void
 set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
-                       u8 speed, int drive_cycle_time)
+                       u8 speed)
 {
        int cycleTime, accessTime = 0, recTime = 0;
        unsigned accessTicks, recTicks;
+       struct hd_driveid *id = drive->id;
        struct mdma_timings_t* tm = NULL;
        int i;
 
@@ -792,11 +700,14 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
                case 1: cycleTime = 150; break;
                case 2: cycleTime = 120; break;
                default:
-                       return 1;
+                       BUG();
+                       break;
        }
-       /* Adjust for drive */
-       if (drive_cycle_time && drive_cycle_time > cycleTime)
-               cycleTime = drive_cycle_time;
+
+       /* Check if drive provides explicit DMA cycle time */
+       if ((id->field_valid & 2) && id->eide_dma_time)
+               cycleTime = max_t(int, id->eide_dma_time, cycleTime);
+
        /* OHare limits according to some old Apple sources */  
        if ((intf_type == controller_ohare) && (cycleTime < 150))
                cycleTime = 150;
@@ -824,8 +735,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
                                break;
                        i++;
                }
-               if (i < 0)
-                       return 1;
                cycleTime = tm[i].cycleTime;
                accessTime = tm[i].accessTime;
                recTime = tm[i].recoveryTime;
@@ -839,8 +748,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
        case controller_sh_ata6: {
                /* 133Mhz cell */
                u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
-               if (tr == 0)
-                       return 1;
                *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
                *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
                }
@@ -848,8 +755,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
        case controller_k2_ata6: {
                /* 100Mhz cell */
                u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
-               if (tr == 0)
-                       return 1;
                *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr;
                *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN;
                }
@@ -911,30 +816,23 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
        printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n",
                drive->name, speed & 0xf,  *timings);
 #endif 
-       return 0;
 }
 #endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
 
-/* 
- * Speedproc. This function is called by the core to set any of the standard
- * DMA timing (MDMA or UDMA) to both the drive and the controller.
- * You may notice we don't use this function on normal "dma check" operation,
- * our dedicated function is more precise as it uses the drive provided
- * cycle time value. We should probably fix this one to deal with that too...
- */
-static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed)
+static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        int unit = (drive->select.b.unit & 0x01);
        int ret = 0;
        pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
-       u32 *timings, *timings2;
+       u32 *timings, *timings2, tl[2];
 
-       if (pmif == NULL)
-               return 1;
-               
        timings = &pmif->timings[unit];
        timings2 = &pmif->timings[unit+2];
-       
+
+       /* Copy timings to local image */
+       tl[0] = *timings;
+       tl[1] = *timings2;
+
        switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
                case XFER_UDMA_6:
@@ -945,38 +843,36 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed)
                case XFER_UDMA_1:
                case XFER_UDMA_0:
                        if (pmif->kind == controller_kl_ata4)
-                               ret = set_timings_udma_ata4(timings, speed);
+                               ret = set_timings_udma_ata4(&tl[0], speed);
                        else if (pmif->kind == controller_un_ata6
                                 || pmif->kind == controller_k2_ata6)
-                               ret = set_timings_udma_ata6(timings, timings2, speed);
+                               ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
                        else if (pmif->kind == controller_sh_ata6)
-                               ret = set_timings_udma_shasta(timings, timings2, speed);
+                               ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
                        else
-                               ret = 1;                
+                               ret = 1;
                        break;
                case XFER_MW_DMA_2:
                case XFER_MW_DMA_1:
                case XFER_MW_DMA_0:
-                       ret = set_timings_mdma(drive, pmif->kind, timings, timings2, speed, 0);
+                       set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
                        break;
                case XFER_SW_DMA_2:
                case XFER_SW_DMA_1:
                case XFER_SW_DMA_0:
-                       return 1;
+                       return;
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
                default:
                        ret = 1;
        }
        if (ret)
-               return ret;
+               return;
 
-       ret = pmac_ide_do_setfeature(drive, speed);
-       if (ret)
-               return ret;
-               
-       pmac_ide_do_update_timings(drive);      
+       /* Apply timings to controller */
+       *timings = tl[0];
+       *timings2 = tl[1];
 
-       return 0;
+       pmac_ide_do_update_timings(drive);      
 }
 
 /*
@@ -1236,6 +1132,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
        hwif->drives[0].unmask = 1;
        hwif->drives[1].unmask = 1;
+       hwif->drives[0].autotune = IDE_TUNE_AUTO;
+       hwif->drives[1].autotune = IDE_TUNE_AUTO;
+       hwif->host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
+                          IDE_HFLAG_POST_SET_MODE;
        hwif->pio_mask = ATA_PIO4;
        hwif->set_pio_mode = pmac_ide_set_pio_mode;
        if (pmif->kind == controller_un_ata6
@@ -1244,7 +1144,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
                hwif->selectproc = pmac_ide_kauai_selectproc;
        else
                hwif->selectproc = pmac_ide_selectproc;
-       hwif->speedproc = pmac_ide_tune_chipset;
+       hwif->set_dma_mode = pmac_ide_set_dma_mode;
 
        printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
               hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
@@ -1678,108 +1578,6 @@ pmac_ide_destroy_dmatable (ide_drive_t *drive)
        }
 }
 
-/*
- * Pick up best MDMA timing for the drive and apply it
- */
-static int
-pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode)
-{
-       ide_hwif_t *hwif = HWIF(drive);
-       pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
-       int drive_cycle_time;
-       struct hd_driveid *id = drive->id;
-       u32 *timings, *timings2;
-       u32 timing_local[2];
-       int ret;
-
-       /* which drive is it ? */
-       timings = &pmif->timings[drive->select.b.unit & 0x01];
-       timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
-
-       /* Check if drive provide explicit cycle time */
-       if ((id->field_valid & 2) && (id->eide_dma_time))
-               drive_cycle_time = id->eide_dma_time;
-       else
-               drive_cycle_time = 0;
-
-       /* Copy timings to local image */
-       timing_local[0] = *timings;
-       timing_local[1] = *timings2;
-
-       /* Calculate controller timings */
-       ret = set_timings_mdma( drive, pmif->kind,
-                               &timing_local[0],
-                               &timing_local[1],
-                               mode,
-                               drive_cycle_time);
-       if (ret)
-               return 0;
-
-       /* Set feature on drive */
-       printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf);
-       ret = pmac_ide_do_setfeature(drive, mode);
-       if (ret) {
-               printk(KERN_WARNING "%s: Failed !\n", drive->name);
-               return 0;
-       }
-
-       /* Apply timings to controller */
-       *timings = timing_local[0];
-       *timings2 = timing_local[1];
-
-       return 1;
-}
-
-/*
- * Pick up best UDMA timing for the drive and apply it
- */
-static int
-pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
-{
-       ide_hwif_t *hwif = HWIF(drive);
-       pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
-       u32 *timings, *timings2;
-       u32 timing_local[2];
-       int ret;
-               
-       /* which drive is it ? */
-       timings = &pmif->timings[drive->select.b.unit & 0x01];
-       timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
-
-       /* Copy timings to local image */
-       timing_local[0] = *timings;
-       timing_local[1] = *timings2;
-       
-       /* Calculate timings for interface */
-       if (pmif->kind == controller_un_ata6
-           || pmif->kind == controller_k2_ata6)
-               ret = set_timings_udma_ata6(    &timing_local[0],
-                                               &timing_local[1],
-                                               mode);
-       else if (pmif->kind == controller_sh_ata6)
-               ret = set_timings_udma_shasta(  &timing_local[0],
-                                               &timing_local[1],
-                                               mode);
-       else
-               ret = set_timings_udma_ata4(&timing_local[0], mode);
-       if (ret)
-               return 0;
-               
-       /* Set feature on drive */
-       printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f);
-       ret = pmac_ide_do_setfeature(drive, mode);
-       if (ret) {
-               printk(KERN_WARNING "%s: Failed !\n", drive->name);
-               return 0;
-       }
-
-       /* Apply timings to controller */
-       *timings = timing_local[0];
-       *timings2 = timing_local[1];
-
-       return 1;
-}
-
 /*
  * Check what is the best DMA timing setting for the drive and
  * call appropriate functions to apply it.
@@ -1787,30 +1585,10 @@ pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
 static int
 pmac_ide_dma_check(ide_drive_t *drive)
 {
-       struct hd_driveid *id = drive->id;
-       ide_hwif_t *hwif = HWIF(drive);
-       int enable = 1;
-       drive->using_dma = 0;
-       
-       if (drive->media == ide_floppy)
-               enable = 0;
-       if (((id->capability & 1) == 0) && !__ide_dma_good_drive(drive))
-               enable = 0;
-       if (__ide_dma_bad_drive(drive))
-               enable = 0;
-
-       if (enable) {
-               u8 mode = ide_max_dma_mode(drive);
-
-               if (mode >= XFER_UDMA_0)
-                       drive->using_dma = pmac_ide_udma_enable(drive, mode);
-               else if (mode >= XFER_MW_DMA_0)
-                       drive->using_dma = pmac_ide_mdma_enable(drive, mode);
-               hwif->OUTB(0, IDE_CONTROL_REG);
-               /* Apply settings to controller */
-               pmac_ide_do_update_timings(drive);
-       }
-       return 0;
+       if (ide_tune_dma(drive))
+               return 0;
+
+       return -1;
 }
 
 /*
@@ -2044,7 +1822,10 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
                        hwif->mwdma_mask = 0x07;
                        hwif->swdma_mask = 0x00;
                        break;
-       }       
+       }
+
+       hwif->autodma = 1;
+       hwif->drives[1].autodma = hwif->drives[0].autodma = hwif->autodma;
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
index 6545fa798b12664e96be153eaaec305249c2c9d8..1b3327ad6bc477332c622b069e55f9d8f7b7f542 100644 (file)
@@ -349,6 +349,7 @@ struct ipoib_neigh {
        struct sk_buff_head queue;
 
        struct neighbour   *neighbour;
+       struct net_device *dev;
 
        struct list_head    list;
 };
@@ -365,7 +366,8 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
                                     INFINIBAND_ALEN, sizeof(void *));
 }
 
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh);
+struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh,
+                                     struct net_device *dev);
 void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh);
 
 extern struct workqueue_struct *ipoib_workqueue;
index e072f3c32ce6f307aa3bdaf7935557b4bc5a53d0..362610d870e4328935f8be02f4ffaa0faae96ea6 100644 (file)
@@ -517,7 +517,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
        struct ipoib_path *path;
        struct ipoib_neigh *neigh;
 
-       neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+       neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
        if (!neigh) {
                ++dev->stats.tx_dropped;
                dev_kfree_skb_any(skb);
@@ -692,9 +692,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                goto out;
                        }
                } else if (neigh->ah) {
-                       if (unlikely(memcmp(&neigh->dgid.raw,
+                       if (unlikely((memcmp(&neigh->dgid.raw,
                                            skb->dst->neighbour->ha + 4,
-                                           sizeof(union ib_gid)))) {
+                                           sizeof(union ib_gid))) ||
+                                        (neigh->dev != dev))) {
                                spin_lock(&priv->lock);
                                /*
                                 * It's safe to call ipoib_put_ah() inside
@@ -817,6 +818,13 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
        unsigned long flags;
        struct ipoib_ah *ah = NULL;
 
+       neigh = *to_ipoib_neigh(n);
+       if (neigh) {
+               priv = netdev_priv(neigh->dev);
+               ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n",
+                         n->dev->name);
+       } else
+               return;
        ipoib_dbg(priv,
                  "neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
                  IPOIB_QPN(n->ha),
@@ -824,13 +832,10 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       neigh = *to_ipoib_neigh(n);
-       if (neigh) {
-               if (neigh->ah)
-                       ah = neigh->ah;
-               list_del(&neigh->list);
-               ipoib_neigh_free(n->dev, neigh);
-       }
+       if (neigh->ah)
+               ah = neigh->ah;
+       list_del(&neigh->list);
+       ipoib_neigh_free(n->dev, neigh);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -838,7 +843,8 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
                ipoib_put_ah(ah);
 }
 
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
+struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour,
+                                     struct net_device *dev)
 {
        struct ipoib_neigh *neigh;
 
@@ -847,6 +853,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
                return NULL;
 
        neigh->neighbour = neighbour;
+       neigh->dev = dev;
        *to_ipoib_neigh(neighbour) = neigh;
        skb_queue_head_init(&neigh->queue);
        ipoib_cm_set(neigh, NULL);
index 827820ec66d1f3db03cb3a23698ef0244176d9e2..9bcfc7ad6aa646af94cdc9ab97ea4d4175583821 100644 (file)
@@ -705,7 +705,8 @@ out:
                if (skb->dst            &&
                    skb->dst->neighbour &&
                    !*to_ipoib_neigh(skb->dst->neighbour)) {
-                       struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+                       struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
+                                                                       skb->dev);
 
                        if (neigh) {
                                kref_get(&mcast->ah->ref);
index 3432dce29520a6df599c7a9e7614027257236913..c74ee9633041d7a566dc1c2d9febf676c5bd744d 100644 (file)
@@ -1,6 +1,7 @@
 config INFINIBAND_SRP
        tristate "InfiniBand SCSI RDMA Protocol"
        depends on SCSI
+       select SCSI_SRP_ATTRS
        ---help---
          Support for the SCSI RDMA Protocol over InfiniBand.  This
          allows you to access storage devices that speak SRP over
index 9ccc63886d92904911a46a1630747478df12693d..950228fb009f29c1ccebd3f9453ee2c731a9a4c9 100644 (file)
@@ -47,6 +47,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_dbg.h>
 #include <scsi/srp.h>
+#include <scsi/scsi_transport_srp.h>
 
 #include <rdma/ib_cache.h>
 
@@ -86,6 +87,8 @@ static void srp_remove_one(struct ib_device *device);
 static void srp_completion(struct ib_cq *cq, void *target_ptr);
 static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
 
+static struct scsi_transport_template *ib_srp_transport_template;
+
 static struct ib_client srp_client = {
        .name   = "srp",
        .add    = srp_add_one,
@@ -420,6 +423,7 @@ static void srp_remove_work(struct work_struct *work)
        list_del(&target->list);
        spin_unlock(&target->srp_host->target_lock);
 
+       srp_remove_host(target->scsi_host);
        scsi_remove_host(target->scsi_host);
        ib_destroy_cm_id(target->cm_id);
        srp_free_target_ib(target);
@@ -1544,12 +1548,24 @@ static struct scsi_host_template srp_template = {
 
 static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
 {
+       struct srp_rport_identifiers ids;
+       struct srp_rport *rport;
+
        sprintf(target->target_name, "SRP.T10:%016llX",
                 (unsigned long long) be64_to_cpu(target->id_ext));
 
        if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device))
                return -ENODEV;
 
+       memcpy(ids.port_id, &target->id_ext, 8);
+       memcpy(ids.port_id + 8, &target->ioc_guid, 8);
+       ids.roles = SRP_RPORT_ROLE_TARGET;
+       rport = srp_rport_add(target->scsi_host, &ids);
+       if (IS_ERR(rport)) {
+               scsi_remove_host(target->scsi_host);
+               return PTR_ERR(rport);
+       }
+
        spin_lock(&host->target_lock);
        list_add_tail(&target->list, &host->target_list);
        spin_unlock(&host->target_lock);
@@ -1775,6 +1791,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
        if (!target_host)
                return -ENOMEM;
 
+       target_host->transportt = ib_srp_transport_template;
        target_host->max_lun     = SRP_MAX_LUN;
        target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
 
@@ -2054,10 +2071,18 @@ static void srp_remove_one(struct ib_device *device)
        kfree(srp_dev);
 }
 
+static struct srp_function_template ib_srp_transport_functions = {
+};
+
 static int __init srp_init_module(void)
 {
        int ret;
 
+       ib_srp_transport_template =
+               srp_attach_transport(&ib_srp_transport_functions);
+       if (!ib_srp_transport_template)
+               return -ENOMEM;
+
        srp_template.sg_tablesize = srp_sg_tablesize;
        srp_max_iu_len = (sizeof (struct srp_cmd) +
                          sizeof (struct srp_indirect_buf) +
@@ -2066,6 +2091,7 @@ static int __init srp_init_module(void)
        ret = class_register(&srp_class);
        if (ret) {
                printk(KERN_ERR PFX "couldn't register class infiniband_srp\n");
+               srp_release_transport(ib_srp_transport_template);
                return ret;
        }
 
@@ -2074,6 +2100,7 @@ static int __init srp_init_module(void)
        ret = ib_register_client(&srp_client);
        if (ret) {
                printk(KERN_ERR PFX "couldn't register IB client\n");
+               srp_release_transport(ib_srp_transport_template);
                ib_sa_unregister_client(&srp_sa_client);
                class_unregister(&srp_class);
                return ret;
@@ -2087,6 +2114,7 @@ static void __exit srp_cleanup_module(void)
        ib_unregister_client(&srp_client);
        ib_sa_unregister_client(&srp_sa_client);
        class_unregister(&srp_class);
+       srp_release_transport(ib_srp_transport_template);
 }
 
 module_init(srp_init_module);
index ded1d6ac6ff3eac662e64137271a2174731d9507..a1800151b6ce8dc045005138154b065055afe171 100644 (file)
@@ -55,7 +55,140 @@ MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
 MODULE_DESCRIPTION("Atari keyboard driver");
 MODULE_LICENSE("GPL");
 
-static unsigned char atakbd_keycode[0x72];
+/*
+ 0x47: KP_7     71
+ 0x48: KP_8     72
+ 0x49: KP_9     73
+ 0x62: KP_/     98
+ 0x4b: KP_4     75
+ 0x4c: KP_5     76
+ 0x4d: KP_6     77
+ 0x37: KP_*     55
+ 0x4f: KP_1     79
+ 0x50: KP_2     80
+ 0x51: KP_3     81
+ 0x4a: KP_-     74
+ 0x52: KP_0     82
+ 0x53: KP_.     83
+ 0x4e: KP_+     78
+
+ 0x67: Up       103
+ 0x6c: Down     108
+ 0x69: Left     105
+ 0x6a: Right    106
+ */
+
+
+static unsigned char atakbd_keycode[0x72] = {  /* American layout */
+       [0]      = KEY_GRAVE,
+       [1]      = KEY_ESC,
+       [2]      = KEY_1,
+       [3]      = KEY_2,
+       [4]      = KEY_3,
+       [5]      = KEY_4,
+       [6]      = KEY_5,
+       [7]      = KEY_6,
+       [8]      = KEY_7,
+       [9]      = KEY_8,
+       [10]     = KEY_9,
+       [11]     = KEY_0,
+       [12]     = KEY_MINUS,
+       [13]     = KEY_EQUAL,
+       [14]     = KEY_BACKSPACE,
+       [15]     = KEY_TAB,
+       [16]     = KEY_Q,
+       [17]     = KEY_W,
+       [18]     = KEY_E,
+       [19]     = KEY_R,
+       [20]     = KEY_T,
+       [21]     = KEY_Y,
+       [22]     = KEY_U,
+       [23]     = KEY_I,
+       [24]     = KEY_O,
+       [25]     = KEY_P,
+       [26]     = KEY_LEFTBRACE,
+       [27]     = KEY_RIGHTBRACE,
+       [28]     = KEY_ENTER,
+       [29]     = KEY_LEFTCTRL,
+       [30]     = KEY_A,
+       [31]     = KEY_S,
+       [32]     = KEY_D,
+       [33]     = KEY_F,
+       [34]     = KEY_G,
+       [35]     = KEY_H,
+       [36]     = KEY_J,
+       [37]     = KEY_K,
+       [38]     = KEY_L,
+       [39]     = KEY_SEMICOLON,
+       [40]     = KEY_APOSTROPHE,
+       [41]     = KEY_BACKSLASH,       /* FIXME, '#' */
+       [42]     = KEY_LEFTSHIFT,
+       [43]     = KEY_GRAVE,           /* FIXME: '~' */
+       [44]     = KEY_Z,
+       [45]     = KEY_X,
+       [46]     = KEY_C,
+       [47]     = KEY_V,
+       [48]     = KEY_B,
+       [49]     = KEY_N,
+       [50]     = KEY_M,
+       [51]     = KEY_COMMA,
+       [52]     = KEY_DOT,
+       [53]     = KEY_SLASH,
+       [54]     = KEY_RIGHTSHIFT,
+       [55]     = KEY_KPASTERISK,
+       [56]     = KEY_LEFTALT,
+       [57]     = KEY_SPACE,
+       [58]     = KEY_CAPSLOCK,
+       [59]     = KEY_F1,
+       [60]     = KEY_F2,
+       [61]     = KEY_F3,
+       [62]     = KEY_F4,
+       [63]     = KEY_F5,
+       [64]     = KEY_F6,
+       [65]     = KEY_F7,
+       [66]     = KEY_F8,
+       [67]     = KEY_F9,
+       [68]     = KEY_F10,
+       [69]     = KEY_ESC,
+       [70]     = KEY_DELETE,
+       [71]     = KEY_KP7,
+       [72]     = KEY_KP8,
+       [73]     = KEY_KP9,
+       [74]     = KEY_KPMINUS,
+       [75]     = KEY_KP4,
+       [76]     = KEY_KP5,
+       [77]     = KEY_KP6,
+       [78]     = KEY_KPPLUS,
+       [79]     = KEY_KP1,
+       [80]     = KEY_KP2,
+       [81]     = KEY_KP3,
+       [82]     = KEY_KP0,
+       [83]     = KEY_KPDOT,
+       [90]     = KEY_KPLEFTPAREN,
+       [91]     = KEY_KPRIGHTPAREN,
+       [92]     = KEY_KPASTERISK,      /* FIXME */
+       [93]     = KEY_KPASTERISK,
+       [94]     = KEY_KPPLUS,
+       [95]     = KEY_HELP,
+       [96]     = KEY_BACKSLASH,       /* FIXME: '<' */
+       [97]     = KEY_KPASTERISK,      /* FIXME */
+       [98]     = KEY_KPSLASH,
+       [99]     = KEY_KPLEFTPAREN,
+       [100]    = KEY_KPRIGHTPAREN,
+       [101]    = KEY_KPSLASH,
+       [102]    = KEY_KPASTERISK,
+       [103]    = KEY_UP,
+       [104]    = KEY_KPASTERISK,      /* FIXME */
+       [105]    = KEY_LEFT,
+       [106]    = KEY_RIGHT,
+       [107]    = KEY_KPASTERISK,      /* FIXME */
+       [108]    = KEY_DOWN,
+       [109]    = KEY_KPASTERISK,      /* FIXME */
+       [110]    = KEY_KPASTERISK,      /* FIXME */
+       [111]    = KEY_KPASTERISK,      /* FIXME */
+       [112]    = KEY_KPASTERISK,      /* FIXME */
+       [113]    = KEY_KPASTERISK       /* FIXME */
+};
 
 static struct input_dev *atakbd_dev;
 
@@ -84,23 +217,22 @@ static void atakbd_interrupt(unsigned char scancode, char down)
 
 static int __init atakbd_init(void)
 {
-       int i;
+       int i, error;
 
-       if (!ATARIHW_PRESENT(ST_MFP))
+       if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
                return -EIO;
 
-       // TODO: request_mem_region if not done in arch code
-
-       if (!(atakbd_dev = input_allocate_device()))
-               return -ENOMEM;
-
        // need to init core driver if not already done so
        if (atari_keyb_init())
                return -ENODEV;
 
+       atakbd_dev = input_allocate_device();
+       if (!atakbd_dev)
+               return -ENOMEM;
+
        atakbd_dev->name = "Atari Keyboard";
        atakbd_dev->phys = "atakbd/input0";
-       atakbd_dev->id.bustype = BUS_ATARI;
+       atakbd_dev->id.bustype = BUS_HOST;
        atakbd_dev->id.vendor = 0x0001;
        atakbd_dev->id.product = 0x0001;
        atakbd_dev->id.version = 0x0100;
@@ -111,16 +243,18 @@ static int __init atakbd_init(void)
        atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
 
        for (i = 1; i < 0x72; i++) {
-               atakbd_keycode[i] = i;
                set_bit(atakbd_keycode[i], atakbd_dev->keybit);
        }
 
-       input_register_device(atakbd_dev);
+       /* error check */
+       error = input_register_device(atakbd_dev);
+       if (error) {
+               input_free_device(atakbd_dev);
+               return error;
+       }
 
        atari_input_keyboard_interrupt_hook = atakbd_interrupt;
 
-       printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
-
        return 0;
 }
 
index 43ab6566fb65527a3f95e7191d814d5394eed43f..c8c7244b48a1bae505aab6b5e70f48657ad30dbb 100644 (file)
@@ -73,14 +73,11 @@ static void atamouse_interrupt(char *buf)
 {
        int buttons, dx, dy;
 
-/*     ikbd_mouse_disable(); */
-
        buttons = (buf[0] & 1) | ((buf[0] & 2) << 1);
 #ifdef FIXED_ATARI_JOYSTICK
        buttons |= atari_mouse_buttons & 2;
        atari_mouse_buttons = buttons;
 #endif
-/*     ikbd_mouse_rel_pos(); */
 
        /* only relative events get here */
        dx =  buf[1];
@@ -126,15 +123,16 @@ static int __init atamouse_init(void)
        if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
                return -ENODEV;
 
-       if (!(atamouse_dev = input_allocate_device()))
-               return -ENOMEM;
-
        if (!(atari_keyb_init()))
                return -ENODEV;
 
+       atamouse_dev = input_allocate_device();
+       if (!atamouse_dev)
+               return -ENOMEM;
+
        atamouse_dev->name = "Atari mouse";
        atamouse_dev->phys = "atamouse/input0";
-       atamouse_dev->id.bustype = BUS_ATARI;
+       atamouse_dev->id.bustype = BUS_HOST;
        atamouse_dev->id.vendor = 0x0001;
        atamouse_dev->id.product = 0x0002;
        atamouse_dev->id.version = 0x0100;
@@ -145,9 +143,11 @@ static int __init atamouse_init(void)
        atamouse_dev->open = atamouse_open;
        atamouse_dev->close = atamouse_close;
 
-       input_register_device(atamouse_dev);
+       if (input_register_device(atamouse_dev)) {
+               input_free_device(atamouse_dev);
+               return -ENOMEM;
+       }
 
-       printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name);
        return 0;
 }
 
index 96581d08774f8b55aa9bfc86e099de666b7be906..51ae4fb7d123b2882380f1ec78531949c70c59a9 100644 (file)
@@ -83,7 +83,7 @@ struct ads7846 {
 
 #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
        struct attribute_group  *attr_group;
-       struct class_device     *hwmon;
+       struct device           *hwmon;
 #endif
 
        u16                     model;
@@ -369,7 +369,7 @@ static struct attribute_group ads7845_attr_group = {
 
 static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
 {
-       struct class_device *hwmon;
+       struct device *hwmon;
        int err;
 
        /* hwmon sensors need a reference voltage */
index 0c1351b23840f8946e151cb45c0e829921ce4c93..948a9b290fd1146933a9d1cb38a9d6993db989a2 100644 (file)
@@ -1088,7 +1088,7 @@ setup_elsa_pci(struct IsdnCard *card)
 
 #else
 
-static void __devinit
+static int __devinit
 setup_elsa_pci(struct IsdnCard *card)
 {
        return (1);
index 8d9864453a234ee060d01a3957c4420ec47b261d..5c46a7130e064520def2c4f1160826bcf81c1147 100644 (file)
@@ -1019,7 +1019,8 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
 static unsigned int
 *init_send_hfcd(int cnt)
 {
-       int i, *send;
+       int i;
+       unsigned *send;
 
        if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
                printk(KERN_WARNING
index 60843b3f3b6f25b4c03ec2b4a8d1d4b63dca8199..98b0149bca68a4d36f93139dbd2db11dea52b6b6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * hfc_usb.c
  *
- * $Id: hfc_usb.c,v 2.3.2.20 2007/08/20 14:07:54 mbachem Exp $
+ * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $
  *
  * modular HiSax ISDN driver for Colognechip HFC-S USB chip
  *
@@ -45,7 +45,7 @@
 #include "hfc_usb.h"
 
 static const char *hfcusb_revision =
-    "$Revision: 2.3.2.20 $ $Date: 2007/08/20 14:07:54 $ ";
+    "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ ";
 
 /* Hisax debug support
 *  debug flags defined in hfc_usb.h as HFCUSB_DBG_[*]
@@ -126,6 +126,12 @@ static struct usb_device_id hfcusb_idtab[] = {
                          {LED_SCHEME1, {0x80, -64, -32, -16},
                           "Twister ISDN TA"}),
        },
+       {
+        USB_DEVICE(0x071d, 0x1005),
+        .driver_info = (unsigned long) &((hfcsusb_vdata)
+                         {LED_SCHEME1, {0x02, 0, 0x01, 0x04},
+                          "Eicon DIVA USB 4.0"}),
+       },
        { }
 };
 
@@ -187,7 +193,7 @@ typedef struct hfcusb_data {
        struct usb_ctrlrequest ctrl_write;      /* buffer for control write request */
        struct usb_ctrlrequest ctrl_read;       /* same for read request */
 
-       __u8 old_led_state, led_state, led_new_data, led_b_active;
+       __u8 old_led_state, led_state;
 
        volatile __u8 threshold_mask;   /* threshold actually reported */
        volatile __u8 bch_enables;      /* or mask for sctrl_r and sctrl register values */
@@ -263,7 +269,7 @@ ctrl_complete(struct urb *urb)
 
                ctrl_start_transfer(hfc);       /* start next transfer */
        }
-}                              /* ctrl_complete */
+}
 
 /* write led data to auxport & invert if necessary */
 static void
@@ -276,18 +282,18 @@ write_led(hfcusb_data * hfc, __u8 led_state)
 }
 
 static void
-set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
+set_led_bit(hfcusb_data * hfc, signed short led_bits, int on)
 {
-       if (unset) {
+       if (on) {
                if (led_bits < 0)
-                       hfc->led_state |= abs(led_bits);
+                       hfc->led_state &= ~abs(led_bits);
                else
-                       hfc->led_state &= ~led_bits;
+                       hfc->led_state |= led_bits;
        } else {
                if (led_bits < 0)
-                       hfc->led_state &= ~abs(led_bits);
+                       hfc->led_state |= abs(led_bits);
                else
-                       hfc->led_state |= led_bits;
+                       hfc->led_state &= ~led_bits;
        }
 }
 
@@ -304,34 +310,34 @@ handle_led(hfcusb_data * hfc, int event)
 
        switch (event) {
                case LED_POWER_ON:
-                       set_led_bit(hfc, driver_info->led_bits[0], 0);
-                       set_led_bit(hfc, driver_info->led_bits[1], 1);
-                       set_led_bit(hfc, driver_info->led_bits[2], 1);
-                       set_led_bit(hfc, driver_info->led_bits[3], 1);
+                       set_led_bit(hfc, driver_info->led_bits[0], 1);
+                       set_led_bit(hfc, driver_info->led_bits[1], 0);
+                       set_led_bit(hfc, driver_info->led_bits[2], 0);
+                       set_led_bit(hfc, driver_info->led_bits[3], 0);
                        break;
                case LED_POWER_OFF:
-                       set_led_bit(hfc, driver_info->led_bits[0], 1);
-                       set_led_bit(hfc, driver_info->led_bits[1], 1);
-                       set_led_bit(hfc, driver_info->led_bits[2], 1);
-                       set_led_bit(hfc, driver_info->led_bits[3], 1);
+                       set_led_bit(hfc, driver_info->led_bits[0], 0);
+                       set_led_bit(hfc, driver_info->led_bits[1], 0);
+                       set_led_bit(hfc, driver_info->led_bits[2], 0);
+                       set_led_bit(hfc, driver_info->led_bits[3], 0);
                        break;
                case LED_S0_ON:
-                       set_led_bit(hfc, driver_info->led_bits[1], 0);
+                       set_led_bit(hfc, driver_info->led_bits[1], 1);
                        break;
                case LED_S0_OFF:
-                       set_led_bit(hfc, driver_info->led_bits[1], 1);
+                       set_led_bit(hfc, driver_info->led_bits[1], 0);
                        break;
                case LED_B1_ON:
-                       set_led_bit(hfc, driver_info->led_bits[2], 0);
+                       set_led_bit(hfc, driver_info->led_bits[2], 1);
                        break;
                case LED_B1_OFF:
-                       set_led_bit(hfc, driver_info->led_bits[2], 1);
+                       set_led_bit(hfc, driver_info->led_bits[2], 0);
                        break;
                case LED_B2_ON:
-                       set_led_bit(hfc, driver_info->led_bits[3], 0);
+                       set_led_bit(hfc, driver_info->led_bits[3], 1);
                        break;
                case LED_B2_OFF:
-                       set_led_bit(hfc, driver_info->led_bits[3], 1);
+                       set_led_bit(hfc, driver_info->led_bits[3], 0);
                        break;
        }
        write_led(hfc, hfc->led_state);
@@ -1159,7 +1165,6 @@ hfc_usb_init(hfcusb_data * hfc)
        hfc->l1_activated = 0;
        hfc->disc_flag = 0;
        hfc->led_state = 0;
-       hfc->led_new_data = 0;
        hfc->old_led_state = 0;
 
        /* init the t3 timer */
@@ -1514,20 +1519,18 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 /* callback for unplugged USB device */
 static void
-hfc_usb_disconnect(struct usb_interface
-                  *intf)
+hfc_usb_disconnect(struct usb_interface *intf)
 {
        hfcusb_data *context = usb_get_intfdata(intf);
        int i;
 
        handle_led(context, LED_POWER_OFF);
-       schedule_timeout((10 * HZ) / 1000);
+       schedule_timeout(HZ / 100);
 
        printk(KERN_INFO "HFC-S USB: device disconnect\n");
        context->disc_flag = 1;
        usb_set_intfdata(intf, NULL);
-       if (!context)
-               return;
+
        if (timer_pending(&context->t3_timer))
                del_timer(&context->t3_timer);
        if (timer_pending(&context->t4_timer))
index 3cd8d5ba239beb8f3a355c6c7edf3e33f87f98d0..34733c903df796d3ea4d610ccb26f42ddb7cd359 100644 (file)
@@ -202,7 +202,7 @@ struct Layer1 {
        void *hardware;
        struct BCState *bcs;
        struct PStack **stlistp;
-       long Flags;
+       unsigned long Flags;
        struct FsmInst l1m;
        struct FsmTimer timer;
        void (*l1l2) (struct PStack *, int, void *);
index 4898fce2d5094d220f529950b1d9b98d8f30c8fb..aa7c94037b2b0eff7071302c37a9dd411f61b3e8 100644 (file)
@@ -56,7 +56,7 @@ struct hisax_d_if {
        struct IsdnCardState *cs;
        struct hisax_b_if *b_if[2];
        struct sk_buff_head erq;
-       long ph_state;
+       unsigned long ph_state;
 };
 
 int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
index fa2db87667c8367f3100d7e071b1a010895ff17e..a895dfed40e5fdcdc19d6e30e3fadcf4fb0d8dda 100644 (file)
@@ -151,7 +151,7 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 static int __devinit njs_pci_probe(struct pci_dev *dev_netjet,
                                   struct IsdnCardState *cs)
 {
-       int cfg;
+       u32 cfg;
 
        if (pci_enable_device(dev_netjet))
                return(0);
index 0a419a0de603a352cb2411cfacbb005f17590d9c..8749fa4ffcee955725e9f8992104c086522828a2 100644 (file)
@@ -17,6 +17,7 @@ if VIRTUALIZATION
 config KVM
        tristate "Kernel-based Virtual Machine (KVM) support"
        depends on X86 && EXPERIMENTAL
+       select PREEMPT_NOTIFIERS
        select ANON_INODES
        ---help---
          Support hosting fully virtualized guest machines using hardware
index c0a789fa9d65e65c9a4c452f04a87c3d96af864d..e5a8f4d3e97386f0ba73e629b8d2a13341fc5dd0 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for Kernel-based Virtual Machine module
 #
 
-kvm-objs := kvm_main.o mmu.o x86_emulate.o
+kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o
 obj-$(CONFIG_KVM) += kvm.o
 kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c
new file mode 100644 (file)
index 0000000..a679157
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * 8259 interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * Authors:
+ *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *   Port from Qemu.
+ */
+#include <linux/mm.h>
+#include "irq.h"
+
+/*
+ * set irq level. If an edge is detected, then the IRR is set to 1
+ */
+static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level)
+{
+       int mask;
+       mask = 1 << irq;
+       if (s->elcr & mask)     /* level triggered */
+               if (level) {
+                       s->irr |= mask;
+                       s->last_irr |= mask;
+               } else {
+                       s->irr &= ~mask;
+                       s->last_irr &= ~mask;
+               }
+       else    /* edge triggered */
+               if (level) {
+                       if ((s->last_irr & mask) == 0)
+                               s->irr |= mask;
+                       s->last_irr |= mask;
+               } else
+                       s->last_irr &= ~mask;
+}
+
+/*
+ * return the highest priority found in mask (highest = smallest
+ * number). Return 8 if no irq
+ */
+static inline int get_priority(struct kvm_kpic_state *s, int mask)
+{
+       int priority;
+       if (mask == 0)
+               return 8;
+       priority = 0;
+       while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
+               priority++;
+       return priority;
+}
+
+/*
+ * return the pic wanted interrupt. return -1 if none
+ */
+static int pic_get_irq(struct kvm_kpic_state *s)
+{
+       int mask, cur_priority, priority;
+
+       mask = s->irr & ~s->imr;
+       priority = get_priority(s, mask);
+       if (priority == 8)
+               return -1;
+       /*
+        * compute current priority. If special fully nested mode on the
+        * master, the IRQ coming from the slave is not taken into account
+        * for the priority computation.
+        */
+       mask = s->isr;
+       if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
+               mask &= ~(1 << 2);
+       cur_priority = get_priority(s, mask);
+       if (priority < cur_priority)
+               /*
+                * higher priority found: an irq should be generated
+                */
+               return (priority + s->priority_add) & 7;
+       else
+               return -1;
+}
+
+/*
+ * raise irq to CPU if necessary. must be called every time the active
+ * irq may change
+ */
+static void pic_update_irq(struct kvm_pic *s)
+{
+       int irq2, irq;
+
+       irq2 = pic_get_irq(&s->pics[1]);
+       if (irq2 >= 0) {
+               /*
+                * if irq request by slave pic, signal master PIC
+                */
+               pic_set_irq1(&s->pics[0], 2, 1);
+               pic_set_irq1(&s->pics[0], 2, 0);
+       }
+       irq = pic_get_irq(&s->pics[0]);
+       if (irq >= 0)
+               s->irq_request(s->irq_request_opaque, 1);
+       else
+               s->irq_request(s->irq_request_opaque, 0);
+}
+
+void kvm_pic_update_irq(struct kvm_pic *s)
+{
+       pic_update_irq(s);
+}
+
+void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+       struct kvm_pic *s = opaque;
+
+       pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+       pic_update_irq(s);
+}
+
+/*
+ * acknowledge interrupt 'irq'
+ */
+static inline void pic_intack(struct kvm_kpic_state *s, int irq)
+{
+       if (s->auto_eoi) {
+               if (s->rotate_on_auto_eoi)
+                       s->priority_add = (irq + 1) & 7;
+       } else
+               s->isr |= (1 << irq);
+       /*
+        * We don't clear a level sensitive interrupt here
+        */
+       if (!(s->elcr & (1 << irq)))
+               s->irr &= ~(1 << irq);
+}
+
+int kvm_pic_read_irq(struct kvm_pic *s)
+{
+       int irq, irq2, intno;
+
+       irq = pic_get_irq(&s->pics[0]);
+       if (irq >= 0) {
+               pic_intack(&s->pics[0], irq);
+               if (irq == 2) {
+                       irq2 = pic_get_irq(&s->pics[1]);
+                       if (irq2 >= 0)
+                               pic_intack(&s->pics[1], irq2);
+                       else
+                               /*
+                                * spurious IRQ on slave controller
+                                */
+                               irq2 = 7;
+                       intno = s->pics[1].irq_base + irq2;
+                       irq = irq2 + 8;
+               } else
+                       intno = s->pics[0].irq_base + irq;
+       } else {
+               /*
+                * spurious IRQ on host controller
+                */
+               irq = 7;
+               intno = s->pics[0].irq_base + irq;
+       }
+       pic_update_irq(s);
+
+       return intno;
+}
+
+static void pic_reset(void *opaque)
+{
+       struct kvm_kpic_state *s = opaque;
+
+       s->last_irr = 0;
+       s->irr = 0;
+       s->imr = 0;
+       s->isr = 0;
+       s->priority_add = 0;
+       s->irq_base = 0;
+       s->read_reg_select = 0;
+       s->poll = 0;
+       s->special_mask = 0;
+       s->init_state = 0;
+       s->auto_eoi = 0;
+       s->rotate_on_auto_eoi = 0;
+       s->special_fully_nested_mode = 0;
+       s->init4 = 0;
+}
+
+static void pic_ioport_write(void *opaque, u32 addr, u32 val)
+{
+       struct kvm_kpic_state *s = opaque;
+       int priority, cmd, irq;
+
+       addr &= 1;
+       if (addr == 0) {
+               if (val & 0x10) {
+                       pic_reset(s);   /* init */
+                       /*
+                        * deassert a pending interrupt
+                        */
+                       s->pics_state->irq_request(s->pics_state->
+                                                  irq_request_opaque, 0);
+                       s->init_state = 1;
+                       s->init4 = val & 1;
+                       if (val & 0x02)
+                               printk(KERN_ERR "single mode not supported");
+                       if (val & 0x08)
+                               printk(KERN_ERR
+                                      "level sensitive irq not supported");
+               } else if (val & 0x08) {
+                       if (val & 0x04)
+                               s->poll = 1;
+                       if (val & 0x02)
+                               s->read_reg_select = val & 1;
+                       if (val & 0x40)
+                               s->special_mask = (val >> 5) & 1;
+               } else {
+                       cmd = val >> 5;
+                       switch (cmd) {
+                       case 0:
+                       case 4:
+                               s->rotate_on_auto_eoi = cmd >> 2;
+                               break;
+                       case 1: /* end of interrupt */
+                       case 5:
+                               priority = get_priority(s, s->isr);
+                               if (priority != 8) {
+                                       irq = (priority + s->priority_add) & 7;
+                                       s->isr &= ~(1 << irq);
+                                       if (cmd == 5)
+                                               s->priority_add = (irq + 1) & 7;
+                                       pic_update_irq(s->pics_state);
+                               }
+                               break;
+                       case 3:
+                               irq = val & 7;
+                               s->isr &= ~(1 << irq);
+                               pic_update_irq(s->pics_state);
+                               break;
+                       case 6:
+                               s->priority_add = (val + 1) & 7;
+                               pic_update_irq(s->pics_state);
+                               break;
+                       case 7:
+                               irq = val & 7;
+                               s->isr &= ~(1 << irq);
+                               s->priority_add = (irq + 1) & 7;
+                               pic_update_irq(s->pics_state);
+                               break;
+                       default:
+                               break;  /* no operation */
+                       }
+               }
+       } else
+               switch (s->init_state) {
+               case 0:         /* normal mode */
+                       s->imr = val;
+                       pic_update_irq(s->pics_state);
+                       break;
+               case 1:
+                       s->irq_base = val & 0xf8;
+                       s->init_state = 2;
+                       break;
+               case 2:
+                       if (s->init4)
+                               s->init_state = 3;
+                       else
+                               s->init_state = 0;
+                       break;
+               case 3:
+                       s->special_fully_nested_mode = (val >> 4) & 1;
+                       s->auto_eoi = (val >> 1) & 1;
+                       s->init_state = 0;
+                       break;
+               }
+}
+
+static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1)
+{
+       int ret;
+
+       ret = pic_get_irq(s);
+       if (ret >= 0) {
+               if (addr1 >> 7) {
+                       s->pics_state->pics[0].isr &= ~(1 << 2);
+                       s->pics_state->pics[0].irr &= ~(1 << 2);
+               }
+               s->irr &= ~(1 << ret);
+               s->isr &= ~(1 << ret);
+               if (addr1 >> 7 || ret != 2)
+                       pic_update_irq(s->pics_state);
+       } else {
+               ret = 0x07;
+               pic_update_irq(s->pics_state);
+       }
+
+       return ret;
+}
+
+static u32 pic_ioport_read(void *opaque, u32 addr1)
+{
+       struct kvm_kpic_state *s = opaque;
+       unsigned int addr;
+       int ret;
+
+       addr = addr1;
+       addr &= 1;
+       if (s->poll) {
+               ret = pic_poll_read(s, addr1);
+               s->poll = 0;
+       } else
+               if (addr == 0)
+                       if (s->read_reg_select)
+                               ret = s->isr;
+                       else
+                               ret = s->irr;
+               else
+                       ret = s->imr;
+       return ret;
+}
+
+static void elcr_ioport_write(void *opaque, u32 addr, u32 val)
+{
+       struct kvm_kpic_state *s = opaque;
+       s->elcr = val & s->elcr_mask;
+}
+
+static u32 elcr_ioport_read(void *opaque, u32 addr1)
+{
+       struct kvm_kpic_state *s = opaque;
+       return s->elcr;
+}
+
+static int picdev_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+       switch (addr) {
+       case 0x20:
+       case 0x21:
+       case 0xa0:
+       case 0xa1:
+       case 0x4d0:
+       case 0x4d1:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static void picdev_write(struct kvm_io_device *this,
+                        gpa_t addr, int len, const void *val)
+{
+       struct kvm_pic *s = this->private;
+       unsigned char data = *(unsigned char *)val;
+
+       if (len != 1) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "PIC: non byte write\n");
+               return;
+       }
+       switch (addr) {
+       case 0x20:
+       case 0x21:
+       case 0xa0:
+       case 0xa1:
+               pic_ioport_write(&s->pics[addr >> 7], addr, data);
+               break;
+       case 0x4d0:
+       case 0x4d1:
+               elcr_ioport_write(&s->pics[addr & 1], addr, data);
+               break;
+       }
+}
+
+static void picdev_read(struct kvm_io_device *this,
+                       gpa_t addr, int len, void *val)
+{
+       struct kvm_pic *s = this->private;
+       unsigned char data = 0;
+
+       if (len != 1) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "PIC: non byte read\n");
+               return;
+       }
+       switch (addr) {
+       case 0x20:
+       case 0x21:
+       case 0xa0:
+       case 0xa1:
+               data = pic_ioport_read(&s->pics[addr >> 7], addr);
+               break;
+       case 0x4d0:
+       case 0x4d1:
+               data = elcr_ioport_read(&s->pics[addr & 1], addr);
+               break;
+       }
+       *(unsigned char *)val = data;
+}
+
+/*
+ * callback when PIC0 irq status changed
+ */
+static void pic_irq_request(void *opaque, int level)
+{
+       struct kvm *kvm = opaque;
+       struct kvm_vcpu *vcpu = kvm->vcpus[0];
+
+       pic_irqchip(kvm)->output = level;
+       if (vcpu)
+               kvm_vcpu_kick(vcpu);
+}
+
+struct kvm_pic *kvm_create_pic(struct kvm *kvm)
+{
+       struct kvm_pic *s;
+       s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
+       if (!s)
+               return NULL;
+       s->pics[0].elcr_mask = 0xf8;
+       s->pics[1].elcr_mask = 0xde;
+       s->irq_request = pic_irq_request;
+       s->irq_request_opaque = kvm;
+       s->pics[0].pics_state = s;
+       s->pics[1].pics_state = s;
+
+       /*
+        * Initialize PIO device
+        */
+       s->dev.read = picdev_read;
+       s->dev.write = picdev_write;
+       s->dev.in_range = picdev_in_range;
+       s->dev.private = s;
+       kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev);
+       return s;
+}
diff --git a/drivers/kvm/ioapic.c b/drivers/kvm/ioapic.c
new file mode 100644 (file)
index 0000000..c7992e6
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ *  Copyright (C) 2001  MandrakeSoft S.A.
+ *
+ *    MandrakeSoft S.A.
+ *    43, rue d'Aboukir
+ *    75002 Paris - France
+ *    http://www.linux-mandrake.com/
+ *    http://www.mandrakesoft.com/
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ *  Yunhong Jiang <yunhong.jiang@intel.com>
+ *  Yaozu (Eddie) Dong <eddie.dong@intel.com>
+ *  Based on Xen 3.1 code.
+ */
+
+#include "kvm.h"
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/apicdef.h>
+#include <asm/io_apic.h>
+#include "irq.h"
+/* #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
+#define ioapic_debug(fmt, arg...)
+static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
+
+static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
+                                         unsigned long addr,
+                                         unsigned long length)
+{
+       unsigned long result = 0;
+
+       switch (ioapic->ioregsel) {
+       case IOAPIC_REG_VERSION:
+               result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16)
+                         | (IOAPIC_VERSION_ID & 0xff));
+               break;
+
+       case IOAPIC_REG_APIC_ID:
+       case IOAPIC_REG_ARB_ID:
+               result = ((ioapic->id & 0xf) << 24);
+               break;
+
+       default:
+               {
+                       u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
+                       u64 redir_content;
+
+                       ASSERT(redir_index < IOAPIC_NUM_PINS);
+
+                       redir_content = ioapic->redirtbl[redir_index].bits;
+                       result = (ioapic->ioregsel & 0x1) ?
+                           (redir_content >> 32) & 0xffffffff :
+                           redir_content & 0xffffffff;
+                       break;
+               }
+       }
+
+       return result;
+}
+
+static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
+{
+       union ioapic_redir_entry *pent;
+
+       pent = &ioapic->redirtbl[idx];
+
+       if (!pent->fields.mask) {
+               ioapic_deliver(ioapic, idx);
+               if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
+                       pent->fields.remote_irr = 1;
+       }
+       if (!pent->fields.trig_mode)
+               ioapic->irr &= ~(1 << idx);
+}
+
+static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
+{
+       unsigned index;
+
+       switch (ioapic->ioregsel) {
+       case IOAPIC_REG_VERSION:
+               /* Writes are ignored. */
+               break;
+
+       case IOAPIC_REG_APIC_ID:
+               ioapic->id = (val >> 24) & 0xf;
+               break;
+
+       case IOAPIC_REG_ARB_ID:
+               break;
+
+       default:
+               index = (ioapic->ioregsel - 0x10) >> 1;
+
+               ioapic_debug("change redir index %x val %x", index, val);
+               if (index >= IOAPIC_NUM_PINS)
+                       return;
+               if (ioapic->ioregsel & 1) {
+                       ioapic->redirtbl[index].bits &= 0xffffffff;
+                       ioapic->redirtbl[index].bits |= (u64) val << 32;
+               } else {
+                       ioapic->redirtbl[index].bits &= ~0xffffffffULL;
+                       ioapic->redirtbl[index].bits |= (u32) val;
+                       ioapic->redirtbl[index].fields.remote_irr = 0;
+               }
+               if (ioapic->irr & (1 << index))
+                       ioapic_service(ioapic, index);
+               break;
+       }
+}
+
+static void ioapic_inj_irq(struct kvm_ioapic *ioapic,
+                          struct kvm_lapic *target,
+                          u8 vector, u8 trig_mode, u8 delivery_mode)
+{
+       ioapic_debug("irq %d trig %d deliv %d", vector, trig_mode,
+                    delivery_mode);
+
+       ASSERT((delivery_mode == dest_Fixed) ||
+              (delivery_mode == dest_LowestPrio));
+
+       kvm_apic_set_irq(target, vector, trig_mode);
+}
+
+static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
+                                      u8 dest_mode)
+{
+       u32 mask = 0;
+       int i;
+       struct kvm *kvm = ioapic->kvm;
+       struct kvm_vcpu *vcpu;
+
+       ioapic_debug("dest %d dest_mode %d", dest, dest_mode);
+
+       if (dest_mode == 0) {   /* Physical mode. */
+               if (dest == 0xFF) {     /* Broadcast. */
+                       for (i = 0; i < KVM_MAX_VCPUS; ++i)
+                               if (kvm->vcpus[i] && kvm->vcpus[i]->apic)
+                                       mask |= 1 << i;
+                       return mask;
+               }
+               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+                       vcpu = kvm->vcpus[i];
+                       if (!vcpu)
+                               continue;
+                       if (kvm_apic_match_physical_addr(vcpu->apic, dest)) {
+                               if (vcpu->apic)
+                                       mask = 1 << i;
+                               break;
+                       }
+               }
+       } else if (dest != 0)   /* Logical mode, MDA non-zero. */
+               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+                       vcpu = kvm->vcpus[i];
+                       if (!vcpu)
+                               continue;
+                       if (vcpu->apic &&
+                           kvm_apic_match_logical_addr(vcpu->apic, dest))
+                               mask |= 1 << vcpu->vcpu_id;
+               }
+       ioapic_debug("mask %x", mask);
+       return mask;
+}
+
+static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
+{
+       u8 dest = ioapic->redirtbl[irq].fields.dest_id;
+       u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
+       u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode;
+       u8 vector = ioapic->redirtbl[irq].fields.vector;
+       u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
+       u32 deliver_bitmask;
+       struct kvm_lapic *target;
+       struct kvm_vcpu *vcpu;
+       int vcpu_id;
+
+       ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
+                    "vector=%x trig_mode=%x",
+                    dest, dest_mode, delivery_mode, vector, trig_mode);
+
+       deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode);
+       if (!deliver_bitmask) {
+               ioapic_debug("no target on destination");
+               return;
+       }
+
+       switch (delivery_mode) {
+       case dest_LowestPrio:
+               target =
+                   kvm_apic_round_robin(ioapic->kvm, vector, deliver_bitmask);
+               if (target != NULL)
+                       ioapic_inj_irq(ioapic, target, vector,
+                                      trig_mode, delivery_mode);
+               else
+                       ioapic_debug("null round robin: "
+                                    "mask=%x vector=%x delivery_mode=%x",
+                                    deliver_bitmask, vector, dest_LowestPrio);
+               break;
+       case dest_Fixed:
+               for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
+                       if (!(deliver_bitmask & (1 << vcpu_id)))
+                               continue;
+                       deliver_bitmask &= ~(1 << vcpu_id);
+                       vcpu = ioapic->kvm->vcpus[vcpu_id];
+                       if (vcpu) {
+                               target = vcpu->apic;
+                               ioapic_inj_irq(ioapic, target, vector,
+                                              trig_mode, delivery_mode);
+                       }
+               }
+               break;
+
+               /* TODO: NMI */
+       default:
+               printk(KERN_WARNING "Unsupported delivery mode %d\n",
+                      delivery_mode);
+               break;
+       }
+}
+
+void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
+{
+       u32 old_irr = ioapic->irr;
+       u32 mask = 1 << irq;
+       union ioapic_redir_entry entry;
+
+       if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
+               entry = ioapic->redirtbl[irq];
+               level ^= entry.fields.polarity;
+               if (!level)
+                       ioapic->irr &= ~mask;
+               else {
+                       ioapic->irr |= mask;
+                       if ((!entry.fields.trig_mode && old_irr != ioapic->irr)
+                           || !entry.fields.remote_irr)
+                               ioapic_service(ioapic, irq);
+               }
+       }
+}
+
+static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector)
+{
+       int i;
+
+       for (i = 0; i < IOAPIC_NUM_PINS; i++)
+               if (ioapic->redirtbl[i].fields.vector == vector)
+                       return i;
+       return -1;
+}
+
+void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
+{
+       struct kvm_ioapic *ioapic = kvm->vioapic;
+       union ioapic_redir_entry *ent;
+       int gsi;
+
+       gsi = get_eoi_gsi(ioapic, vector);
+       if (gsi == -1) {
+               printk(KERN_WARNING "Can't find redir item for %d EOI\n",
+                      vector);
+               return;
+       }
+
+       ent = &ioapic->redirtbl[gsi];
+       ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
+
+       ent->fields.remote_irr = 0;
+       if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
+               ioapic_deliver(ioapic, gsi);
+}
+
+static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+       struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+
+       return ((addr >= ioapic->base_address &&
+                (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
+}
+
+static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
+                            void *val)
+{
+       struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+       u32 result;
+
+       ioapic_debug("addr %lx", (unsigned long)addr);
+       ASSERT(!(addr & 0xf));  /* check alignment */
+
+       addr &= 0xff;
+       switch (addr) {
+       case IOAPIC_REG_SELECT:
+               result = ioapic->ioregsel;
+               break;
+
+       case IOAPIC_REG_WINDOW:
+               result = ioapic_read_indirect(ioapic, addr, len);
+               break;
+
+       default:
+               result = 0;
+               break;
+       }
+       switch (len) {
+       case 8:
+               *(u64 *) val = result;
+               break;
+       case 1:
+       case 2:
+       case 4:
+               memcpy(val, (char *)&result, len);
+               break;
+       default:
+               printk(KERN_WARNING "ioapic: wrong length %d\n", len);
+       }
+}
+
+static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
+                             const void *val)
+{
+       struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+       u32 data;
+
+       ioapic_debug("ioapic_mmio_write addr=%lx len=%d val=%p\n",
+                    addr, len, val);
+       ASSERT(!(addr & 0xf));  /* check alignment */
+       if (len == 4 || len == 8)
+               data = *(u32 *) val;
+       else {
+               printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
+               return;
+       }
+
+       addr &= 0xff;
+       switch (addr) {
+       case IOAPIC_REG_SELECT:
+               ioapic->ioregsel = data;
+               break;
+
+       case IOAPIC_REG_WINDOW:
+               ioapic_write_indirect(ioapic, data);
+               break;
+
+       default:
+               break;
+       }
+}
+
+int kvm_ioapic_init(struct kvm *kvm)
+{
+       struct kvm_ioapic *ioapic;
+       int i;
+
+       ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
+       if (!ioapic)
+               return -ENOMEM;
+       kvm->vioapic = ioapic;
+       for (i = 0; i < IOAPIC_NUM_PINS; i++)
+               ioapic->redirtbl[i].fields.mask = 1;
+       ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
+       ioapic->dev.read = ioapic_mmio_read;
+       ioapic->dev.write = ioapic_mmio_write;
+       ioapic->dev.in_range = ioapic_in_range;
+       ioapic->dev.private = ioapic;
+       ioapic->kvm = kvm;
+       kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev);
+       return 0;
+}
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c
new file mode 100644 (file)
index 0000000..7628c7f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * irq.c: API for in kernel interrupt controller
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * Authors:
+ *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *
+ */
+
+#include <linux/module.h>
+
+#include "kvm.h"
+#include "irq.h"
+
+/*
+ * check if there is pending interrupt without
+ * intack.
+ */
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
+{
+       struct kvm_pic *s;
+
+       if (kvm_apic_has_interrupt(v) == -1) {  /* LAPIC */
+               if (kvm_apic_accept_pic_intr(v)) {
+                       s = pic_irqchip(v->kvm);        /* PIC */
+                       return s->output;
+               } else
+                       return 0;
+       }
+       return 1;
+}
+EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
+
+/*
+ * Read pending interrupt vector and intack.
+ */
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
+{
+       struct kvm_pic *s;
+       int vector;
+
+       vector = kvm_get_apic_interrupt(v);     /* APIC */
+       if (vector == -1) {
+               if (kvm_apic_accept_pic_intr(v)) {
+                       s = pic_irqchip(v->kvm);
+                       s->output = 0;          /* PIC */
+                       vector = kvm_pic_read_irq(s);
+               }
+       }
+       return vector;
+}
+EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
+
+static void vcpu_kick_intr(void *info)
+{
+#ifdef DEBUG
+       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
+       printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu);
+#endif
+}
+
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+{
+       int ipi_pcpu = vcpu->cpu;
+
+       if (waitqueue_active(&vcpu->wq)) {
+               wake_up_interruptible(&vcpu->wq);
+               ++vcpu->stat.halt_wakeup;
+       }
+       if (vcpu->guest_mode)
+               smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
+}
+
+void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
+{
+       kvm_inject_apic_timer_irqs(vcpu);
+       /* TODO: PIT, RTC etc. */
+}
+EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
+
+void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+       kvm_apic_timer_intr_post(vcpu, vec);
+       /* TODO: PIT, RTC etc. */
+}
+EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
new file mode 100644 (file)
index 0000000..11fc014
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * irq.h: in kernel interrupt controller related definitions
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * Authors:
+ *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include "kvm.h"
+
+typedef void irq_request_func(void *opaque, int level);
+
+struct kvm_kpic_state {
+       u8 last_irr;    /* edge detection */
+       u8 irr;         /* interrupt request register */
+       u8 imr;         /* interrupt mask register */
+       u8 isr;         /* interrupt service register */
+       u8 priority_add;        /* highest irq priority */
+       u8 irq_base;
+       u8 read_reg_select;
+       u8 poll;
+       u8 special_mask;
+       u8 init_state;
+       u8 auto_eoi;
+       u8 rotate_on_auto_eoi;
+       u8 special_fully_nested_mode;
+       u8 init4;               /* true if 4 byte init */
+       u8 elcr;                /* PIIX edge/trigger selection */
+       u8 elcr_mask;
+       struct kvm_pic *pics_state;
+};
+
+struct kvm_pic {
+       struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
+       irq_request_func *irq_request;
+       void *irq_request_opaque;
+       int output;             /* intr from master PIC */
+       struct kvm_io_device dev;
+};
+
+struct kvm_pic *kvm_create_pic(struct kvm *kvm);
+void kvm_pic_set_irq(void *opaque, int irq, int level);
+int kvm_pic_read_irq(struct kvm_pic *s);
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
+void kvm_pic_update_irq(struct kvm_pic *s);
+
+#define IOAPIC_NUM_PINS  KVM_IOAPIC_NUM_PINS
+#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */
+#define IOAPIC_EDGE_TRIG  0
+#define IOAPIC_LEVEL_TRIG 1
+
+#define IOAPIC_DEFAULT_BASE_ADDRESS  0xfec00000
+#define IOAPIC_MEM_LENGTH            0x100
+
+/* Direct registers. */
+#define IOAPIC_REG_SELECT  0x00
+#define IOAPIC_REG_WINDOW  0x10
+#define IOAPIC_REG_EOI     0x40        /* IA64 IOSAPIC only */
+
+/* Indirect registers. */
+#define IOAPIC_REG_APIC_ID 0x00        /* x86 IOAPIC only */
+#define IOAPIC_REG_VERSION 0x01
+#define IOAPIC_REG_ARB_ID  0x02        /* x86 IOAPIC only */
+
+struct kvm_ioapic {
+       u64 base_address;
+       u32 ioregsel;
+       u32 id;
+       u32 irr;
+       u32 pad;
+       union ioapic_redir_entry {
+               u64 bits;
+               struct {
+                       u8 vector;
+                       u8 delivery_mode:3;
+                       u8 dest_mode:1;
+                       u8 delivery_status:1;
+                       u8 polarity:1;
+                       u8 remote_irr:1;
+                       u8 trig_mode:1;
+                       u8 mask:1;
+                       u8 reserve:7;
+                       u8 reserved[4];
+                       u8 dest_id;
+               } fields;
+       } redirtbl[IOAPIC_NUM_PINS];
+       struct kvm_io_device dev;
+       struct kvm *kvm;
+};
+
+struct kvm_lapic {
+       unsigned long base_address;
+       struct kvm_io_device dev;
+       struct {
+               atomic_t pending;
+               s64 period;     /* unit: ns */
+               u32 divide_count;
+               ktime_t last_update;
+               struct hrtimer dev;
+       } timer;
+       struct kvm_vcpu *vcpu;
+       struct page *regs_page;
+       void *regs;
+};
+
+#ifdef DEBUG
+#define ASSERT(x)                                                      \
+do {                                                                   \
+       if (!(x)) {                                                     \
+               printk(KERN_EMERG "assertion failed %s: %d: %s\n",      \
+                      __FILE__, __LINE__, #x);                         \
+               BUG();                                                  \
+       }                                                               \
+} while (0)
+#else
+#define ASSERT(x) do { } while (0)
+#endif
+
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
+int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
+int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
+int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
+int kvm_create_lapic(struct kvm_vcpu *vcpu);
+void kvm_lapic_reset(struct kvm_vcpu *vcpu);
+void kvm_free_apic(struct kvm_lapic *apic);
+u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
+void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
+void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
+struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
+                                      unsigned long bitmap);
+u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
+void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
+void kvm_ioapic_update_eoi(struct kvm *kvm, int vector);
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
+int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig);
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
+int kvm_ioapic_init(struct kvm *kvm);
+void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
+int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
+void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
+void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
+void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
+
+#endif
index 336be86c6f5a9c023556a4b8703152213df094fb..3b0bc4bda5f2372122b7ee21b0837c4b771722d7 100644 (file)
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/preempt.h>
 #include <asm/signal.h>
 
-#include "vmx.h"
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
 
-#define CR0_PE_MASK (1ULL << 0)
-#define CR0_MP_MASK (1ULL << 1)
-#define CR0_TS_MASK (1ULL << 3)
-#define CR0_NE_MASK (1ULL << 5)
-#define CR0_WP_MASK (1ULL << 16)
-#define CR0_NW_MASK (1ULL << 29)
-#define CR0_CD_MASK (1ULL << 30)
-#define CR0_PG_MASK (1ULL << 31)
-
-#define CR3_WPT_MASK (1ULL << 3)
-#define CR3_PCD_MASK (1ULL << 4)
-
-#define CR3_RESEVED_BITS 0x07ULL
-#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL)
-#define CR3_FLAGS_MASK ((1ULL << 5) - 1)
-
-#define CR4_VME_MASK (1ULL << 0)
-#define CR4_PSE_MASK (1ULL << 4)
-#define CR4_PAE_MASK (1ULL << 5)
-#define CR4_PGE_MASK (1ULL << 7)
-#define CR4_VMXE_MASK (1ULL << 13)
+#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
+#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
+#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL)
 
 #define KVM_GUEST_CR0_MASK \
-       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
-        | CR0_NW_MASK | CR0_CD_MASK)
+       (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \
+        | X86_CR0_NW | X86_CR0_CD)
 #define KVM_VM_CR0_ALWAYS_ON \
-       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_MASK \
-        | CR0_MP_MASK)
+       (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \
+        | X86_CR0_MP)
 #define KVM_GUEST_CR4_MASK \
-       (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
-#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
-#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK)
+       (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE)
+#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
+#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE)
 
 #define INVALID_PAGE (~(hpa_t)0)
 #define UNMAPPED_GVA (~(gpa_t)0)
 
 #define KVM_MAX_VCPUS 4
 #define KVM_ALIAS_SLOTS 4
-#define KVM_MEMORY_SLOTS 4
+#define KVM_MEMORY_SLOTS 8
 #define KVM_NUM_MMU_PAGES 1024
 #define KVM_MIN_FREE_MMU_PAGES 5
 #define KVM_REFILL_PAGES 25
 #define KVM_MAX_CPUID_ENTRIES 40
 
-#define FX_IMAGE_SIZE 512
-#define FX_IMAGE_ALIGN 16
-#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
-
 #define DE_VECTOR 0
 #define NM_VECTOR 7
 #define DF_VECTOR 8
@@ -158,15 +136,8 @@ struct kvm_mmu_page {
        };
 };
 
-struct vmcs {
-       u32 revision_id;
-       u32 abort;
-       char data[0];
-};
-
-#define vmx_msr_entry kvm_msr_entry
-
 struct kvm_vcpu;
+extern struct kmem_cache *kvm_vcpu_cache;
 
 /*
  * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
@@ -260,6 +231,7 @@ struct kvm_stat {
        u32 signal_exits;
        u32 irq_window_exits;
        u32 halt_exits;
+       u32 halt_wakeup;
        u32 request_irq_exits;
        u32 irq_exits;
        u32 light_exits;
@@ -328,21 +300,17 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
 
 struct kvm_vcpu {
        struct kvm *kvm;
-       union {
-               struct vmcs *vmcs;
-               struct vcpu_svm *svm;
-       };
+       struct preempt_notifier preempt_notifier;
+       int vcpu_id;
        struct mutex mutex;
        int   cpu;
-       int   launched;
        u64 host_tsc;
        struct kvm_run *run;
        int interrupt_window_open;
        int guest_mode;
        unsigned long requests;
        unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
-#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
-       unsigned long irq_pending[NR_IRQ_WORDS];
+       DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS);
        unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
        unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
@@ -357,15 +325,15 @@ struct kvm_vcpu {
        u64 pdptrs[4]; /* pae */
        u64 shadow_efer;
        u64 apic_base;
+       struct kvm_lapic *apic;    /* kernel irqchip context */
+#define VCPU_MP_STATE_RUNNABLE          0
+#define VCPU_MP_STATE_UNINITIALIZED     1
+#define VCPU_MP_STATE_INIT_RECEIVED     2
+#define VCPU_MP_STATE_SIPI_RECEIVED     3
+#define VCPU_MP_STATE_HALTED            4
+       int mp_state;
+       int sipi_vector;
        u64 ia32_misc_enable_msr;
-       int nmsrs;
-       int save_nmsrs;
-       int msr_offset_efer;
-#ifdef CONFIG_X86_64
-       int msr_offset_kernel_gs_base;
-#endif
-       struct vmx_msr_entry *guest_msrs;
-       struct vmx_msr_entry *host_msrs;
 
        struct kvm_mmu mmu;
 
@@ -379,16 +347,10 @@ struct kvm_vcpu {
 
        struct kvm_guest_debug guest_debug;
 
-       char fx_buf[FX_BUF_SIZE];
-       char *host_fx_image;
-       char *guest_fx_image;
+       struct i387_fxsave_struct host_fx_image;
+       struct i387_fxsave_struct guest_fx_image;
        int fpu_active;
        int guest_fpu_loaded;
-       struct vmx_host_state {
-               int loaded;
-               u16 fs_sel, gs_sel, ldt_sel;
-               int fs_gs_ldt_reload_needed;
-       } vmx_host_state;
 
        int mmio_needed;
        int mmio_read_completed;
@@ -399,6 +361,7 @@ struct kvm_vcpu {
        gva_t mmio_fault_cr2;
        struct kvm_pio_request pio;
        void *pio_data;
+       wait_queue_head_t wq;
 
        int sigset_active;
        sigset_t sigset;
@@ -436,7 +399,7 @@ struct kvm_memory_slot {
 };
 
 struct kvm {
-       spinlock_t lock; /* protects everything except vcpus */
+       struct mutex lock; /* protects everything except vcpus */
        int naliases;
        struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
        int nmemslots;
@@ -447,39 +410,59 @@ struct kvm {
        struct list_head active_mmu_pages;
        int n_free_mmu_pages;
        struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
-       int nvcpus;
-       struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
-       int memory_config_version;
-       int busy;
+       struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
        unsigned long rmap_overflow;
        struct list_head vm_list;
        struct file *filp;
        struct kvm_io_bus mmio_bus;
        struct kvm_io_bus pio_bus;
+       struct kvm_pic *vpic;
+       struct kvm_ioapic *vioapic;
+       int round_robin_prev_vcpu;
 };
 
+static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
+{
+       return kvm->vpic;
+}
+
+static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
+{
+       return kvm->vioapic;
+}
+
+static inline int irqchip_in_kernel(struct kvm *kvm)
+{
+       return pic_irqchip(kvm) != 0;
+}
+
 struct descriptor_table {
        u16 limit;
        unsigned long base;
 } __attribute__((packed));
 
-struct kvm_arch_ops {
+struct kvm_x86_ops {
        int (*cpu_has_kvm_support)(void);          /* __init */
        int (*disabled_by_bios)(void);             /* __init */
        void (*hardware_enable)(void *dummy);      /* __init */
        void (*hardware_disable)(void *dummy);
+       void (*check_processor_compatibility)(void *rtn);
        int (*hardware_setup)(void);               /* __init */
        void (*hardware_unsetup)(void);            /* __exit */
 
-       int (*vcpu_create)(struct kvm_vcpu *vcpu);
+       /* Create, but do not attach this VCPU */
+       struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
        void (*vcpu_free)(struct kvm_vcpu *vcpu);
+       void (*vcpu_reset)(struct kvm_vcpu *vcpu);
 
-       void (*vcpu_load)(struct kvm_vcpu *vcpu);
+       void (*prepare_guest_switch)(struct kvm_vcpu *vcpu);
+       void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
        void (*vcpu_put)(struct kvm_vcpu *vcpu);
        void (*vcpu_decache)(struct kvm_vcpu *vcpu);
 
        int (*set_guest_debug)(struct kvm_vcpu *vcpu,
                               struct kvm_debug_guest *dbg);
+       void (*guest_debug_pre)(struct kvm_vcpu *vcpu);
        int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
        int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
        u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
@@ -505,27 +488,43 @@ struct kvm_arch_ops {
        unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
        void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
 
-       void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr);
        void (*tlb_flush)(struct kvm_vcpu *vcpu);
        void (*inject_page_fault)(struct kvm_vcpu *vcpu,
                                  unsigned long addr, u32 err_code);
 
        void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
 
-       int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
-       int (*vcpu_setup)(struct kvm_vcpu *vcpu);
+       void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+       int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
        void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
        void (*patch_hypercall)(struct kvm_vcpu *vcpu,
                                unsigned char *hypercall_addr);
+       int (*get_irq)(struct kvm_vcpu *vcpu);
+       void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
+       void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
+       void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
+                                      struct kvm_run *run);
 };
 
-extern struct kvm_arch_ops *kvm_arch_ops;
+extern struct kvm_x86_ops *kvm_x86_ops;
+
+/* The guest did something we don't support. */
+#define pr_unimpl(vcpu, fmt, ...)                                      \
+ do {                                                                  \
+       if (printk_ratelimit())                                         \
+               printk(KERN_ERR "kvm: %i: cpu%i " fmt,                  \
+                      current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \
+ } while(0)
 
 #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
 #define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
 
-int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
-void kvm_exit_arch(void);
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
+                 struct module *module);
+void kvm_exit_x86(void);
 
 int kvm_mmu_module_init(void);
 void kvm_mmu_module_exit(void);
@@ -545,8 +544,6 @@ static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
 hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
 struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
 
-void kvm_emulator_want_group7_invlpg(void);
-
 extern hpa_t bad_page_address;
 
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
@@ -561,6 +558,7 @@ enum emulation_result {
 
 int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
                        unsigned long cr2, u16 error_code);
+void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
 void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
 void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
@@ -574,9 +572,11 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 
 struct x86_emulate_ctxt;
 
-int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
-                 int size, unsigned long count, int string, int down,
-                 gva_t address, int rep, unsigned port);
+int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+                    int size, unsigned port);
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+                          int size, unsigned long count, int down,
+                           gva_t address, int rep, unsigned port);
 void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
 int kvm_emulate_halt(struct kvm_vcpu *vcpu);
 int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
@@ -590,34 +590,33 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
 void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
 void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
+unsigned long get_cr8(struct kvm_vcpu *vcpu);
 void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
 
 int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
 
 void fx_init(struct kvm_vcpu *vcpu);
 
-void load_msrs(struct vmx_msr_entry *e, int n);
-void save_msrs(struct vmx_msr_entry *e, int n);
 void kvm_resched(struct kvm_vcpu *vcpu);
 void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
 void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
 void kvm_flush_remote_tlbs(struct kvm *kvm);
 
-int kvm_read_guest(struct kvm_vcpu *vcpu,
-              gva_t addr,
-              unsigned long size,
-              void *dest);
-
-int kvm_write_guest(struct kvm_vcpu *vcpu,
-               gva_t addr,
-               unsigned long size,
-               void *data);
+int emulator_read_std(unsigned long addr,
+                      void *val,
+                     unsigned int bytes,
+                     struct kvm_vcpu *vcpu);
+int emulator_write_emulated(unsigned long addr,
+                           const void *val,
+                           unsigned int bytes,
+                           struct kvm_vcpu *vcpu);
 
 unsigned long segment_base(u16 selector);
 
 void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
-                      const u8 *old, const u8 *new, int bytes);
+                      const u8 *new, int bytes);
 int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
 void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
 int kvm_mmu_load(struct kvm_vcpu *vcpu);
@@ -625,6 +624,16 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu);
 
 int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
 
+static inline void kvm_guest_enter(void)
+{
+       current->flags |= PF_VCPU;
+}
+
+static inline void kvm_guest_exit(void)
+{
+       current->flags &= ~PF_VCPU;
+}
+
 static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
                                     u32 error_code)
 {
@@ -656,17 +665,17 @@ static inline int is_long_mode(struct kvm_vcpu *vcpu)
 
 static inline int is_pae(struct kvm_vcpu *vcpu)
 {
-       return vcpu->cr4 & CR4_PAE_MASK;
+       return vcpu->cr4 & X86_CR4_PAE;
 }
 
 static inline int is_pse(struct kvm_vcpu *vcpu)
 {
-       return vcpu->cr4 & CR4_PSE_MASK;
+       return vcpu->cr4 & X86_CR4_PSE;
 }
 
 static inline int is_paging(struct kvm_vcpu *vcpu)
 {
-       return vcpu->cr0 & CR0_PG_MASK;
+       return vcpu->cr0 & X86_CR0_PG;
 }
 
 static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
@@ -746,12 +755,12 @@ static inline unsigned long read_msr(unsigned long msr)
 }
 #endif
 
-static inline void fx_save(void *image)
+static inline void fx_save(struct i387_fxsave_struct *image)
 {
        asm ("fxsave (%0)":: "r" (image));
 }
 
-static inline void fx_restore(void *image)
+static inline void fx_restore(struct i387_fxsave_struct *image)
 {
        asm ("fxrstor (%0)":: "r" (image));
 }
index cd0557954e50ef3614c03c334b38f06104ca0551..af2d288c881d32500a5f753cb6453432ce3b6c15 100644 (file)
@@ -18,6 +18,7 @@
 #include "kvm.h"
 #include "x86_emulate.h"
 #include "segment_descriptor.h"
+#include "irq.h"
 
 #include <linux/kvm.h>
 #include <linux/module.h>
@@ -37,6 +38,7 @@
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/anon_inodes.h>
+#include <linux/profile.h>
 
 #include <asm/processor.h>
 #include <asm/msr.h>
@@ -52,9 +54,11 @@ static LIST_HEAD(vm_list);
 
 static cpumask_t cpus_hardware_enabled;
 
-struct kvm_arch_ops *kvm_arch_ops;
+struct kvm_x86_ops *kvm_x86_ops;
+struct kmem_cache *kvm_vcpu_cache;
+EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
 
-static void hardware_disable(void *ignored);
+static __read_mostly struct preempt_ops kvm_preempt_ops;
 
 #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
 
@@ -73,6 +77,7 @@ static struct kvm_stats_debugfs_item {
        { "signal_exits", STAT_OFFSET(signal_exits) },
        { "irq_window", STAT_OFFSET(irq_window_exits) },
        { "halt_exits", STAT_OFFSET(halt_exits) },
+       { "halt_wakeup", STAT_OFFSET(halt_wakeup) },
        { "request_irq", STAT_OFFSET(request_irq_exits) },
        { "irq_exits", STAT_OFFSET(irq_exits) },
        { "light_exits", STAT_OFFSET(light_exits) },
@@ -84,10 +89,17 @@ static struct dentry *debugfs_dir;
 
 #define MAX_IO_MSRS 256
 
-#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
-#define LMSW_GUEST_MASK 0x0eULL
-#define CR4_RESEVED_BITS (~((1ULL << 11) - 1))
-#define CR8_RESEVED_BITS (~0x0fULL)
+#define CR0_RESERVED_BITS                                              \
+       (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
+                         | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
+                         | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
+#define CR4_RESERVED_BITS                                              \
+       (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
+                         | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE     \
+                         | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR  \
+                         | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
+
+#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
 #define EFER_RESERVED_BITS 0xfffffffffffff2fe
 
 #ifdef CONFIG_X86_64
@@ -139,82 +151,14 @@ static inline int valid_vcpu(int n)
        return likely(n >= 0 && n < KVM_MAX_VCPUS);
 }
 
-int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
-                  void *dest)
-{
-       unsigned char *host_buf = dest;
-       unsigned long req_size = size;
-
-       while (size) {
-               hpa_t paddr;
-               unsigned now;
-               unsigned offset;
-               hva_t guest_buf;
-
-               paddr = gva_to_hpa(vcpu, addr);
-
-               if (is_error_hpa(paddr))
-                       break;
-
-               guest_buf = (hva_t)kmap_atomic(
-                                       pfn_to_page(paddr >> PAGE_SHIFT),
-                                       KM_USER0);
-               offset = addr & ~PAGE_MASK;
-               guest_buf |= offset;
-               now = min(size, PAGE_SIZE - offset);
-               memcpy(host_buf, (void*)guest_buf, now);
-               host_buf += now;
-               addr += now;
-               size -= now;
-               kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
-       }
-       return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_read_guest);
-
-int kvm_write_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
-                   void *data)
-{
-       unsigned char *host_buf = data;
-       unsigned long req_size = size;
-
-       while (size) {
-               hpa_t paddr;
-               unsigned now;
-               unsigned offset;
-               hva_t guest_buf;
-               gfn_t gfn;
-
-               paddr = gva_to_hpa(vcpu, addr);
-
-               if (is_error_hpa(paddr))
-                       break;
-
-               gfn = vcpu->mmu.gva_to_gpa(vcpu, addr) >> PAGE_SHIFT;
-               mark_page_dirty(vcpu->kvm, gfn);
-               guest_buf = (hva_t)kmap_atomic(
-                               pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0);
-               offset = addr & ~PAGE_MASK;
-               guest_buf |= offset;
-               now = min(size, PAGE_SIZE - offset);
-               memcpy((void*)guest_buf, host_buf, now);
-               host_buf += now;
-               addr += now;
-               size -= now;
-               kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
-       }
-       return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_write_guest);
-
 void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
 {
        if (!vcpu->fpu_active || vcpu->guest_fpu_loaded)
                return;
 
        vcpu->guest_fpu_loaded = 1;
-       fx_save(vcpu->host_fx_image);
-       fx_restore(vcpu->guest_fx_image);
+       fx_save(&vcpu->host_fx_image);
+       fx_restore(&vcpu->guest_fx_image);
 }
 EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);
 
@@ -224,8 +168,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
                return;
 
        vcpu->guest_fpu_loaded = 0;
-       fx_save(vcpu->guest_fx_image);
-       fx_restore(vcpu->host_fx_image);
+       fx_save(&vcpu->guest_fx_image);
+       fx_restore(&vcpu->host_fx_image);
 }
 EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
 
@@ -234,13 +178,21 @@ EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
  */
 static void vcpu_load(struct kvm_vcpu *vcpu)
 {
+       int cpu;
+
        mutex_lock(&vcpu->mutex);
-       kvm_arch_ops->vcpu_load(vcpu);
+       cpu = get_cpu();
+       preempt_notifier_register(&vcpu->preempt_notifier);
+       kvm_x86_ops->vcpu_load(vcpu, cpu);
+       put_cpu();
 }
 
 static void vcpu_put(struct kvm_vcpu *vcpu)
 {
-       kvm_arch_ops->vcpu_put(vcpu);
+       preempt_disable();
+       kvm_x86_ops->vcpu_put(vcpu);
+       preempt_notifier_unregister(&vcpu->preempt_notifier);
+       preempt_enable();
        mutex_unlock(&vcpu->mutex);
 }
 
@@ -261,8 +213,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
        atomic_set(&completed, 0);
        cpus_clear(cpus);
        needed = 0;
-       for (i = 0; i < kvm->nvcpus; ++i) {
-               vcpu = &kvm->vcpus[i];
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               vcpu = kvm->vcpus[i];
+               if (!vcpu)
+                       continue;
                if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
                        continue;
                cpu = vcpu->cpu;
@@ -286,37 +240,79 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
        }
 }
 
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
+{
+       struct page *page;
+       int r;
+
+       mutex_init(&vcpu->mutex);
+       vcpu->cpu = -1;
+       vcpu->mmu.root_hpa = INVALID_PAGE;
+       vcpu->kvm = kvm;
+       vcpu->vcpu_id = id;
+       if (!irqchip_in_kernel(kvm) || id == 0)
+               vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+       else
+               vcpu->mp_state = VCPU_MP_STATE_UNINITIALIZED;
+       init_waitqueue_head(&vcpu->wq);
+
+       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!page) {
+               r = -ENOMEM;
+               goto fail;
+       }
+       vcpu->run = page_address(page);
+
+       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!page) {
+               r = -ENOMEM;
+               goto fail_free_run;
+       }
+       vcpu->pio_data = page_address(page);
+
+       r = kvm_mmu_create(vcpu);
+       if (r < 0)
+               goto fail_free_pio_data;
+
+       return 0;
+
+fail_free_pio_data:
+       free_page((unsigned long)vcpu->pio_data);
+fail_free_run:
+       free_page((unsigned long)vcpu->run);
+fail:
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_init);
+
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+       kvm_mmu_destroy(vcpu);
+       if (vcpu->apic)
+               hrtimer_cancel(&vcpu->apic->timer.dev);
+       kvm_free_apic(vcpu->apic);
+       free_page((unsigned long)vcpu->pio_data);
+       free_page((unsigned long)vcpu->run);
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
+
 static struct kvm *kvm_create_vm(void)
 {
        struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
-       int i;
 
        if (!kvm)
                return ERR_PTR(-ENOMEM);
 
        kvm_io_bus_init(&kvm->pio_bus);
-       spin_lock_init(&kvm->lock);
+       mutex_init(&kvm->lock);
        INIT_LIST_HEAD(&kvm->active_mmu_pages);
        kvm_io_bus_init(&kvm->mmio_bus);
-       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-               struct kvm_vcpu *vcpu = &kvm->vcpus[i];
-
-               mutex_init(&vcpu->mutex);
-               vcpu->cpu = -1;
-               vcpu->kvm = kvm;
-               vcpu->mmu.root_hpa = INVALID_PAGE;
-       }
        spin_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
        spin_unlock(&kvm_lock);
        return kvm;
 }
 
-static int kvm_dev_open(struct inode *inode, struct file *filp)
-{
-       return 0;
-}
-
 /*
  * Free any memory in @free but not in @dont.
  */
@@ -353,7 +349,7 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
 {
        int i;
 
-       for (i = 0; i < 2; ++i)
+       for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i)
                if (vcpu->pio.guest_pages[i]) {
                        __free_page(vcpu->pio.guest_pages[i]);
                        vcpu->pio.guest_pages[i] = NULL;
@@ -362,30 +358,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
 
 static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->vmcs)
-               return;
-
        vcpu_load(vcpu);
        kvm_mmu_unload(vcpu);
        vcpu_put(vcpu);
 }
 
-static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
-{
-       if (!vcpu->vmcs)
-               return;
-
-       vcpu_load(vcpu);
-       kvm_mmu_destroy(vcpu);
-       vcpu_put(vcpu);
-       kvm_arch_ops->vcpu_free(vcpu);
-       free_page((unsigned long)vcpu->run);
-       vcpu->run = NULL;
-       free_page((unsigned long)vcpu->pio_data);
-       vcpu->pio_data = NULL;
-       free_pio_guest_pages(vcpu);
-}
-
 static void kvm_free_vcpus(struct kvm *kvm)
 {
        unsigned int i;
@@ -394,14 +371,15 @@ static void kvm_free_vcpus(struct kvm *kvm)
         * Unpin any mmu pages first.
         */
        for (i = 0; i < KVM_MAX_VCPUS; ++i)
-               kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
-       for (i = 0; i < KVM_MAX_VCPUS; ++i)
-               kvm_free_vcpu(&kvm->vcpus[i]);
-}
+               if (kvm->vcpus[i])
+                       kvm_unload_vcpu_mmu(kvm->vcpus[i]);
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               if (kvm->vcpus[i]) {
+                       kvm_x86_ops->vcpu_free(kvm->vcpus[i]);
+                       kvm->vcpus[i] = NULL;
+               }
+       }
 
-static int kvm_dev_release(struct inode *inode, struct file *filp)
-{
-       return 0;
 }
 
 static void kvm_destroy_vm(struct kvm *kvm)
@@ -411,6 +389,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
        spin_unlock(&kvm_lock);
        kvm_io_bus_destroy(&kvm->pio_bus);
        kvm_io_bus_destroy(&kvm->mmio_bus);
+       kfree(kvm->vpic);
+       kfree(kvm->vioapic);
        kvm_free_vcpus(kvm);
        kvm_free_physmem(kvm);
        kfree(kvm);
@@ -426,7 +406,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
 
 static void inject_gp(struct kvm_vcpu *vcpu)
 {
-       kvm_arch_ops->inject_gp(vcpu, 0);
+       kvm_x86_ops->inject_gp(vcpu, 0);
 }
 
 /*
@@ -437,58 +417,60 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
        gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
        unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
        int i;
-       u64 pdpte;
        u64 *pdpt;
        int ret;
        struct page *page;
+       u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
 
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        page = gfn_to_page(vcpu->kvm, pdpt_gfn);
-       /* FIXME: !page - emulate? 0xff? */
+       if (!page) {
+               ret = 0;
+               goto out;
+       }
+
        pdpt = kmap_atomic(page, KM_USER0);
+       memcpy(pdpte, pdpt+offset, sizeof(pdpte));
+       kunmap_atomic(pdpt, KM_USER0);
 
-       ret = 1;
-       for (i = 0; i < 4; ++i) {
-               pdpte = pdpt[offset + i];
-               if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
+       for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
+               if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
                        ret = 0;
                        goto out;
                }
        }
+       ret = 1;
 
-       for (i = 0; i < 4; ++i)
-               vcpu->pdptrs[i] = pdpt[offset + i];
-
+       memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs));
 out:
-       kunmap_atomic(pdpt, KM_USER0);
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
 
        return ret;
 }
 
 void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
-       if (cr0 & CR0_RESEVED_BITS) {
+       if (cr0 & CR0_RESERVED_BITS) {
                printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
                       cr0, vcpu->cr0);
                inject_gp(vcpu);
                return;
        }
 
-       if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) {
+       if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
                printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
                inject_gp(vcpu);
                return;
        }
 
-       if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) {
+       if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
                printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
                       "and a clear PE flag\n");
                inject_gp(vcpu);
                return;
        }
 
-       if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+       if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
 #ifdef CONFIG_X86_64
                if ((vcpu->shadow_efer & EFER_LME)) {
                        int cs_db, cs_l;
@@ -499,7 +481,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
                                inject_gp(vcpu);
                                return;
                        }
-                       kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+                       kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
                        if (cs_l) {
                                printk(KERN_DEBUG "set_cr0: #GP, start paging "
                                       "in long mode while CS.L == 1\n");
@@ -518,12 +500,12 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 
        }
 
-       kvm_arch_ops->set_cr0(vcpu, cr0);
+       kvm_x86_ops->set_cr0(vcpu, cr0);
        vcpu->cr0 = cr0;
 
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        kvm_mmu_reset_context(vcpu);
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
        return;
 }
 EXPORT_SYMBOL_GPL(set_cr0);
@@ -536,62 +518,72 @@ EXPORT_SYMBOL_GPL(lmsw);
 
 void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
-       if (cr4 & CR4_RESEVED_BITS) {
+       if (cr4 & CR4_RESERVED_BITS) {
                printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
                inject_gp(vcpu);
                return;
        }
 
        if (is_long_mode(vcpu)) {
-               if (!(cr4 & CR4_PAE_MASK)) {
+               if (!(cr4 & X86_CR4_PAE)) {
                        printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
                               "in long mode\n");
                        inject_gp(vcpu);
                        return;
                }
-       } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
+       } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE)
                   && !load_pdptrs(vcpu, vcpu->cr3)) {
                printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
                inject_gp(vcpu);
+               return;
        }
 
-       if (cr4 & CR4_VMXE_MASK) {
+       if (cr4 & X86_CR4_VMXE) {
                printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
                inject_gp(vcpu);
                return;
        }
-       kvm_arch_ops->set_cr4(vcpu, cr4);
-       spin_lock(&vcpu->kvm->lock);
+       kvm_x86_ops->set_cr4(vcpu, cr4);
+       vcpu->cr4 = cr4;
+       mutex_lock(&vcpu->kvm->lock);
        kvm_mmu_reset_context(vcpu);
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
 }
 EXPORT_SYMBOL_GPL(set_cr4);
 
 void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
        if (is_long_mode(vcpu)) {
-               if (cr3 & CR3_L_MODE_RESEVED_BITS) {
+               if (cr3 & CR3_L_MODE_RESERVED_BITS) {
                        printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
                        inject_gp(vcpu);
                        return;
                }
        } else {
-               if (cr3 & CR3_RESEVED_BITS) {
-                       printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
-                       inject_gp(vcpu);
-                       return;
-               }
-               if (is_paging(vcpu) && is_pae(vcpu) &&
-                   !load_pdptrs(vcpu, cr3)) {
-                       printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
-                              "reserved bits\n");
-                       inject_gp(vcpu);
-                       return;
+               if (is_pae(vcpu)) {
+                       if (cr3 & CR3_PAE_RESERVED_BITS) {
+                               printk(KERN_DEBUG
+                                      "set_cr3: #GP, reserved bits\n");
+                               inject_gp(vcpu);
+                               return;
+                       }
+                       if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
+                               printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
+                                      "reserved bits\n");
+                               inject_gp(vcpu);
+                               return;
+                       }
+               } else {
+                       if (cr3 & CR3_NONPAE_RESERVED_BITS) {
+                               printk(KERN_DEBUG
+                                      "set_cr3: #GP, reserved bits\n");
+                               inject_gp(vcpu);
+                               return;
+                       }
                }
        }
 
-       vcpu->cr3 = cr3;
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        /*
         * Does the new cr3 value map to physical memory? (Note, we
         * catch an invalid cr3 even in real-mode, because it would
@@ -603,46 +595,73 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
         */
        if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
                inject_gp(vcpu);
-       else
+       else {
+               vcpu->cr3 = cr3;
                vcpu->mmu.new_cr3(vcpu);
-       spin_unlock(&vcpu->kvm->lock);
+       }
+       mutex_unlock(&vcpu->kvm->lock);
 }
 EXPORT_SYMBOL_GPL(set_cr3);
 
 void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
-       if ( cr8 & CR8_RESEVED_BITS) {
+       if (cr8 & CR8_RESERVED_BITS) {
                printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
                inject_gp(vcpu);
                return;
        }
-       vcpu->cr8 = cr8;
+       if (irqchip_in_kernel(vcpu->kvm))
+               kvm_lapic_set_tpr(vcpu, cr8);
+       else
+               vcpu->cr8 = cr8;
 }
 EXPORT_SYMBOL_GPL(set_cr8);
 
-void fx_init(struct kvm_vcpu *vcpu)
+unsigned long get_cr8(struct kvm_vcpu *vcpu)
+{
+       if (irqchip_in_kernel(vcpu->kvm))
+               return kvm_lapic_get_cr8(vcpu);
+       else
+               return vcpu->cr8;
+}
+EXPORT_SYMBOL_GPL(get_cr8);
+
+u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
 {
-       struct __attribute__ ((__packed__)) fx_image_s {
-               u16 control; //fcw
-               u16 status; //fsw
-               u16 tag; // ftw
-               u16 opcode; //fop
-               u64 ip; // fpu ip
-               u64 operand;// fpu dp
-               u32 mxcsr;
-               u32 mxcsr_mask;
+       if (irqchip_in_kernel(vcpu->kvm))
+               return vcpu->apic_base;
+       else
+               return vcpu->apic_base;
+}
+EXPORT_SYMBOL_GPL(kvm_get_apic_base);
 
-       } *fx_image;
+void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
+{
+       /* TODO: reserve bits check */
+       if (irqchip_in_kernel(vcpu->kvm))
+               kvm_lapic_set_base(vcpu, data);
+       else
+               vcpu->apic_base = data;
+}
+EXPORT_SYMBOL_GPL(kvm_set_apic_base);
+
+void fx_init(struct kvm_vcpu *vcpu)
+{
+       unsigned after_mxcsr_mask;
 
-       fx_save(vcpu->host_fx_image);
+       /* Initialize guest FPU by resetting ours and saving into guest's */
+       preempt_disable();
+       fx_save(&vcpu->host_fx_image);
        fpu_init();
-       fx_save(vcpu->guest_fx_image);
-       fx_restore(vcpu->host_fx_image);
+       fx_save(&vcpu->guest_fx_image);
+       fx_restore(&vcpu->host_fx_image);
+       preempt_enable();
 
-       fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
-       fx_image->mxcsr = 0x1f80;
-       memset(vcpu->guest_fx_image + sizeof(struct fx_image_s),
-              0, FX_IMAGE_SIZE - sizeof(struct fx_image_s));
+       vcpu->cr0 |= X86_CR0_ET;
+       after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
+       vcpu->guest_fx_image.mxcsr = 0x1f80;
+       memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask,
+              0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
 }
 EXPORT_SYMBOL_GPL(fx_init);
 
@@ -661,7 +680,6 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
        unsigned long i;
        struct kvm_memory_slot *memslot;
        struct kvm_memory_slot old, new;
-       int memory_config_version;
 
        r = -EINVAL;
        /* General sanity checks */
@@ -681,10 +699,8 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
        if (!npages)
                mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
 
-raced:
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
 
-       memory_config_version = kvm->memory_config_version;
        new = old = *memslot;
 
        new.base_gfn = base_gfn;
@@ -707,11 +723,6 @@ raced:
                      (base_gfn >= s->base_gfn + s->npages)))
                        goto out_unlock;
        }
-       /*
-        * Do memory allocations outside lock.  memory_config_version will
-        * detect any races.
-        */
-       spin_unlock(&kvm->lock);
 
        /* Deallocate if slot is being removed */
        if (!npages)
@@ -728,14 +739,14 @@ raced:
                new.phys_mem = vmalloc(npages * sizeof(struct page *));
 
                if (!new.phys_mem)
-                       goto out_free;
+                       goto out_unlock;
 
                memset(new.phys_mem, 0, npages * sizeof(struct page *));
                for (i = 0; i < npages; ++i) {
                        new.phys_mem[i] = alloc_page(GFP_HIGHUSER
                                                     | __GFP_ZERO);
                        if (!new.phys_mem[i])
-                               goto out_free;
+                               goto out_unlock;
                        set_page_private(new.phys_mem[i],0);
                }
        }
@@ -746,39 +757,25 @@ raced:
 
                new.dirty_bitmap = vmalloc(dirty_bytes);
                if (!new.dirty_bitmap)
-                       goto out_free;
+                       goto out_unlock;
                memset(new.dirty_bitmap, 0, dirty_bytes);
        }
 
-       spin_lock(&kvm->lock);
-
-       if (memory_config_version != kvm->memory_config_version) {
-               spin_unlock(&kvm->lock);
-               kvm_free_physmem_slot(&new, &old);
-               goto raced;
-       }
-
-       r = -EAGAIN;
-       if (kvm->busy)
-               goto out_unlock;
-
        if (mem->slot >= kvm->nmemslots)
                kvm->nmemslots = mem->slot + 1;
 
        *memslot = new;
-       ++kvm->memory_config_version;
 
        kvm_mmu_slot_remove_write_access(kvm, mem->slot);
        kvm_flush_remote_tlbs(kvm);
 
-       spin_unlock(&kvm->lock);
+       mutex_unlock(&kvm->lock);
 
        kvm_free_physmem_slot(&old, &new);
        return 0;
 
 out_unlock:
-       spin_unlock(&kvm->lock);
-out_free:
+       mutex_unlock(&kvm->lock);
        kvm_free_physmem_slot(&new, &old);
 out:
        return r;
@@ -795,14 +792,8 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        int n;
        unsigned long any = 0;
 
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
 
-       /*
-        * Prevent changes to guest memory configuration even while the lock
-        * is not taken.
-        */
-       ++kvm->busy;
-       spin_unlock(&kvm->lock);
        r = -EINVAL;
        if (log->slot >= KVM_MEMORY_SLOTS)
                goto out;
@@ -821,18 +812,17 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
                goto out;
 
-       spin_lock(&kvm->lock);
-       kvm_mmu_slot_remove_write_access(kvm, log->slot);
-       kvm_flush_remote_tlbs(kvm);
-       memset(memslot->dirty_bitmap, 0, n);
-       spin_unlock(&kvm->lock);
+       /* If nothing is dirty, don't bother messing with page tables. */
+       if (any) {
+               kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               kvm_flush_remote_tlbs(kvm);
+               memset(memslot->dirty_bitmap, 0, n);
+       }
 
        r = 0;
 
 out:
-       spin_lock(&kvm->lock);
-       --kvm->busy;
-       spin_unlock(&kvm->lock);
+       mutex_unlock(&kvm->lock);
        return r;
 }
 
@@ -862,7 +852,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
            < alias->target_phys_addr)
                goto out;
 
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
 
        p = &kvm->aliases[alias->slot];
        p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
@@ -876,7 +866,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
 
        kvm_mmu_zap_all(kvm);
 
-       spin_unlock(&kvm->lock);
+       mutex_unlock(&kvm->lock);
 
        return 0;
 
@@ -884,6 +874,63 @@ out:
        return r;
 }
 
+static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
+{
+       int r;
+
+       r = 0;
+       switch (chip->chip_id) {
+       case KVM_IRQCHIP_PIC_MASTER:
+               memcpy (&chip->chip.pic,
+                       &pic_irqchip(kvm)->pics[0],
+                       sizeof(struct kvm_pic_state));
+               break;
+       case KVM_IRQCHIP_PIC_SLAVE:
+               memcpy (&chip->chip.pic,
+                       &pic_irqchip(kvm)->pics[1],
+                       sizeof(struct kvm_pic_state));
+               break;
+       case KVM_IRQCHIP_IOAPIC:
+               memcpy (&chip->chip.ioapic,
+                       ioapic_irqchip(kvm),
+                       sizeof(struct kvm_ioapic_state));
+               break;
+       default:
+               r = -EINVAL;
+               break;
+       }
+       return r;
+}
+
+static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
+{
+       int r;
+
+       r = 0;
+       switch (chip->chip_id) {
+       case KVM_IRQCHIP_PIC_MASTER:
+               memcpy (&pic_irqchip(kvm)->pics[0],
+                       &chip->chip.pic,
+                       sizeof(struct kvm_pic_state));
+               break;
+       case KVM_IRQCHIP_PIC_SLAVE:
+               memcpy (&pic_irqchip(kvm)->pics[1],
+                       &chip->chip.pic,
+                       sizeof(struct kvm_pic_state));
+               break;
+       case KVM_IRQCHIP_IOAPIC:
+               memcpy (ioapic_irqchip(kvm),
+                       &chip->chip.ioapic,
+                       sizeof(struct kvm_ioapic_state));
+               break;
+       default:
+               r = -EINVAL;
+               break;
+       }
+       kvm_pic_update_irq(pic_irqchip(kvm));
+       return r;
+}
+
 static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
 {
        int i;
@@ -930,37 +977,26 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
 }
 EXPORT_SYMBOL_GPL(gfn_to_page);
 
+/* WARNING: Does not work on aliased pages. */
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 {
-       int i;
        struct kvm_memory_slot *memslot;
-       unsigned long rel_gfn;
 
-       for (i = 0; i < kvm->nmemslots; ++i) {
-               memslot = &kvm->memslots[i];
-
-               if (gfn >= memslot->base_gfn
-                   && gfn < memslot->base_gfn + memslot->npages) {
+       memslot = __gfn_to_memslot(kvm, gfn);
+       if (memslot && memslot->dirty_bitmap) {
+               unsigned long rel_gfn = gfn - memslot->base_gfn;
 
-                       if (!memslot->dirty_bitmap)
-                               return;
-
-                       rel_gfn = gfn - memslot->base_gfn;
-
-                       /* avoid RMW */
-                       if (!test_bit(rel_gfn, memslot->dirty_bitmap))
-                               set_bit(rel_gfn, memslot->dirty_bitmap);
-                       return;
-               }
+               /* avoid RMW */
+               if (!test_bit(rel_gfn, memslot->dirty_bitmap))
+                       set_bit(rel_gfn, memslot->dirty_bitmap);
        }
 }
 
-static int emulator_read_std(unsigned long addr,
+int emulator_read_std(unsigned long addr,
                             void *val,
                             unsigned int bytes,
-                            struct x86_emulate_ctxt *ctxt)
+                            struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu *vcpu = ctxt->vcpu;
        void *data = val;
 
        while (bytes) {
@@ -990,26 +1026,42 @@ static int emulator_read_std(unsigned long addr,
 
        return X86EMUL_CONTINUE;
 }
+EXPORT_SYMBOL_GPL(emulator_read_std);
 
 static int emulator_write_std(unsigned long addr,
                              const void *val,
                              unsigned int bytes,
-                             struct x86_emulate_ctxt *ctxt)
+                             struct kvm_vcpu *vcpu)
 {
-       printk(KERN_ERR "emulator_write_std: addr %lx n %d\n",
-              addr, bytes);
+       pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes);
        return X86EMUL_UNHANDLEABLE;
 }
 
+/*
+ * Only apic need an MMIO device hook, so shortcut now..
+ */
+static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
+                                               gpa_t addr)
+{
+       struct kvm_io_device *dev;
+
+       if (vcpu->apic) {
+               dev = &vcpu->apic->dev;
+               if (dev->in_range(dev, addr))
+                       return dev;
+       }
+       return NULL;
+}
+
 static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
                                                gpa_t addr)
 {
-       /*
-        * Note that its important to have this wrapper function because
-        * in the very near future we will be checking for MMIOs against
-        * the LAPIC as well as the general MMIO bus
-        */
-       return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+       struct kvm_io_device *dev;
+
+       dev = vcpu_find_pervcpu_dev(vcpu, addr);
+       if (dev == NULL)
+               dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+       return dev;
 }
 
 static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
@@ -1021,9 +1073,8 @@ static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
 static int emulator_read_emulated(unsigned long addr,
                                  void *val,
                                  unsigned int bytes,
-                                 struct x86_emulate_ctxt *ctxt)
+                                 struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu      *vcpu = ctxt->vcpu;
        struct kvm_io_device *mmio_dev;
        gpa_t                 gpa;
 
@@ -1031,7 +1082,7 @@ static int emulator_read_emulated(unsigned long addr,
                memcpy(val, vcpu->mmio_data, bytes);
                vcpu->mmio_read_completed = 0;
                return X86EMUL_CONTINUE;
-       } else if (emulator_read_std(addr, val, bytes, ctxt)
+       } else if (emulator_read_std(addr, val, bytes, vcpu)
                   == X86EMUL_CONTINUE)
                return X86EMUL_CONTINUE;
 
@@ -1061,7 +1112,6 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
 {
        struct page *page;
        void *virt;
-       unsigned offset = offset_in_page(gpa);
 
        if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
                return 0;
@@ -1070,7 +1120,7 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
                return 0;
        mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
        virt = kmap_atomic(page, KM_USER0);
-       kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
+       kvm_mmu_pte_write(vcpu, gpa, val, bytes);
        memcpy(virt + offset_in_page(gpa), val, bytes);
        kunmap_atomic(virt, KM_USER0);
        return 1;
@@ -1079,14 +1129,13 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
 static int emulator_write_emulated_onepage(unsigned long addr,
                                           const void *val,
                                           unsigned int bytes,
-                                          struct x86_emulate_ctxt *ctxt)
+                                          struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu      *vcpu = ctxt->vcpu;
        struct kvm_io_device *mmio_dev;
        gpa_t                 gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
 
        if (gpa == UNMAPPED_GVA) {
-               kvm_arch_ops->inject_page_fault(vcpu, addr, 2);
+               kvm_x86_ops->inject_page_fault(vcpu, addr, 2);
                return X86EMUL_PROPAGATE_FAULT;
        }
 
@@ -1111,31 +1160,32 @@ static int emulator_write_emulated_onepage(unsigned long addr,
        return X86EMUL_CONTINUE;
 }
 
-static int emulator_write_emulated(unsigned long addr,
+int emulator_write_emulated(unsigned long addr,
                                   const void *val,
                                   unsigned int bytes,
-                                  struct x86_emulate_ctxt *ctxt)
+                                  struct kvm_vcpu *vcpu)
 {
        /* Crossing a page boundary? */
        if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
                int rc, now;
 
                now = -addr & ~PAGE_MASK;
-               rc = emulator_write_emulated_onepage(addr, val, now, ctxt);
+               rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
                if (rc != X86EMUL_CONTINUE)
                        return rc;
                addr += now;
                val += now;
                bytes -= now;
        }
-       return emulator_write_emulated_onepage(addr, val, bytes, ctxt);
+       return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
 }
+EXPORT_SYMBOL_GPL(emulator_write_emulated);
 
 static int emulator_cmpxchg_emulated(unsigned long addr,
                                     const void *old,
                                     const void *new,
                                     unsigned int bytes,
-                                    struct x86_emulate_ctxt *ctxt)
+                                    struct kvm_vcpu *vcpu)
 {
        static int reported;
 
@@ -1143,12 +1193,12 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
                reported = 1;
                printk(KERN_WARNING "kvm: emulating exchange as write\n");
        }
-       return emulator_write_emulated(addr, new, bytes, ctxt);
+       return emulator_write_emulated(addr, new, bytes, vcpu);
 }
 
 static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
 {
-       return kvm_arch_ops->get_segment_base(vcpu, seg);
+       return kvm_x86_ops->get_segment_base(vcpu, seg);
 }
 
 int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
@@ -1158,10 +1208,8 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
 
 int emulate_clts(struct kvm_vcpu *vcpu)
 {
-       unsigned long cr0;
-
-       cr0 = vcpu->cr0 & ~CR0_TS_MASK;
-       kvm_arch_ops->set_cr0(vcpu, cr0);
+       vcpu->cr0 &= ~X86_CR0_TS;
+       kvm_x86_ops->set_cr0(vcpu, vcpu->cr0);
        return X86EMUL_CONTINUE;
 }
 
@@ -1171,11 +1219,10 @@ int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest)
 
        switch (dr) {
        case 0 ... 3:
-               *dest = kvm_arch_ops->get_dr(vcpu, dr);
+               *dest = kvm_x86_ops->get_dr(vcpu, dr);
                return X86EMUL_CONTINUE;
        default:
-               printk(KERN_DEBUG "%s: unexpected dr %u\n",
-                      __FUNCTION__, dr);
+               pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr);
                return X86EMUL_UNHANDLEABLE;
        }
 }
@@ -1185,7 +1232,7 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
        unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
        int exception;
 
-       kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
+       kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
        if (exception) {
                /* FIXME: better handling */
                return X86EMUL_UNHANDLEABLE;
@@ -1193,25 +1240,25 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
        return X86EMUL_CONTINUE;
 }
 
-static void report_emulation_failure(struct x86_emulate_ctxt *ctxt)
+void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
 {
        static int reported;
        u8 opcodes[4];
-       unsigned long rip = ctxt->vcpu->rip;
+       unsigned long rip = vcpu->rip;
        unsigned long rip_linear;
 
-       rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS);
+       rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
 
        if (reported)
                return;
 
-       emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt);
+       emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu);
 
-       printk(KERN_ERR "emulation failed but !mmio_needed?"
-              " rip %lx %02x %02x %02x %02x\n",
-              rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
+       printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
+              context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
        reported = 1;
 }
+EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
 
 struct x86_emulate_ops emulate_ops = {
        .read_std            = emulator_read_std,
@@ -1231,12 +1278,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
        int cs_db, cs_l;
 
        vcpu->mmio_fault_cr2 = cr2;
-       kvm_arch_ops->cache_regs(vcpu);
+       kvm_x86_ops->cache_regs(vcpu);
 
-       kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+       kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
 
        emulate_ctxt.vcpu = vcpu;
-       emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu);
+       emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
        emulate_ctxt.cr2 = cr2;
        emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
                ? X86EMUL_MODE_REAL : cs_l
@@ -1259,9 +1306,13 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
        emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS);
 
        vcpu->mmio_is_write = 0;
+       vcpu->pio.string = 0;
        r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
+       if (vcpu->pio.string)
+               return EMULATE_DO_MMIO;
 
        if ((r || vcpu->mmio_is_write) && run) {
+               run->exit_reason = KVM_EXIT_MMIO;
                run->mmio.phys_addr = vcpu->mmio_phys_addr;
                memcpy(run->mmio.data, vcpu->mmio_data, 8);
                run->mmio.len = vcpu->mmio_size;
@@ -1272,14 +1323,14 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
                if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
                        return EMULATE_DONE;
                if (!vcpu->mmio_needed) {
-                       report_emulation_failure(&emulate_ctxt);
+                       kvm_report_emulation_failure(vcpu, "mmio");
                        return EMULATE_FAIL;
                }
                return EMULATE_DO_MMIO;
        }
 
-       kvm_arch_ops->decache_regs(vcpu);
-       kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
+       kvm_x86_ops->decache_regs(vcpu);
+       kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags);
 
        if (vcpu->mmio_is_write) {
                vcpu->mmio_needed = 0;
@@ -1290,14 +1341,45 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
 }
 EXPORT_SYMBOL_GPL(emulate_instruction);
 
-int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+/*
+ * The vCPU has executed a HLT instruction with in-kernel mode enabled.
+ */
+static void kvm_vcpu_block(struct kvm_vcpu *vcpu)
 {
-       if (vcpu->irq_summary)
-               return 1;
+       DECLARE_WAITQUEUE(wait, current);
 
-       vcpu->run->exit_reason = KVM_EXIT_HLT;
+       add_wait_queue(&vcpu->wq, &wait);
+
+       /*
+        * We will block until either an interrupt or a signal wakes us up
+        */
+       while (!kvm_cpu_has_interrupt(vcpu)
+              && !signal_pending(current)
+              && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE
+              && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               vcpu_put(vcpu);
+               schedule();
+               vcpu_load(vcpu);
+       }
+
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&vcpu->wq, &wait);
+}
+
+int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+{
        ++vcpu->stat.halt_exits;
-       return 0;
+       if (irqchip_in_kernel(vcpu->kvm)) {
+               vcpu->mp_state = VCPU_MP_STATE_HALTED;
+               kvm_vcpu_block(vcpu);
+               if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE)
+                       return -EINTR;
+               return 1;
+       } else {
+               vcpu->run->exit_reason = KVM_EXIT_HLT;
+               return 0;
+       }
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_halt);
 
@@ -1305,7 +1387,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
 
-       kvm_arch_ops->cache_regs(vcpu);
+       kvm_x86_ops->cache_regs(vcpu);
        ret = -KVM_EINVAL;
 #ifdef CONFIG_X86_64
        if (is_long_mode(vcpu)) {
@@ -1329,6 +1411,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
        }
        switch (nr) {
        default:
+               run->hypercall.nr = nr;
                run->hypercall.args[0] = a0;
                run->hypercall.args[1] = a1;
                run->hypercall.args[2] = a2;
@@ -1337,11 +1420,11 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
                run->hypercall.args[5] = a5;
                run->hypercall.ret = ret;
                run->hypercall.longmode = is_long_mode(vcpu);
-               kvm_arch_ops->decache_regs(vcpu);
+               kvm_x86_ops->decache_regs(vcpu);
                return 0;
        }
        vcpu->regs[VCPU_REGS_RAX] = ret;
-       kvm_arch_ops->decache_regs(vcpu);
+       kvm_x86_ops->decache_regs(vcpu);
        return 1;
 }
 EXPORT_SYMBOL_GPL(kvm_hypercall);
@@ -1355,26 +1438,26 @@ void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
 {
        struct descriptor_table dt = { limit, base };
 
-       kvm_arch_ops->set_gdt(vcpu, &dt);
+       kvm_x86_ops->set_gdt(vcpu, &dt);
 }
 
 void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
 {
        struct descriptor_table dt = { limit, base };
 
-       kvm_arch_ops->set_idt(vcpu, &dt);
+       kvm_x86_ops->set_idt(vcpu, &dt);
 }
 
 void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
                   unsigned long *rflags)
 {
        lmsw(vcpu, msw);
-       *rflags = kvm_arch_ops->get_rflags(vcpu);
+       *rflags = kvm_x86_ops->get_rflags(vcpu);
 }
 
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
 {
-       kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+       kvm_x86_ops->decache_cr4_guest_bits(vcpu);
        switch (cr) {
        case 0:
                return vcpu->cr0;
@@ -1396,7 +1479,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
        switch (cr) {
        case 0:
                set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
-               *rflags = kvm_arch_ops->get_rflags(vcpu);
+               *rflags = kvm_x86_ops->get_rflags(vcpu);
                break;
        case 2:
                vcpu->cr2 = val;
@@ -1439,7 +1522,7 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
 
        mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT);
        para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT);
-       para_state = kmap_atomic(para_state_page, KM_USER0);
+       para_state = kmap(para_state_page);
 
        printk(KERN_DEBUG "....  guest version: %d\n", para_state->guest_version);
        printk(KERN_DEBUG "....           size: %d\n", para_state->size);
@@ -1470,12 +1553,12 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
        mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT);
        hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT),
                                KM_USER1) + (hypercall_hpa & ~PAGE_MASK);
-       kvm_arch_ops->patch_hypercall(vcpu, hypercall);
+       kvm_x86_ops->patch_hypercall(vcpu, hypercall);
        kunmap_atomic(hypercall, KM_USER1);
 
        para_state->ret = 0;
 err_kunmap_skip:
-       kunmap_atomic(para_state, KM_USER0);
+       kunmap(para_state_page);
        return 0;
 err_gp:
        return 1;
@@ -1511,7 +1594,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
                data = 3;
                break;
        case MSR_IA32_APICBASE:
-               data = vcpu->apic_base;
+               data = kvm_get_apic_base(vcpu);
                break;
        case MSR_IA32_MISC_ENABLE:
                data = vcpu->ia32_misc_enable_msr;
@@ -1522,7 +1605,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
                break;
 #endif
        default:
-               printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr);
+               pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
                return 1;
        }
        *pdata = data;
@@ -1537,7 +1620,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
  */
 int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
-       return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
+       return kvm_x86_ops->get_msr(vcpu, msr_index, pdata);
 }
 
 #ifdef CONFIG_X86_64
@@ -1558,7 +1641,7 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
                return;
        }
 
-       kvm_arch_ops->set_efer(vcpu, efer);
+       kvm_x86_ops->set_efer(vcpu, efer);
 
        efer &= ~EFER_LMA;
        efer |= vcpu->shadow_efer & EFER_LMA;
@@ -1577,11 +1660,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                break;
 #endif
        case MSR_IA32_MC0_STATUS:
-               printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
+               pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
                       __FUNCTION__, data);
                break;
        case MSR_IA32_MCG_STATUS:
-               printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
+               pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
                        __FUNCTION__, data);
                break;
        case MSR_IA32_UCODE_REV:
@@ -1589,7 +1672,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        case 0x200 ... 0x2ff: /* MTRRs */
                break;
        case MSR_IA32_APICBASE:
-               vcpu->apic_base = data;
+               kvm_set_apic_base(vcpu, data);
                break;
        case MSR_IA32_MISC_ENABLE:
                vcpu->ia32_misc_enable_msr = data;
@@ -1601,7 +1684,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                return vcpu_register_para(vcpu, data);
 
        default:
-               printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr);
+               pr_unimpl(vcpu, "unhandled wrmsr: 0x%x\n", msr);
                return 1;
        }
        return 0;
@@ -1615,44 +1698,24 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
  */
 int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
-       return kvm_arch_ops->set_msr(vcpu, msr_index, data);
+       return kvm_x86_ops->set_msr(vcpu, msr_index, data);
 }
 
 void kvm_resched(struct kvm_vcpu *vcpu)
 {
        if (!need_resched())
                return;
-       vcpu_put(vcpu);
        cond_resched();
-       vcpu_load(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_resched);
 
-void load_msrs(struct vmx_msr_entry *e, int n)
-{
-       int i;
-
-       for (i = 0; i < n; ++i)
-               wrmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(load_msrs);
-
-void save_msrs(struct vmx_msr_entry *e, int n)
-{
-       int i;
-
-       for (i = 0; i < n; ++i)
-               rdmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(save_msrs);
-
 void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
 {
        int i;
        u32 function;
        struct kvm_cpuid_entry *e, *best;
 
-       kvm_arch_ops->cache_regs(vcpu);
+       kvm_x86_ops->cache_regs(vcpu);
        function = vcpu->regs[VCPU_REGS_RAX];
        vcpu->regs[VCPU_REGS_RAX] = 0;
        vcpu->regs[VCPU_REGS_RBX] = 0;
@@ -1678,8 +1741,8 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
                vcpu->regs[VCPU_REGS_RCX] = best->ecx;
                vcpu->regs[VCPU_REGS_RDX] = best->edx;
        }
-       kvm_arch_ops->decache_regs(vcpu);
-       kvm_arch_ops->skip_emulated_instruction(vcpu);
+       kvm_x86_ops->decache_regs(vcpu);
+       kvm_x86_ops->skip_emulated_instruction(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
 
@@ -1690,11 +1753,9 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
        unsigned bytes;
        int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1;
 
-       kvm_arch_ops->vcpu_put(vcpu);
        q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
                 PAGE_KERNEL);
        if (!q) {
-               kvm_arch_ops->vcpu_load(vcpu);
                free_pio_guest_pages(vcpu);
                return -ENOMEM;
        }
@@ -1706,7 +1767,6 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
                memcpy(p, q, bytes);
        q -= vcpu->pio.guest_page_offset;
        vunmap(q);
-       kvm_arch_ops->vcpu_load(vcpu);
        free_pio_guest_pages(vcpu);
        return 0;
 }
@@ -1717,7 +1777,7 @@ static int complete_pio(struct kvm_vcpu *vcpu)
        long delta;
        int r;
 
-       kvm_arch_ops->cache_regs(vcpu);
+       kvm_x86_ops->cache_regs(vcpu);
 
        if (!io->string) {
                if (io->in)
@@ -1727,7 +1787,7 @@ static int complete_pio(struct kvm_vcpu *vcpu)
                if (io->in) {
                        r = pio_copy_data(vcpu);
                        if (r) {
-                               kvm_arch_ops->cache_regs(vcpu);
+                               kvm_x86_ops->cache_regs(vcpu);
                                return r;
                        }
                }
@@ -1750,79 +1810,109 @@ static int complete_pio(struct kvm_vcpu *vcpu)
                        vcpu->regs[VCPU_REGS_RSI] += delta;
        }
 
-       kvm_arch_ops->decache_regs(vcpu);
+       kvm_x86_ops->decache_regs(vcpu);
 
        io->count -= io->cur_count;
        io->cur_count = 0;
 
-       if (!io->count)
-               kvm_arch_ops->skip_emulated_instruction(vcpu);
        return 0;
 }
 
-void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+static void kernel_pio(struct kvm_io_device *pio_dev,
+                      struct kvm_vcpu *vcpu,
+                      void *pd)
 {
        /* TODO: String I/O for in kernel device */
 
+       mutex_lock(&vcpu->kvm->lock);
        if (vcpu->pio.in)
                kvm_iodevice_read(pio_dev, vcpu->pio.port,
                                  vcpu->pio.size,
-                                 vcpu->pio_data);
+                                 pd);
        else
                kvm_iodevice_write(pio_dev, vcpu->pio.port,
                                   vcpu->pio.size,
-                                  vcpu->pio_data);
+                                  pd);
+       mutex_unlock(&vcpu->kvm->lock);
+}
+
+static void pio_string_write(struct kvm_io_device *pio_dev,
+                            struct kvm_vcpu *vcpu)
+{
+       struct kvm_pio_request *io = &vcpu->pio;
+       void *pd = vcpu->pio_data;
+       int i;
+
+       mutex_lock(&vcpu->kvm->lock);
+       for (i = 0; i < io->cur_count; i++) {
+               kvm_iodevice_write(pio_dev, io->port,
+                                  io->size,
+                                  pd);
+               pd += io->size;
+       }
+       mutex_unlock(&vcpu->kvm->lock);
 }
 
-int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
-                 int size, unsigned long count, int string, int down,
+int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+                 int size, unsigned port)
+{
+       struct kvm_io_device *pio_dev;
+
+       vcpu->run->exit_reason = KVM_EXIT_IO;
+       vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+       vcpu->run->io.size = vcpu->pio.size = size;
+       vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+       vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1;
+       vcpu->run->io.port = vcpu->pio.port = port;
+       vcpu->pio.in = in;
+       vcpu->pio.string = 0;
+       vcpu->pio.down = 0;
+       vcpu->pio.guest_page_offset = 0;
+       vcpu->pio.rep = 0;
+
+       kvm_x86_ops->cache_regs(vcpu);
+       memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
+       kvm_x86_ops->decache_regs(vcpu);
+
+       kvm_x86_ops->skip_emulated_instruction(vcpu);
+
+       pio_dev = vcpu_find_pio_dev(vcpu, port);
+       if (pio_dev) {
+               kernel_pio(pio_dev, vcpu, vcpu->pio_data);
+               complete_pio(vcpu);
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_pio);
+
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+                 int size, unsigned long count, int down,
                  gva_t address, int rep, unsigned port)
 {
        unsigned now, in_page;
-       int i;
+       int i, ret = 0;
        int nr_pages = 1;
        struct page *page;
        struct kvm_io_device *pio_dev;
 
        vcpu->run->exit_reason = KVM_EXIT_IO;
        vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
-       vcpu->run->io.size = size;
+       vcpu->run->io.size = vcpu->pio.size = size;
        vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
-       vcpu->run->io.count = count;
-       vcpu->run->io.port = port;
-       vcpu->pio.count = count;
-       vcpu->pio.cur_count = count;
-       vcpu->pio.size = size;
+       vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count;
+       vcpu->run->io.port = vcpu->pio.port = port;
        vcpu->pio.in = in;
-       vcpu->pio.port = port;
-       vcpu->pio.string = string;
+       vcpu->pio.string = 1;
        vcpu->pio.down = down;
        vcpu->pio.guest_page_offset = offset_in_page(address);
        vcpu->pio.rep = rep;
 
-       pio_dev = vcpu_find_pio_dev(vcpu, port);
-       if (!string) {
-               kvm_arch_ops->cache_regs(vcpu);
-               memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
-               kvm_arch_ops->decache_regs(vcpu);
-               if (pio_dev) {
-                       kernel_pio(pio_dev, vcpu);
-                       complete_pio(vcpu);
-                       return 1;
-               }
-               return 0;
-       }
-       /* TODO: String I/O for in kernel device */
-       if (pio_dev)
-               printk(KERN_ERR "kvm_setup_pio: no string io support\n");
-
        if (!count) {
-               kvm_arch_ops->skip_emulated_instruction(vcpu);
+               kvm_x86_ops->skip_emulated_instruction(vcpu);
                return 1;
        }
 
-       now = min(count, PAGE_SIZE / size);
-
        if (!down)
                in_page = PAGE_SIZE - offset_in_page(address);
        else
@@ -1841,20 +1931,23 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
                /*
                 * String I/O in reverse.  Yuck.  Kill the guest, fix later.
                 */
-               printk(KERN_ERR "kvm: guest string pio down\n");
+               pr_unimpl(vcpu, "guest string pio down\n");
                inject_gp(vcpu);
                return 1;
        }
        vcpu->run->io.count = now;
        vcpu->pio.cur_count = now;
 
+       if (vcpu->pio.cur_count == vcpu->pio.count)
+               kvm_x86_ops->skip_emulated_instruction(vcpu);
+
        for (i = 0; i < nr_pages; ++i) {
-               spin_lock(&vcpu->kvm->lock);
+               mutex_lock(&vcpu->kvm->lock);
                page = gva_to_page(vcpu, address + i * PAGE_SIZE);
                if (page)
                        get_page(page);
                vcpu->pio.guest_pages[i] = page;
-               spin_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&vcpu->kvm->lock);
                if (!page) {
                        inject_gp(vcpu);
                        free_pio_guest_pages(vcpu);
@@ -1862,11 +1955,147 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
                }
        }
 
-       if (!vcpu->pio.in)
-               return pio_copy_data(vcpu);
-       return 0;
+       pio_dev = vcpu_find_pio_dev(vcpu, port);
+       if (!vcpu->pio.in) {
+               /* string PIO write */
+               ret = pio_copy_data(vcpu);
+               if (ret >= 0 && pio_dev) {
+                       pio_string_write(pio_dev, vcpu);
+                       complete_pio(vcpu);
+                       if (vcpu->pio.count == 0)
+                               ret = 1;
+               }
+       } else if (pio_dev)
+               pr_unimpl(vcpu, "no string pio read support yet, "
+                      "port %x size %d count %ld\n",
+                       port, size, count);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
+
+/*
+ * Check if userspace requested an interrupt window, and that the
+ * interrupt window is open.
+ *
+ * No need to exit to userspace if we already have an interrupt queued.
+ */
+static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
+                                         struct kvm_run *kvm_run)
+{
+       return (!vcpu->irq_summary &&
+               kvm_run->request_interrupt_window &&
+               vcpu->interrupt_window_open &&
+               (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
+}
+
+static void post_kvm_run_save(struct kvm_vcpu *vcpu,
+                             struct kvm_run *kvm_run)
+{
+       kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
+       kvm_run->cr8 = get_cr8(vcpu);
+       kvm_run->apic_base = kvm_get_apic_base(vcpu);
+       if (irqchip_in_kernel(vcpu->kvm))
+               kvm_run->ready_for_interrupt_injection = 1;
+       else
+               kvm_run->ready_for_interrupt_injection =
+                                       (vcpu->interrupt_window_open &&
+                                        vcpu->irq_summary == 0);
+}
+
+static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       int r;
+
+       if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) {
+               printk("vcpu %d received sipi with vector # %x\n",
+                      vcpu->vcpu_id, vcpu->sipi_vector);
+               kvm_lapic_reset(vcpu);
+               kvm_x86_ops->vcpu_reset(vcpu);
+               vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+       }
+
+preempted:
+       if (vcpu->guest_debug.enabled)
+               kvm_x86_ops->guest_debug_pre(vcpu);
+
+again:
+       r = kvm_mmu_reload(vcpu);
+       if (unlikely(r))
+               goto out;
+
+       preempt_disable();
+
+       kvm_x86_ops->prepare_guest_switch(vcpu);
+       kvm_load_guest_fpu(vcpu);
+
+       local_irq_disable();
+
+       if (signal_pending(current)) {
+               local_irq_enable();
+               preempt_enable();
+               r = -EINTR;
+               kvm_run->exit_reason = KVM_EXIT_INTR;
+               ++vcpu->stat.signal_exits;
+               goto out;
+       }
+
+       if (irqchip_in_kernel(vcpu->kvm))
+               kvm_x86_ops->inject_pending_irq(vcpu);
+       else if (!vcpu->mmio_read_completed)
+               kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run);
+
+       vcpu->guest_mode = 1;
+       kvm_guest_enter();
+
+       if (vcpu->requests)
+               if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
+                       kvm_x86_ops->tlb_flush(vcpu);
+
+       kvm_x86_ops->run(vcpu, kvm_run);
+
+       kvm_guest_exit();
+       vcpu->guest_mode = 0;
+       local_irq_enable();
+
+       ++vcpu->stat.exits;
+
+       preempt_enable();
+
+       /*
+        * Profile KVM exit RIPs:
+        */
+       if (unlikely(prof_on == KVM_PROFILING)) {
+               kvm_x86_ops->cache_regs(vcpu);
+               profile_hit(KVM_PROFILING, (void *)vcpu->rip);
+       }
+
+       r = kvm_x86_ops->handle_exit(kvm_run, vcpu);
+
+       if (r > 0) {
+               if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+                       r = -EINTR;
+                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       ++vcpu->stat.request_irq_exits;
+                       goto out;
+               }
+               if (!need_resched()) {
+                       ++vcpu->stat.light_exits;
+                       goto again;
+               }
+       }
+
+out:
+       if (r > 0) {
+               kvm_resched(vcpu);
+               goto preempted;
+       }
+
+       post_kvm_run_save(vcpu, kvm_run);
+
+       return r;
 }
-EXPORT_SYMBOL_GPL(kvm_setup_pio);
+
 
 static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
@@ -1875,11 +2104,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        vcpu_load(vcpu);
 
+       if (unlikely(vcpu->mp_state == VCPU_MP_STATE_UNINITIALIZED)) {
+               kvm_vcpu_block(vcpu);
+               vcpu_put(vcpu);
+               return -EAGAIN;
+       }
+
        if (vcpu->sigset_active)
                sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
        /* re-sync apic's tpr */
-       vcpu->cr8 = kvm_run->cr8;
+       if (!irqchip_in_kernel(vcpu->kvm))
+               set_cr8(vcpu, kvm_run->cr8);
 
        if (vcpu->pio.cur_count) {
                r = complete_pio(vcpu);
@@ -1897,19 +2133,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        /*
                         * Read-modify-write.  Back to userspace.
                         */
-                       kvm_run->exit_reason = KVM_EXIT_MMIO;
                        r = 0;
                        goto out;
                }
        }
 
        if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) {
-               kvm_arch_ops->cache_regs(vcpu);
+               kvm_x86_ops->cache_regs(vcpu);
                vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret;
-               kvm_arch_ops->decache_regs(vcpu);
+               kvm_x86_ops->decache_regs(vcpu);
        }
 
-       r = kvm_arch_ops->run(vcpu, kvm_run);
+       r = __vcpu_run(vcpu, kvm_run);
 
 out:
        if (vcpu->sigset_active)
@@ -1924,7 +2159,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
 {
        vcpu_load(vcpu);
 
-       kvm_arch_ops->cache_regs(vcpu);
+       kvm_x86_ops->cache_regs(vcpu);
 
        regs->rax = vcpu->regs[VCPU_REGS_RAX];
        regs->rbx = vcpu->regs[VCPU_REGS_RBX];
@@ -1946,7 +2181,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
 #endif
 
        regs->rip = vcpu->rip;
-       regs->rflags = kvm_arch_ops->get_rflags(vcpu);
+       regs->rflags = kvm_x86_ops->get_rflags(vcpu);
 
        /*
         * Don't leak debug flags in case they were set for guest debugging
@@ -1984,9 +2219,9 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
 #endif
 
        vcpu->rip = regs->rip;
-       kvm_arch_ops->set_rflags(vcpu, regs->rflags);
+       kvm_x86_ops->set_rflags(vcpu, regs->rflags);
 
-       kvm_arch_ops->decache_regs(vcpu);
+       kvm_x86_ops->decache_regs(vcpu);
 
        vcpu_put(vcpu);
 
@@ -1996,13 +2231,14 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
 static void get_segment(struct kvm_vcpu *vcpu,
                        struct kvm_segment *var, int seg)
 {
-       return kvm_arch_ops->get_segment(vcpu, var, seg);
+       return kvm_x86_ops->get_segment(vcpu, var, seg);
 }
 
 static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                                    struct kvm_sregs *sregs)
 {
        struct descriptor_table dt;
+       int pending_vec;
 
        vcpu_load(vcpu);
 
@@ -2016,24 +2252,31 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
        get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
        get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
 
-       kvm_arch_ops->get_idt(vcpu, &dt);
+       kvm_x86_ops->get_idt(vcpu, &dt);
        sregs->idt.limit = dt.limit;
        sregs->idt.base = dt.base;
-       kvm_arch_ops->get_gdt(vcpu, &dt);
+       kvm_x86_ops->get_gdt(vcpu, &dt);
        sregs->gdt.limit = dt.limit;
        sregs->gdt.base = dt.base;
 
-       kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+       kvm_x86_ops->decache_cr4_guest_bits(vcpu);
        sregs->cr0 = vcpu->cr0;
        sregs->cr2 = vcpu->cr2;
        sregs->cr3 = vcpu->cr3;
        sregs->cr4 = vcpu->cr4;
-       sregs->cr8 = vcpu->cr8;
+       sregs->cr8 = get_cr8(vcpu);
        sregs->efer = vcpu->shadow_efer;
-       sregs->apic_base = vcpu->apic_base;
-
-       memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
-              sizeof sregs->interrupt_bitmap);
+       sregs->apic_base = kvm_get_apic_base(vcpu);
+
+       if (irqchip_in_kernel(vcpu->kvm)) {
+               memset(sregs->interrupt_bitmap, 0,
+                      sizeof sregs->interrupt_bitmap);
+               pending_vec = kvm_x86_ops->get_irq(vcpu);
+               if (pending_vec >= 0)
+                       set_bit(pending_vec, (unsigned long *)sregs->interrupt_bitmap);
+       } else
+               memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
+                      sizeof sregs->interrupt_bitmap);
 
        vcpu_put(vcpu);
 
@@ -2043,56 +2286,69 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
 static void set_segment(struct kvm_vcpu *vcpu,
                        struct kvm_segment *var, int seg)
 {
-       return kvm_arch_ops->set_segment(vcpu, var, seg);
+       return kvm_x86_ops->set_segment(vcpu, var, seg);
 }
 
 static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
                                    struct kvm_sregs *sregs)
 {
        int mmu_reset_needed = 0;
-       int i;
+       int i, pending_vec, max_bits;
        struct descriptor_table dt;
 
        vcpu_load(vcpu);
 
        dt.limit = sregs->idt.limit;
        dt.base = sregs->idt.base;
-       kvm_arch_ops->set_idt(vcpu, &dt);
+       kvm_x86_ops->set_idt(vcpu, &dt);
        dt.limit = sregs->gdt.limit;
        dt.base = sregs->gdt.base;
-       kvm_arch_ops->set_gdt(vcpu, &dt);
+       kvm_x86_ops->set_gdt(vcpu, &dt);
 
        vcpu->cr2 = sregs->cr2;
        mmu_reset_needed |= vcpu->cr3 != sregs->cr3;
        vcpu->cr3 = sregs->cr3;
 
-       vcpu->cr8 = sregs->cr8;
+       set_cr8(vcpu, sregs->cr8);
 
        mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
 #ifdef CONFIG_X86_64
-       kvm_arch_ops->set_efer(vcpu, sregs->efer);
+       kvm_x86_ops->set_efer(vcpu, sregs->efer);
 #endif
-       vcpu->apic_base = sregs->apic_base;
+       kvm_set_apic_base(vcpu, sregs->apic_base);
 
-       kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+       kvm_x86_ops->decache_cr4_guest_bits(vcpu);
 
        mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
-       kvm_arch_ops->set_cr0(vcpu, sregs->cr0);
+       vcpu->cr0 = sregs->cr0;
+       kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
 
        mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
-       kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
+       kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
        if (!is_long_mode(vcpu) && is_pae(vcpu))
                load_pdptrs(vcpu, vcpu->cr3);
 
        if (mmu_reset_needed)
                kvm_mmu_reset_context(vcpu);
 
-       memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
-              sizeof vcpu->irq_pending);
-       vcpu->irq_summary = 0;
-       for (i = 0; i < NR_IRQ_WORDS; ++i)
-               if (vcpu->irq_pending[i])
-                       __set_bit(i, &vcpu->irq_summary);
+       if (!irqchip_in_kernel(vcpu->kvm)) {
+               memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
+                      sizeof vcpu->irq_pending);
+               vcpu->irq_summary = 0;
+               for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i)
+                       if (vcpu->irq_pending[i])
+                               __set_bit(i, &vcpu->irq_summary);
+       } else {
+               max_bits = (sizeof sregs->interrupt_bitmap) << 3;
+               pending_vec = find_first_bit(
+                       (const unsigned long *)sregs->interrupt_bitmap,
+                       max_bits);
+               /* Only pending external irq is handled here */
+               if (pending_vec < max_bits) {
+                       kvm_x86_ops->set_irq(vcpu, pending_vec);
+                       printk("Set back pending irq %d\n", pending_vec);
+               }
+       }
 
        set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
        set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
@@ -2109,6 +2365,16 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+       struct kvm_segment cs;
+
+       get_segment(vcpu, &cs, VCPU_SREG_CS);
+       *db = cs.db;
+       *l = cs.l;
+}
+EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits);
+
 /*
  * List of msr numbers which we expose to userspace through KVM_GET_MSRS
  * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
@@ -2236,13 +2502,13 @@ static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
        gpa_t gpa;
 
        vcpu_load(vcpu);
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
        tr->physical_address = gpa;
        tr->valid = gpa != UNMAPPED_GVA;
        tr->writeable = 1;
        tr->usermode = 0;
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
        vcpu_put(vcpu);
 
        return 0;
@@ -2253,6 +2519,8 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
 {
        if (irq->irq < 0 || irq->irq >= 256)
                return -EINVAL;
+       if (irqchip_in_kernel(vcpu->kvm))
+               return -ENXIO;
        vcpu_load(vcpu);
 
        set_bit(irq->irq, vcpu->irq_pending);
@@ -2270,7 +2538,7 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
 
        vcpu_load(vcpu);
 
-       r = kvm_arch_ops->set_guest_debug(vcpu, dbg);
+       r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
 
        vcpu_put(vcpu);
 
@@ -2285,7 +2553,6 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
        unsigned long pgoff;
        struct page *page;
 
-       *type = VM_FAULT_MINOR;
        pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
        if (pgoff == 0)
                page = virt_to_page(vcpu->run);
@@ -2294,6 +2561,9 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
        else
                return NOPAGE_SIGBUS;
        get_page(page);
+       if (type != NULL)
+               *type = VM_FAULT_MINOR;
+
        return page;
 }
 
@@ -2346,74 +2616,52 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
 {
        int r;
        struct kvm_vcpu *vcpu;
-       struct page *page;
 
-       r = -EINVAL;
        if (!valid_vcpu(n))
-               goto out;
-
-       vcpu = &kvm->vcpus[n];
-
-       mutex_lock(&vcpu->mutex);
-
-       if (vcpu->vmcs) {
-               mutex_unlock(&vcpu->mutex);
-               return -EEXIST;
-       }
-
-       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       r = -ENOMEM;
-       if (!page)
-               goto out_unlock;
-       vcpu->run = page_address(page);
-
-       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       r = -ENOMEM;
-       if (!page)
-               goto out_free_run;
-       vcpu->pio_data = page_address(page);
+               return -EINVAL;
 
-       vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
-                                          FX_IMAGE_ALIGN);
-       vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
-       vcpu->cr0 = 0x10;
+       vcpu = kvm_x86_ops->vcpu_create(kvm, n);
+       if (IS_ERR(vcpu))
+               return PTR_ERR(vcpu);
 
-       r = kvm_arch_ops->vcpu_create(vcpu);
-       if (r < 0)
-               goto out_free_vcpus;
+       preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
 
-       r = kvm_mmu_create(vcpu);
-       if (r < 0)
-               goto out_free_vcpus;
+       /* We do fxsave: this must be aligned. */
+       BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF);
 
-       kvm_arch_ops->vcpu_load(vcpu);
+       vcpu_load(vcpu);
        r = kvm_mmu_setup(vcpu);
-       if (r >= 0)
-               r = kvm_arch_ops->vcpu_setup(vcpu);
        vcpu_put(vcpu);
-
        if (r < 0)
-               goto out_free_vcpus;
+               goto free_vcpu;
 
+       mutex_lock(&kvm->lock);
+       if (kvm->vcpus[n]) {
+               r = -EEXIST;
+               mutex_unlock(&kvm->lock);
+               goto mmu_unload;
+       }
+       kvm->vcpus[n] = vcpu;
+       mutex_unlock(&kvm->lock);
+
+       /* Now it's all set up, let userspace reach it */
        r = create_vcpu_fd(vcpu);
        if (r < 0)
-               goto out_free_vcpus;
+               goto unlink;
+       return r;
 
-       spin_lock(&kvm_lock);
-       if (n >= kvm->nvcpus)
-               kvm->nvcpus = n + 1;
-       spin_unlock(&kvm_lock);
+unlink:
+       mutex_lock(&kvm->lock);
+       kvm->vcpus[n] = NULL;
+       mutex_unlock(&kvm->lock);
 
-       return r;
+mmu_unload:
+       vcpu_load(vcpu);
+       kvm_mmu_unload(vcpu);
+       vcpu_put(vcpu);
 
-out_free_vcpus:
-       kvm_free_vcpu(vcpu);
-out_free_run:
-       free_page((unsigned long)vcpu->run);
-       vcpu->run = NULL;
-out_unlock:
-       mutex_unlock(&vcpu->mutex);
-out:
+free_vcpu:
+       kvm_x86_ops->vcpu_free(vcpu);
        return r;
 }
 
@@ -2493,7 +2741,7 @@ struct fxsave {
 
 static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-       struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+       struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
 
        vcpu_load(vcpu);
 
@@ -2513,7 +2761,7 @@ static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 
 static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-       struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+       struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
 
        vcpu_load(vcpu);
 
@@ -2531,6 +2779,27 @@ static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
        return 0;
 }
 
+static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
+                                   struct kvm_lapic_state *s)
+{
+       vcpu_load(vcpu);
+       memcpy(s->regs, vcpu->apic->regs, sizeof *s);
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
+static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
+                                   struct kvm_lapic_state *s)
+{
+       vcpu_load(vcpu);
+       memcpy(vcpu->apic->regs, s->regs, sizeof *s);
+       kvm_apic_post_state_restore(vcpu);
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
 static long kvm_vcpu_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
@@ -2700,6 +2969,31 @@ static long kvm_vcpu_ioctl(struct file *filp,
                r = 0;
                break;
        }
+       case KVM_GET_LAPIC: {
+               struct kvm_lapic_state lapic;
+
+               memset(&lapic, 0, sizeof lapic);
+               r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic);
+               if (r)
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user(argp, &lapic, sizeof lapic))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_SET_LAPIC: {
+               struct kvm_lapic_state lapic;
+
+               r = -EFAULT;
+               if (copy_from_user(&lapic, argp, sizeof lapic))
+                       goto out;
+               r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);;
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
        default:
                ;
        }
@@ -2753,6 +3047,75 @@ static long kvm_vm_ioctl(struct file *filp,
                        goto out;
                break;
        }
+       case KVM_CREATE_IRQCHIP:
+               r = -ENOMEM;
+               kvm->vpic = kvm_create_pic(kvm);
+               if (kvm->vpic) {
+                       r = kvm_ioapic_init(kvm);
+                       if (r) {
+                               kfree(kvm->vpic);
+                               kvm->vpic = NULL;
+                               goto out;
+                       }
+               }
+               else
+                       goto out;
+               break;
+       case KVM_IRQ_LINE: {
+               struct kvm_irq_level irq_event;
+
+               r = -EFAULT;
+               if (copy_from_user(&irq_event, argp, sizeof irq_event))
+                       goto out;
+               if (irqchip_in_kernel(kvm)) {
+                       mutex_lock(&kvm->lock);
+                       if (irq_event.irq < 16)
+                               kvm_pic_set_irq(pic_irqchip(kvm),
+                                       irq_event.irq,
+                                       irq_event.level);
+                       kvm_ioapic_set_irq(kvm->vioapic,
+                                       irq_event.irq,
+                                       irq_event.level);
+                       mutex_unlock(&kvm->lock);
+                       r = 0;
+               }
+               break;
+       }
+       case KVM_GET_IRQCHIP: {
+               /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+               struct kvm_irqchip chip;
+
+               r = -EFAULT;
+               if (copy_from_user(&chip, argp, sizeof chip))
+                       goto out;
+               r = -ENXIO;
+               if (!irqchip_in_kernel(kvm))
+                       goto out;
+               r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
+               if (r)
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user(argp, &chip, sizeof chip))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_SET_IRQCHIP: {
+               /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+               struct kvm_irqchip chip;
+
+               r = -EFAULT;
+               if (copy_from_user(&chip, argp, sizeof chip))
+                       goto out;
+               r = -ENXIO;
+               if (!irqchip_in_kernel(kvm))
+                       goto out;
+               r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
        default:
                ;
        }
@@ -2768,12 +3131,14 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
        unsigned long pgoff;
        struct page *page;
 
-       *type = VM_FAULT_MINOR;
        pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
        page = gfn_to_page(kvm, pgoff);
        if (!page)
                return NOPAGE_SIGBUS;
        get_page(page);
+       if (type != NULL)
+               *type = VM_FAULT_MINOR;
+
        return page;
 }
 
@@ -2861,12 +3226,20 @@ static long kvm_dev_ioctl(struct file *filp,
                r = 0;
                break;
        }
-       case KVM_CHECK_EXTENSION:
-               /*
-                * No extensions defined at present.
-                */
-               r = 0;
+       case KVM_CHECK_EXTENSION: {
+               int ext = (long)argp;
+
+               switch (ext) {
+               case KVM_CAP_IRQCHIP:
+               case KVM_CAP_HLT:
+                       r = 1;
+                       break;
+               default:
+                       r = 0;
+                       break;
+               }
                break;
+       }
        case KVM_GET_VCPU_MMAP_SIZE:
                r = -EINVAL;
                if (arg)
@@ -2881,8 +3254,6 @@ out:
 }
 
 static struct file_operations kvm_chardev_ops = {
-       .open           = kvm_dev_open,
-       .release        = kvm_dev_release,
        .unlocked_ioctl = kvm_dev_ioctl,
        .compat_ioctl   = kvm_dev_ioctl,
 };
@@ -2893,25 +3264,6 @@ static struct miscdevice kvm_dev = {
        &kvm_chardev_ops,
 };
 
-static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
-                       void *v)
-{
-       if (val == SYS_RESTART) {
-               /*
-                * Some (well, at least mine) BIOSes hang on reboot if
-                * in vmx root mode.
-                */
-               printk(KERN_INFO "kvm: exiting hardware virtualization\n");
-               on_each_cpu(hardware_disable, NULL, 0, 1);
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block kvm_reboot_notifier = {
-       .notifier_call = kvm_reboot,
-       .priority = 0,
-};
-
 /*
  * Make sure that a cpu that is being hot-unplugged does not have any vcpus
  * cached on it.
@@ -2925,7 +3277,9 @@ static void decache_vcpus_on_cpu(int cpu)
        spin_lock(&kvm_lock);
        list_for_each_entry(vm, &vm_list, vm_list)
                for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       vcpu = &vm->vcpus[i];
+                       vcpu = vm->vcpus[i];
+                       if (!vcpu)
+                               continue;
                        /*
                         * If the vcpu is locked, then it is running on some
                         * other cpu and therefore it is not cached on the
@@ -2936,7 +3290,7 @@ static void decache_vcpus_on_cpu(int cpu)
                         */
                        if (mutex_trylock(&vcpu->mutex)) {
                                if (vcpu->cpu == cpu) {
-                                       kvm_arch_ops->vcpu_decache(vcpu);
+                                       kvm_x86_ops->vcpu_decache(vcpu);
                                        vcpu->cpu = -1;
                                }
                                mutex_unlock(&vcpu->mutex);
@@ -2952,7 +3306,7 @@ static void hardware_enable(void *junk)
        if (cpu_isset(cpu, cpus_hardware_enabled))
                return;
        cpu_set(cpu, cpus_hardware_enabled);
-       kvm_arch_ops->hardware_enable(NULL);
+       kvm_x86_ops->hardware_enable(NULL);
 }
 
 static void hardware_disable(void *junk)
@@ -2963,7 +3317,7 @@ static void hardware_disable(void *junk)
                return;
        cpu_clear(cpu, cpus_hardware_enabled);
        decache_vcpus_on_cpu(cpu);
-       kvm_arch_ops->hardware_disable(NULL);
+       kvm_x86_ops->hardware_disable(NULL);
 }
 
 static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
@@ -2994,6 +3348,25 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
        return NOTIFY_OK;
 }
 
+static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
+                       void *v)
+{
+       if (val == SYS_RESTART) {
+               /*
+                * Some (well, at least mine) BIOSes hang on reboot if
+                * in vmx root mode.
+                */
+               printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+               on_each_cpu(hardware_disable, NULL, 0, 1);
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_reboot_notifier = {
+       .notifier_call = kvm_reboot,
+       .priority = 0,
+};
+
 void kvm_io_bus_init(struct kvm_io_bus *bus)
 {
        memset(bus, 0, sizeof(*bus));
@@ -3047,18 +3420,15 @@ static u64 stat_get(void *_offset)
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
                for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       vcpu = &kvm->vcpus[i];
-                       total += *(u32 *)((void *)vcpu + offset);
+                       vcpu = kvm->vcpus[i];
+                       if (vcpu)
+                               total += *(u32 *)((void *)vcpu + offset);
                }
        spin_unlock(&kvm_lock);
        return total;
 }
 
-static void stat_set(void *offset, u64 val)
-{
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, NULL, "%llu\n");
 
 static __init void kvm_init_debug(void)
 {
@@ -3105,11 +3475,34 @@ static struct sys_device kvm_sysdev = {
 
 hpa_t bad_page_address;
 
-int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
+static inline
+struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
+{
+       return container_of(pn, struct kvm_vcpu, preempt_notifier);
+}
+
+static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
+{
+       struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+       kvm_x86_ops->vcpu_load(vcpu, cpu);
+}
+
+static void kvm_sched_out(struct preempt_notifier *pn,
+                         struct task_struct *next)
+{
+       struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+       kvm_x86_ops->vcpu_put(vcpu);
+}
+
+int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
+                 struct module *module)
 {
        int r;
+       int cpu;
 
-       if (kvm_arch_ops) {
+       if (kvm_x86_ops) {
                printk(KERN_ERR "kvm: already loaded the other module\n");
                return -EEXIST;
        }
@@ -3123,12 +3516,20 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
                return -EOPNOTSUPP;
        }
 
-       kvm_arch_ops = ops;
+       kvm_x86_ops = ops;
 
-       r = kvm_arch_ops->hardware_setup();
+       r = kvm_x86_ops->hardware_setup();
        if (r < 0)
                goto out;
 
+       for_each_online_cpu(cpu) {
+               smp_call_function_single(cpu,
+                               kvm_x86_ops->check_processor_compatibility,
+                               &r, 0, 1);
+               if (r < 0)
+                       goto out_free_0;
+       }
+
        on_each_cpu(hardware_enable, NULL, 0, 1);
        r = register_cpu_notifier(&kvm_cpu_notifier);
        if (r)
@@ -3143,6 +3544,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
        if (r)
                goto out_free_3;
 
+       /* A kmem cache lets us meet the alignment requirements of fx_save. */
+       kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size,
+                                          __alignof__(struct kvm_vcpu), 0, 0);
+       if (!kvm_vcpu_cache) {
+               r = -ENOMEM;
+               goto out_free_4;
+       }
+
        kvm_chardev_ops.owner = module;
 
        r = misc_register(&kvm_dev);
@@ -3151,9 +3560,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
                goto out_free;
        }
 
+       kvm_preempt_ops.sched_in = kvm_sched_in;
+       kvm_preempt_ops.sched_out = kvm_sched_out;
+
        return r;
 
 out_free:
+       kmem_cache_destroy(kvm_vcpu_cache);
+out_free_4:
        sysdev_unregister(&kvm_sysdev);
 out_free_3:
        sysdev_class_unregister(&kvm_sysdev_class);
@@ -3162,22 +3576,24 @@ out_free_2:
        unregister_cpu_notifier(&kvm_cpu_notifier);
 out_free_1:
        on_each_cpu(hardware_disable, NULL, 0, 1);
-       kvm_arch_ops->hardware_unsetup();
+out_free_0:
+       kvm_x86_ops->hardware_unsetup();
 out:
-       kvm_arch_ops = NULL;
+       kvm_x86_ops = NULL;
        return r;
 }
 
-void kvm_exit_arch(void)
+void kvm_exit_x86(void)
 {
        misc_deregister(&kvm_dev);
+       kmem_cache_destroy(kvm_vcpu_cache);
        sysdev_unregister(&kvm_sysdev);
        sysdev_class_unregister(&kvm_sysdev_class);
        unregister_reboot_notifier(&kvm_reboot_notifier);
        unregister_cpu_notifier(&kvm_cpu_notifier);
        on_each_cpu(hardware_disable, NULL, 0, 1);
-       kvm_arch_ops->hardware_unsetup();
-       kvm_arch_ops = NULL;
+       kvm_x86_ops->hardware_unsetup();
+       kvm_x86_ops = NULL;
 }
 
 static __init int kvm_init(void)
@@ -3220,5 +3636,5 @@ static __exit void kvm_exit(void)
 module_init(kvm_init)
 module_exit(kvm_exit)
 
-EXPORT_SYMBOL_GPL(kvm_init_arch);
-EXPORT_SYMBOL_GPL(kvm_exit_arch);
+EXPORT_SYMBOL_GPL(kvm_init_x86);
+EXPORT_SYMBOL_GPL(kvm_exit_x86);
index a869983d683d1af454a64fd431df715d7bd1ed43..a0e415daef5b0142ba00cf2b5cec9b9e12b53d5b 100644 (file)
@@ -20,7 +20,10 @@ static const u32 host_save_user_msrs[] = {
 #define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
 #define NUM_DB_REGS 4
 
+struct kvm_vcpu;
+
 struct vcpu_svm {
+       struct kvm_vcpu vcpu;
        struct vmcb *vmcb;
        unsigned long vmcb_pa;
        struct svm_cpu_data *svm_data;
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
new file mode 100644 (file)
index 0000000..a190587
--- /dev/null
@@ -0,0 +1,1064 @@
+
+/*
+ * Local APIC virtualization
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright (C) 2007 Novell
+ * Copyright (C) 2007 Intel
+ *
+ * Authors:
+ *   Dor Laor <dor.laor@qumranet.com>
+ *   Gregory Haskins <ghaskins@novell.com>
+ *   Yaozu (Eddie) Dong <eddie.dong@intel.com>
+ *
+ * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "kvm.h"
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/apicdef.h>
+#include <asm/atomic.h>
+#include <asm/div64.h>
+#include "irq.h"
+
+#define PRId64 "d"
+#define PRIx64 "llx"
+#define PRIu64 "u"
+#define PRIo64 "o"
+
+#define APIC_BUS_CYCLE_NS 1
+
+/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
+#define apic_debug(fmt, arg...)
+
+#define APIC_LVT_NUM                   6
+/* 14 is the version for Xeon and Pentium 8.4.8*/
+#define APIC_VERSION                   (0x14UL | ((APIC_LVT_NUM - 1) << 16))
+#define LAPIC_MMIO_LENGTH              (1 << 12)
+/* followed define is not in apicdef.h */
+#define APIC_SHORT_MASK                        0xc0000
+#define APIC_DEST_NOSHORT              0x0
+#define APIC_DEST_MASK                 0x800
+#define MAX_APIC_VECTOR                        256
+
+#define VEC_POS(v) ((v) & (32 - 1))
+#define REG_POS(v) (((v) >> 5) << 4)
+static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
+{
+       return *((u32 *) (apic->regs + reg_off));
+}
+
+static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
+{
+       *((u32 *) (apic->regs + reg_off)) = val;
+}
+
+static inline int apic_test_and_set_vector(int vec, void *bitmap)
+{
+       return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline int apic_test_and_clear_vector(int vec, void *bitmap)
+{
+       return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline void apic_set_vector(int vec, void *bitmap)
+{
+       set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline void apic_clear_vector(int vec, void *bitmap)
+{
+       clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline int apic_hw_enabled(struct kvm_lapic *apic)
+{
+       return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE;
+}
+
+static inline int  apic_sw_enabled(struct kvm_lapic *apic)
+{
+       return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
+}
+
+static inline int apic_enabled(struct kvm_lapic *apic)
+{
+       return apic_sw_enabled(apic) && apic_hw_enabled(apic);
+}
+
+#define LVT_MASK       \
+       (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK)
+
+#define LINT_MASK      \
+       (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
+        APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
+
+static inline int kvm_apic_id(struct kvm_lapic *apic)
+{
+       return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+}
+
+static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
+{
+       return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
+}
+
+static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
+{
+       return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
+}
+
+static inline int apic_lvtt_period(struct kvm_lapic *apic)
+{
+       return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC;
+}
+
+static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
+       LVT_MASK | APIC_LVT_TIMER_PERIODIC,     /* LVTT */
+       LVT_MASK | APIC_MODE_MASK,      /* LVTTHMR */
+       LVT_MASK | APIC_MODE_MASK,      /* LVTPC */
+       LINT_MASK, LINT_MASK,   /* LVT0-1 */
+       LVT_MASK                /* LVTERR */
+};
+
+static int find_highest_vector(void *bitmap)
+{
+       u32 *word = bitmap;
+       int word_offset = MAX_APIC_VECTOR >> 5;
+
+       while ((word_offset != 0) && (word[(--word_offset) << 2] == 0))
+               continue;
+
+       if (likely(!word_offset && !word[0]))
+               return -1;
+       else
+               return fls(word[word_offset << 2]) - 1 + (word_offset << 5);
+}
+
+static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
+{
+       return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
+}
+
+static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
+{
+       apic_clear_vector(vec, apic->regs + APIC_IRR);
+}
+
+static inline int apic_find_highest_irr(struct kvm_lapic *apic)
+{
+       int result;
+
+       result = find_highest_vector(apic->regs + APIC_IRR);
+       ASSERT(result == -1 || result >= 16);
+
+       return result;
+}
+
+int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       int highest_irr;
+
+       if (!apic)
+               return 0;
+       highest_irr = apic_find_highest_irr(apic);
+
+       return highest_irr;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
+
+int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig)
+{
+       if (!apic_test_and_set_irr(vec, apic)) {
+               /* a new pending irq is set in IRR */
+               if (trig)
+                       apic_set_vector(vec, apic->regs + APIC_TMR);
+               else
+                       apic_clear_vector(vec, apic->regs + APIC_TMR);
+               kvm_vcpu_kick(apic->vcpu);
+               return 1;
+       }
+       return 0;
+}
+
+static inline int apic_find_highest_isr(struct kvm_lapic *apic)
+{
+       int result;
+
+       result = find_highest_vector(apic->regs + APIC_ISR);
+       ASSERT(result == -1 || result >= 16);
+
+       return result;
+}
+
+static void apic_update_ppr(struct kvm_lapic *apic)
+{
+       u32 tpr, isrv, ppr;
+       int isr;
+
+       tpr = apic_get_reg(apic, APIC_TASKPRI);
+       isr = apic_find_highest_isr(apic);
+       isrv = (isr != -1) ? isr : 0;
+
+       if ((tpr & 0xf0) >= (isrv & 0xf0))
+               ppr = tpr & 0xff;
+       else
+               ppr = isrv & 0xf0;
+
+       apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
+                  apic, ppr, isr, isrv);
+
+       apic_set_reg(apic, APIC_PROCPRI, ppr);
+}
+
+static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
+{
+       apic_set_reg(apic, APIC_TASKPRI, tpr);
+       apic_update_ppr(apic);
+}
+
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
+{
+       return kvm_apic_id(apic) == dest;
+}
+
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
+{
+       int result = 0;
+       u8 logical_id;
+
+       logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
+
+       switch (apic_get_reg(apic, APIC_DFR)) {
+       case APIC_DFR_FLAT:
+               if (logical_id & mda)
+                       result = 1;
+               break;
+       case APIC_DFR_CLUSTER:
+               if (((logical_id >> 4) == (mda >> 0x4))
+                   && (logical_id & mda & 0xf))
+                       result = 1;
+               break;
+       default:
+               printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n",
+                      apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
+               break;
+       }
+
+       return result;
+}
+
+static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+                          int short_hand, int dest, int dest_mode)
+{
+       int result = 0;
+       struct kvm_lapic *target = vcpu->apic;
+
+       apic_debug("target %p, source %p, dest 0x%x, "
+                  "dest_mode 0x%x, short_hand 0x%x",
+                  target, source, dest, dest_mode, short_hand);
+
+       ASSERT(!target);
+       switch (short_hand) {
+       case APIC_DEST_NOSHORT:
+               if (dest_mode == 0) {
+                       /* Physical mode. */
+                       if ((dest == 0xFF) || (dest == kvm_apic_id(target)))
+                               result = 1;
+               } else
+                       /* Logical mode. */
+                       result = kvm_apic_match_logical_addr(target, dest);
+               break;
+       case APIC_DEST_SELF:
+               if (target == source)
+                       result = 1;
+               break;
+       case APIC_DEST_ALLINC:
+               result = 1;
+               break;
+       case APIC_DEST_ALLBUT:
+               if (target != source)
+                       result = 1;
+               break;
+       default:
+               printk(KERN_WARNING "Bad dest shorthand value %x\n",
+                      short_hand);
+               break;
+       }
+
+       return result;
+}
+
+/*
+ * Add a pending IRQ into lapic.
+ * Return 1 if successfully added and 0 if discarded.
+ */
+static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
+                            int vector, int level, int trig_mode)
+{
+       int orig_irr, result = 0;
+       struct kvm_vcpu *vcpu = apic->vcpu;
+
+       switch (delivery_mode) {
+       case APIC_DM_FIXED:
+       case APIC_DM_LOWEST:
+               /* FIXME add logic for vcpu on reset */
+               if (unlikely(!apic_enabled(apic)))
+                       break;
+
+               orig_irr = apic_test_and_set_irr(vector, apic);
+               if (orig_irr && trig_mode) {
+                       apic_debug("level trig mode repeatedly for vector %d",
+                                  vector);
+                       break;
+               }
+
+               if (trig_mode) {
+                       apic_debug("level trig mode for vector %d", vector);
+                       apic_set_vector(vector, apic->regs + APIC_TMR);
+               } else
+                       apic_clear_vector(vector, apic->regs + APIC_TMR);
+
+               if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+                       kvm_vcpu_kick(vcpu);
+               else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) {
+                       vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+                       if (waitqueue_active(&vcpu->wq))
+                               wake_up_interruptible(&vcpu->wq);
+               }
+
+               result = (orig_irr == 0);
+               break;
+
+       case APIC_DM_REMRD:
+               printk(KERN_DEBUG "Ignoring delivery mode 3\n");
+               break;
+
+       case APIC_DM_SMI:
+               printk(KERN_DEBUG "Ignoring guest SMI\n");
+               break;
+       case APIC_DM_NMI:
+               printk(KERN_DEBUG "Ignoring guest NMI\n");
+               break;
+
+       case APIC_DM_INIT:
+               if (level) {
+                       if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+                               printk(KERN_DEBUG
+                                      "INIT on a runnable vcpu %d\n",
+                                      vcpu->vcpu_id);
+                       vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED;
+                       kvm_vcpu_kick(vcpu);
+               } else {
+                       printk(KERN_DEBUG
+                              "Ignoring de-assert INIT to vcpu %d\n",
+                              vcpu->vcpu_id);
+               }
+
+               break;
+
+       case APIC_DM_STARTUP:
+               printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n",
+                      vcpu->vcpu_id, vector);
+               if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) {
+                       vcpu->sipi_vector = vector;
+                       vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED;
+                       if (waitqueue_active(&vcpu->wq))
+                               wake_up_interruptible(&vcpu->wq);
+               }
+               break;
+
+       default:
+               printk(KERN_ERR "TODO: unsupported delivery mode %x\n",
+                      delivery_mode);
+               break;
+       }
+       return result;
+}
+
+struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
+                                      unsigned long bitmap)
+{
+       int vcpu_id;
+       int last;
+       int next;
+       struct kvm_lapic *apic;
+
+       last = kvm->round_robin_prev_vcpu;
+       next = last;
+
+       do {
+               if (++next == KVM_MAX_VCPUS)
+                       next = 0;
+               if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
+                       continue;
+               apic = kvm->vcpus[next]->apic;
+               if (apic && apic_enabled(apic))
+                       break;
+               apic = NULL;
+       } while (next != last);
+       kvm->round_robin_prev_vcpu = next;
+
+       if (!apic) {
+               vcpu_id = ffs(bitmap) - 1;
+               if (vcpu_id < 0) {
+                       vcpu_id = 0;
+                       printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
+               }
+               apic = kvm->vcpus[vcpu_id]->apic;
+       }
+
+       return apic;
+}
+
+static void apic_set_eoi(struct kvm_lapic *apic)
+{
+       int vector = apic_find_highest_isr(apic);
+
+       /*
+        * Not every write EOI will has corresponding ISR,
+        * one example is when Kernel check timer on setup_IO_APIC
+        */
+       if (vector == -1)
+               return;
+
+       apic_clear_vector(vector, apic->regs + APIC_ISR);
+       apic_update_ppr(apic);
+
+       if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
+               kvm_ioapic_update_eoi(apic->vcpu->kvm, vector);
+}
+
+static void apic_send_ipi(struct kvm_lapic *apic)
+{
+       u32 icr_low = apic_get_reg(apic, APIC_ICR);
+       u32 icr_high = apic_get_reg(apic, APIC_ICR2);
+
+       unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
+       unsigned int short_hand = icr_low & APIC_SHORT_MASK;
+       unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
+       unsigned int level = icr_low & APIC_INT_ASSERT;
+       unsigned int dest_mode = icr_low & APIC_DEST_MASK;
+       unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
+       unsigned int vector = icr_low & APIC_VECTOR_MASK;
+
+       struct kvm_lapic *target;
+       struct kvm_vcpu *vcpu;
+       unsigned long lpr_map = 0;
+       int i;
+
+       apic_debug("icr_high 0x%x, icr_low 0x%x, "
+                  "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
+                  "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
+                  icr_high, icr_low, short_hand, dest,
+                  trig_mode, level, dest_mode, delivery_mode, vector);
+
+       for (i = 0; i < KVM_MAX_VCPUS; i++) {
+               vcpu = apic->vcpu->kvm->vcpus[i];
+               if (!vcpu)
+                       continue;
+
+               if (vcpu->apic &&
+                   apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
+                       if (delivery_mode == APIC_DM_LOWEST)
+                               set_bit(vcpu->vcpu_id, &lpr_map);
+                       else
+                               __apic_accept_irq(vcpu->apic, delivery_mode,
+                                                 vector, level, trig_mode);
+               }
+       }
+
+       if (delivery_mode == APIC_DM_LOWEST) {
+               target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map);
+               if (target != NULL)
+                       __apic_accept_irq(target, delivery_mode,
+                                         vector, level, trig_mode);
+       }
+}
+
+static u32 apic_get_tmcct(struct kvm_lapic *apic)
+{
+       u32 counter_passed;
+       ktime_t passed, now = apic->timer.dev.base->get_time();
+       u32 tmcct = apic_get_reg(apic, APIC_TMICT);
+
+       ASSERT(apic != NULL);
+
+       if (unlikely(ktime_to_ns(now) <=
+               ktime_to_ns(apic->timer.last_update))) {
+               /* Wrap around */
+               passed = ktime_add(( {
+                                   (ktime_t) {
+                                   .tv64 = KTIME_MAX -
+                                   (apic->timer.last_update).tv64}; }
+                                  ), now);
+               apic_debug("time elapsed\n");
+       } else
+               passed = ktime_sub(now, apic->timer.last_update);
+
+       counter_passed = div64_64(ktime_to_ns(passed),
+                                 (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+       tmcct -= counter_passed;
+
+       if (tmcct <= 0) {
+               if (unlikely(!apic_lvtt_period(apic)))
+                       tmcct = 0;
+               else
+                       do {
+                               tmcct += apic_get_reg(apic, APIC_TMICT);
+                       } while (tmcct <= 0);
+       }
+
+       return tmcct;
+}
+
+static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
+{
+       u32 val = 0;
+
+       if (offset >= LAPIC_MMIO_LENGTH)
+               return 0;
+
+       switch (offset) {
+       case APIC_ARBPRI:
+               printk(KERN_WARNING "Access APIC ARBPRI register "
+                      "which is for P6\n");
+               break;
+
+       case APIC_TMCCT:        /* Timer CCR */
+               val = apic_get_tmcct(apic);
+               break;
+
+       default:
+               apic_update_ppr(apic);
+               val = apic_get_reg(apic, offset);
+               break;
+       }
+
+       return val;
+}
+
+static void apic_mmio_read(struct kvm_io_device *this,
+                          gpa_t address, int len, void *data)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+       unsigned int offset = address - apic->base_address;
+       unsigned char alignment = offset & 0xf;
+       u32 result;
+
+       if ((alignment + len) > 4) {
+               printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d",
+                      (unsigned long)address, len);
+               return;
+       }
+       result = __apic_read(apic, offset & ~0xf);
+
+       switch (len) {
+       case 1:
+       case 2:
+       case 4:
+               memcpy(data, (char *)&result + alignment, len);
+               break;
+       default:
+               printk(KERN_ERR "Local APIC read with len = %x, "
+                      "should be 1,2, or 4 instead\n", len);
+               break;
+       }
+}
+
+static void update_divide_count(struct kvm_lapic *apic)
+{
+       u32 tmp1, tmp2, tdcr;
+
+       tdcr = apic_get_reg(apic, APIC_TDCR);
+       tmp1 = tdcr & 0xf;
+       tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
+       apic->timer.divide_count = 0x1 << (tmp2 & 0x7);
+
+       apic_debug("timer divide count is 0x%x\n",
+                                  apic->timer.divide_count);
+}
+
+static void start_apic_timer(struct kvm_lapic *apic)
+{
+       ktime_t now = apic->timer.dev.base->get_time();
+
+       apic->timer.last_update = now;
+
+       apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
+                   APIC_BUS_CYCLE_NS * apic->timer.divide_count;
+       atomic_set(&apic->timer.pending, 0);
+       hrtimer_start(&apic->timer.dev,
+                     ktime_add_ns(now, apic->timer.period),
+                     HRTIMER_MODE_ABS);
+
+       apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
+                          PRIx64 ", "
+                          "timer initial count 0x%x, period %lldns, "
+                          "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__,
+                          APIC_BUS_CYCLE_NS, ktime_to_ns(now),
+                          apic_get_reg(apic, APIC_TMICT),
+                          apic->timer.period,
+                          ktime_to_ns(ktime_add_ns(now,
+                                       apic->timer.period)));
+}
+
+static void apic_mmio_write(struct kvm_io_device *this,
+                           gpa_t address, int len, const void *data)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+       unsigned int offset = address - apic->base_address;
+       unsigned char alignment = offset & 0xf;
+       u32 val;
+
+       /*
+        * APIC register must be aligned on 128-bits boundary.
+        * 32/64/128 bits registers must be accessed thru 32 bits.
+        * Refer SDM 8.4.1
+        */
+       if (len != 4 || alignment) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "apic write: bad size=%d %lx\n",
+                              len, (long)address);
+               return;
+       }
+
+       val = *(u32 *) data;
+
+       /* too common printing */
+       if (offset != APIC_EOI)
+               apic_debug("%s: offset 0x%x with length 0x%x, and value is "
+                          "0x%x\n", __FUNCTION__, offset, len, val);
+
+       offset &= 0xff0;
+
+       switch (offset) {
+       case APIC_ID:           /* Local APIC ID */
+               apic_set_reg(apic, APIC_ID, val);
+               break;
+
+       case APIC_TASKPRI:
+               apic_set_tpr(apic, val & 0xff);
+               break;
+
+       case APIC_EOI:
+               apic_set_eoi(apic);
+               break;
+
+       case APIC_LDR:
+               apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK);
+               break;
+
+       case APIC_DFR:
+               apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
+               break;
+
+       case APIC_SPIV:
+               apic_set_reg(apic, APIC_SPIV, val & 0x3ff);
+               if (!(val & APIC_SPIV_APIC_ENABLED)) {
+                       int i;
+                       u32 lvt_val;
+
+                       for (i = 0; i < APIC_LVT_NUM; i++) {
+                               lvt_val = apic_get_reg(apic,
+                                                      APIC_LVTT + 0x10 * i);
+                               apic_set_reg(apic, APIC_LVTT + 0x10 * i,
+                                            lvt_val | APIC_LVT_MASKED);
+                       }
+                       atomic_set(&apic->timer.pending, 0);
+
+               }
+               break;
+
+       case APIC_ICR:
+               /* No delay here, so we always clear the pending bit */
+               apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
+               apic_send_ipi(apic);
+               break;
+
+       case APIC_ICR2:
+               apic_set_reg(apic, APIC_ICR2, val & 0xff000000);
+               break;
+
+       case APIC_LVTT:
+       case APIC_LVTTHMR:
+       case APIC_LVTPC:
+       case APIC_LVT0:
+       case APIC_LVT1:
+       case APIC_LVTERR:
+               /* TODO: Check vector */
+               if (!apic_sw_enabled(apic))
+                       val |= APIC_LVT_MASKED;
+
+               val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4];
+               apic_set_reg(apic, offset, val);
+
+               break;
+
+       case APIC_TMICT:
+               hrtimer_cancel(&apic->timer.dev);
+               apic_set_reg(apic, APIC_TMICT, val);
+               start_apic_timer(apic);
+               return;
+
+       case APIC_TDCR:
+               if (val & 4)
+                       printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val);
+               apic_set_reg(apic, APIC_TDCR, val);
+               update_divide_count(apic);
+               break;
+
+       default:
+               apic_debug("Local APIC Write to read-only register %x\n",
+                          offset);
+               break;
+       }
+
+}
+
+static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+       int ret = 0;
+
+
+       if (apic_hw_enabled(apic) &&
+           (addr >= apic->base_address) &&
+           (addr < (apic->base_address + LAPIC_MMIO_LENGTH)))
+               ret = 1;
+
+       return ret;
+}
+
+void kvm_free_apic(struct kvm_lapic *apic)
+{
+       if (!apic)
+               return;
+
+       hrtimer_cancel(&apic->timer.dev);
+
+       if (apic->regs_page) {
+               __free_page(apic->regs_page);
+               apic->regs_page = 0;
+       }
+
+       kfree(apic);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * LAPIC interface
+ *----------------------------------------------------------------------
+ */
+
+void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+
+       if (!apic)
+               return;
+       apic_set_tpr(apic, ((cr8 & 0x0f) << 4));
+}
+
+u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       u64 tpr;
+
+       if (!apic)
+               return 0;
+       tpr = (u64) apic_get_reg(apic, APIC_TASKPRI);
+
+       return (tpr & 0xf0) >> 4;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8);
+
+void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+
+       if (!apic) {
+               value |= MSR_IA32_APICBASE_BSP;
+               vcpu->apic_base = value;
+               return;
+       }
+       if (apic->vcpu->vcpu_id)
+               value &= ~MSR_IA32_APICBASE_BSP;
+
+       vcpu->apic_base = value;
+       apic->base_address = apic->vcpu->apic_base &
+                            MSR_IA32_APICBASE_BASE;
+
+       /* with FSB delivery interrupt, we can restart APIC functionality */
+       apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
+                  "0x%lx.\n", apic->apic_base, apic->base_address);
+
+}
+
+u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu)
+{
+       return vcpu->apic_base;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_get_base);
+
+void kvm_lapic_reset(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic;
+       int i;
+
+       apic_debug("%s\n", __FUNCTION__);
+
+       ASSERT(vcpu);
+       apic = vcpu->apic;
+       ASSERT(apic != NULL);
+
+       /* Stop the timer in case it's a reset to an active apic */
+       hrtimer_cancel(&apic->timer.dev);
+
+       apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
+       apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+
+       for (i = 0; i < APIC_LVT_NUM; i++)
+               apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
+       apic_set_reg(apic, APIC_LVT0,
+                    SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
+
+       apic_set_reg(apic, APIC_DFR, 0xffffffffU);
+       apic_set_reg(apic, APIC_SPIV, 0xff);
+       apic_set_reg(apic, APIC_TASKPRI, 0);
+       apic_set_reg(apic, APIC_LDR, 0);
+       apic_set_reg(apic, APIC_ESR, 0);
+       apic_set_reg(apic, APIC_ICR, 0);
+       apic_set_reg(apic, APIC_ICR2, 0);
+       apic_set_reg(apic, APIC_TDCR, 0);
+       apic_set_reg(apic, APIC_TMICT, 0);
+       for (i = 0; i < 8; i++) {
+               apic_set_reg(apic, APIC_IRR + 0x10 * i, 0);
+               apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
+               apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
+       }
+       apic->timer.divide_count = 0;
+       atomic_set(&apic->timer.pending, 0);
+       if (vcpu->vcpu_id == 0)
+               vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+       apic_update_ppr(apic);
+
+       apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
+                  "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__,
+                  vcpu, kvm_apic_id(apic),
+                  vcpu->apic_base, apic->base_address);
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_reset);
+
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       int ret = 0;
+
+       if (!apic)
+               return 0;
+       ret = apic_enabled(apic);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
+
+/*
+ *----------------------------------------------------------------------
+ * timer interface
+ *----------------------------------------------------------------------
+ */
+
+/* TODO: make sure __apic_timer_fn runs in current pCPU */
+static int __apic_timer_fn(struct kvm_lapic *apic)
+{
+       int result = 0;
+       wait_queue_head_t *q = &apic->vcpu->wq;
+
+       atomic_inc(&apic->timer.pending);
+       if (waitqueue_active(q))
+       {
+               apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+               wake_up_interruptible(q);
+       }
+       if (apic_lvtt_period(apic)) {
+               result = 1;
+               apic->timer.dev.expires = ktime_add_ns(
+                                       apic->timer.dev.expires,
+                                       apic->timer.period);
+       }
+       return result;
+}
+
+static int __inject_apic_timer_irq(struct kvm_lapic *apic)
+{
+       int vector;
+
+       vector = apic_lvt_vector(apic, APIC_LVTT);
+       return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
+}
+
+static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
+{
+       struct kvm_lapic *apic;
+       int restart_timer = 0;
+
+       apic = container_of(data, struct kvm_lapic, timer.dev);
+
+       restart_timer = __apic_timer_fn(apic);
+
+       if (restart_timer)
+               return HRTIMER_RESTART;
+       else
+               return HRTIMER_NORESTART;
+}
+
+int kvm_create_lapic(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic;
+
+       ASSERT(vcpu != NULL);
+       apic_debug("apic_init %d\n", vcpu->vcpu_id);
+
+       apic = kzalloc(sizeof(*apic), GFP_KERNEL);
+       if (!apic)
+               goto nomem;
+
+       vcpu->apic = apic;
+
+       apic->regs_page = alloc_page(GFP_KERNEL);
+       if (apic->regs_page == NULL) {
+               printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
+                      vcpu->vcpu_id);
+               goto nomem;
+       }
+       apic->regs = page_address(apic->regs_page);
+       memset(apic->regs, 0, PAGE_SIZE);
+       apic->vcpu = vcpu;
+
+       hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       apic->timer.dev.function = apic_timer_fn;
+       apic->base_address = APIC_DEFAULT_PHYS_BASE;
+       vcpu->apic_base = APIC_DEFAULT_PHYS_BASE;
+
+       kvm_lapic_reset(vcpu);
+       apic->dev.read = apic_mmio_read;
+       apic->dev.write = apic_mmio_write;
+       apic->dev.in_range = apic_mmio_range;
+       apic->dev.private = apic;
+
+       return 0;
+nomem:
+       kvm_free_apic(apic);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_create_lapic);
+
+int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+       int highest_irr;
+
+       if (!apic || !apic_enabled(apic))
+               return -1;
+
+       apic_update_ppr(apic);
+       highest_irr = apic_find_highest_irr(apic);
+       if ((highest_irr == -1) ||
+           ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)))
+               return -1;
+       return highest_irr;
+}
+
+int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
+{
+       u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0);
+       int r = 0;
+
+       if (vcpu->vcpu_id == 0) {
+               if (!apic_hw_enabled(vcpu->apic))
+                       r = 1;
+               if ((lvt0 & APIC_LVT_MASKED) == 0 &&
+                   GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
+                       r = 1;
+       }
+       return r;
+}
+
+void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+
+       if (apic && apic_lvt_enabled(apic, APIC_LVTT) &&
+               atomic_read(&apic->timer.pending) > 0) {
+               if (__inject_apic_timer_irq(apic))
+                       atomic_dec(&apic->timer.pending);
+       }
+}
+
+void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+
+       if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
+               apic->timer.last_update = ktime_add_ns(
+                               apic->timer.last_update,
+                               apic->timer.period);
+}
+
+int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
+{
+       int vector = kvm_apic_has_interrupt(vcpu);
+       struct kvm_lapic *apic = vcpu->apic;
+
+       if (vector == -1)
+               return -1;
+
+       apic_set_vector(vector, apic->regs + APIC_ISR);
+       apic_update_ppr(apic);
+       apic_clear_irr(vector, apic);
+       return vector;
+}
+
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+
+       apic->base_address = vcpu->apic_base &
+                            MSR_IA32_APICBASE_BASE;
+       apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+       apic_update_ppr(apic);
+       hrtimer_cancel(&apic->timer.dev);
+       update_divide_count(apic);
+       start_apic_timer(apic);
+}
+
+void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+       struct hrtimer *timer;
+
+       if (!apic)
+               return;
+
+       timer = &apic->timer.dev;
+       if (hrtimer_cancel(timer))
+               hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS);
+}
+EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer);
index 23965aa5ee7807315aebecf5b03d0970fbd1efbe..6d84d30f5ed00aea64d11214ead90a15fcbb1ded 100644 (file)
@@ -158,7 +158,7 @@ static struct kmem_cache *mmu_page_header_cache;
 
 static int is_write_protection(struct kvm_vcpu *vcpu)
 {
-       return vcpu->cr0 & CR0_WP_MASK;
+       return vcpu->cr0 & X86_CR0_WP;
 }
 
 static int is_cpuid_PSE36(void)
@@ -202,15 +202,14 @@ static void set_shadow_pte(u64 *sptep, u64 spte)
 }
 
 static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
-                                 struct kmem_cache *base_cache, int min,
-                                 gfp_t gfp_flags)
+                                 struct kmem_cache *base_cache, int min)
 {
        void *obj;
 
        if (cache->nobjs >= min)
                return 0;
        while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
-               obj = kmem_cache_zalloc(base_cache, gfp_flags);
+               obj = kmem_cache_zalloc(base_cache, GFP_KERNEL);
                if (!obj)
                        return -ENOMEM;
                cache->objects[cache->nobjs++] = obj;
@@ -225,14 +224,14 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
 }
 
 static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
-                                      int min, gfp_t gfp_flags)
+                                      int min)
 {
        struct page *page;
 
        if (cache->nobjs >= min)
                return 0;
        while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
-               page = alloc_page(gfp_flags);
+               page = alloc_page(GFP_KERNEL);
                if (!page)
                        return -ENOMEM;
                set_page_private(page, 0);
@@ -247,44 +246,28 @@ static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
                free_page((unsigned long)mc->objects[--mc->nobjs]);
 }
 
-static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
+static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
 {
        int r;
 
+       kvm_mmu_free_some_pages(vcpu);
        r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache,
-                                  pte_chain_cache, 4, gfp_flags);
+                                  pte_chain_cache, 4);
        if (r)
                goto out;
        r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
-                                  rmap_desc_cache, 1, gfp_flags);
+                                  rmap_desc_cache, 1);
        if (r)
                goto out;
-       r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
+       r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4);
        if (r)
                goto out;
        r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
-                                  mmu_page_header_cache, 4, gfp_flags);
+                                  mmu_page_header_cache, 4);
 out:
        return r;
 }
 
-static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
-{
-       int r;
-
-       r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
-       kvm_mmu_free_some_pages(vcpu);
-       if (r < 0) {
-               spin_unlock(&vcpu->kvm->lock);
-               kvm_arch_ops->vcpu_put(vcpu);
-               r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
-               kvm_arch_ops->vcpu_load(vcpu);
-               spin_lock(&vcpu->kvm->lock);
-               kvm_mmu_free_some_pages(vcpu);
-       }
-       return r;
-}
-
 static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 {
        mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
@@ -969,7 +952,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
 static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
 {
        ++vcpu->stat.tlb_flush;
-       kvm_arch_ops->tlb_flush(vcpu);
+       kvm_x86_ops->tlb_flush(vcpu);
 }
 
 static void paging_new_cr3(struct kvm_vcpu *vcpu)
@@ -982,7 +965,7 @@ static void inject_page_fault(struct kvm_vcpu *vcpu,
                              u64 addr,
                              u32 err_code)
 {
-       kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
+       kvm_x86_ops->inject_page_fault(vcpu, addr, err_code);
 }
 
 static void paging_free(struct kvm_vcpu *vcpu)
@@ -1071,15 +1054,15 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
 {
        int r;
 
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        r = mmu_topup_memory_caches(vcpu);
        if (r)
                goto out;
        mmu_alloc_roots(vcpu);
-       kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
+       kvm_x86_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
        kvm_mmu_flush_tlb(vcpu);
 out:
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
        return r;
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_load);
@@ -1124,7 +1107,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
 }
 
 void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
-                      const u8 *old, const u8 *new, int bytes)
+                      const u8 *new, int bytes)
 {
        gfn_t gfn = gpa >> PAGE_SHIFT;
        struct kvm_mmu_page *page;
index 4b5391c717f8d4ddece1a84883cfb12b2efe3656..6b094b44f8fbb6c4babb91da8662d87c952a40f0 100644 (file)
@@ -58,7 +58,10 @@ struct guest_walker {
        int level;
        gfn_t table_gfn[PT_MAX_FULL_LEVELS];
        pt_element_t *table;
+       pt_element_t pte;
        pt_element_t *ptep;
+       struct page *page;
+       int index;
        pt_element_t inherited_ar;
        gfn_t gfn;
        u32 error_code;
@@ -80,11 +83,14 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
        pgprintk("%s: addr %lx\n", __FUNCTION__, addr);
        walker->level = vcpu->mmu.root_level;
        walker->table = NULL;
+       walker->page = NULL;
+       walker->ptep = NULL;
        root = vcpu->cr3;
 #if PTTYPE == 64
        if (!is_long_mode(vcpu)) {
                walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3];
                root = *walker->ptep;
+               walker->pte = root;
                if (!(root & PT_PRESENT_MASK))
                        goto not_present;
                --walker->level;
@@ -96,10 +102,11 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
                 walker->level - 1, table_gfn);
        slot = gfn_to_memslot(vcpu->kvm, table_gfn);
        hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK);
-       walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0);
+       walker->page = pfn_to_page(hpa >> PAGE_SHIFT);
+       walker->table = kmap_atomic(walker->page, KM_USER0);
 
        ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
-              (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0);
+              (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0);
 
        walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK;
 
@@ -108,6 +115,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
                hpa_t paddr;
 
                ptep = &walker->table[index];
+               walker->index = index;
                ASSERT(((unsigned long)walker->table & PAGE_MASK) ==
                       ((unsigned long)ptep & PAGE_MASK));
 
@@ -148,16 +156,20 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
 
                walker->inherited_ar &= walker->table[index];
                table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
-               paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK);
                kunmap_atomic(walker->table, KM_USER0);
-               walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT),
-                                           KM_USER0);
+               paddr = safe_gpa_to_hpa(vcpu, table_gfn << PAGE_SHIFT);
+               walker->page = pfn_to_page(paddr >> PAGE_SHIFT);
+               walker->table = kmap_atomic(walker->page, KM_USER0);
                --walker->level;
                walker->table_gfn[walker->level - 1 ] = table_gfn;
                pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
                         walker->level - 1, table_gfn);
        }
-       walker->ptep = ptep;
+       walker->pte = *ptep;
+       if (walker->page)
+               walker->ptep = NULL;
+       if (walker->table)
+               kunmap_atomic(walker->table, KM_USER0);
        pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep);
        return 1;
 
@@ -175,13 +187,9 @@ err:
                walker->error_code |= PFERR_USER_MASK;
        if (fetch_fault)
                walker->error_code |= PFERR_FETCH_MASK;
-       return 0;
-}
-
-static void FNAME(release_walker)(struct guest_walker *walker)
-{
        if (walker->table)
                kunmap_atomic(walker->table, KM_USER0);
+       return 0;
 }
 
 static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
@@ -193,7 +201,7 @@ static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
 static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
                                  u64 *shadow_pte,
                                  gpa_t gaddr,
-                                 pt_element_t *gpte,
+                                 pt_element_t gpte,
                                  u64 access_bits,
                                  int user_fault,
                                  int write_fault,
@@ -202,23 +210,34 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
                                  gfn_t gfn)
 {
        hpa_t paddr;
-       int dirty = *gpte & PT_DIRTY_MASK;
+       int dirty = gpte & PT_DIRTY_MASK;
        u64 spte = *shadow_pte;
        int was_rmapped = is_rmap_pte(spte);
 
        pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
                 " user_fault %d gfn %lx\n",
-                __FUNCTION__, spte, (u64)*gpte, access_bits,
+                __FUNCTION__, spte, (u64)gpte, access_bits,
                 write_fault, user_fault, gfn);
 
        if (write_fault && !dirty) {
-               *gpte |= PT_DIRTY_MASK;
+               pt_element_t *guest_ent, *tmp = NULL;
+
+               if (walker->ptep)
+                       guest_ent = walker->ptep;
+               else {
+                       tmp = kmap_atomic(walker->page, KM_USER0);
+                       guest_ent = &tmp[walker->index];
+               }
+
+               *guest_ent |= PT_DIRTY_MASK;
+               if (!walker->ptep)
+                       kunmap_atomic(tmp, KM_USER0);
                dirty = 1;
                FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
        }
 
        spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK;
-       spte |= *gpte & PT64_NX_MASK;
+       spte |= gpte & PT64_NX_MASK;
        if (!dirty)
                access_bits &= ~PT_WRITABLE_MASK;
 
@@ -255,7 +274,7 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
                        access_bits &= ~PT_WRITABLE_MASK;
                        if (is_writeble_pte(spte)) {
                                spte &= ~PT_WRITABLE_MASK;
-                               kvm_arch_ops->tlb_flush(vcpu);
+                               kvm_x86_ops->tlb_flush(vcpu);
                        }
                        if (write_fault)
                                *ptwrite = 1;
@@ -273,13 +292,13 @@ unshadowed:
                rmap_add(vcpu, shadow_pte);
 }
 
-static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t *gpte,
+static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte,
                           u64 *shadow_pte, u64 access_bits,
                           int user_fault, int write_fault, int *ptwrite,
                           struct guest_walker *walker, gfn_t gfn)
 {
-       access_bits &= *gpte;
-       FNAME(set_pte_common)(vcpu, shadow_pte, *gpte & PT_BASE_ADDR_MASK,
+       access_bits &= gpte;
+       FNAME(set_pte_common)(vcpu, shadow_pte, gpte & PT_BASE_ADDR_MASK,
                              gpte, access_bits, user_fault, write_fault,
                              ptwrite, walker, gfn);
 }
@@ -295,22 +314,22 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
        if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK))
                return;
        pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
-       FNAME(set_pte)(vcpu, &gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
+       FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
                       0, NULL, NULL,
                       (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT);
 }
 
-static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t *gpde,
+static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t gpde,
                           u64 *shadow_pte, u64 access_bits,
                           int user_fault, int write_fault, int *ptwrite,
                           struct guest_walker *walker, gfn_t gfn)
 {
        gpa_t gaddr;
 
-       access_bits &= *gpde;
+       access_bits &= gpde;
        gaddr = (gpa_t)gfn << PAGE_SHIFT;
        if (PTTYPE == 32 && is_cpuid_PSE36())
-               gaddr |= (*gpde & PT32_DIR_PSE36_MASK) <<
+               gaddr |= (gpde & PT32_DIR_PSE36_MASK) <<
                        (32 - PT32_DIR_PSE36_SHIFT);
        FNAME(set_pte_common)(vcpu, shadow_pte, gaddr,
                              gpde, access_bits, user_fault, write_fault,
@@ -328,9 +347,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
        int level;
        u64 *shadow_ent;
        u64 *prev_shadow_ent = NULL;
-       pt_element_t *guest_ent = walker->ptep;
 
-       if (!is_present_pte(*guest_ent))
+       if (!is_present_pte(walker->pte))
                return NULL;
 
        shadow_addr = vcpu->mmu.root_hpa;
@@ -364,12 +382,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                if (level - 1 == PT_PAGE_TABLE_LEVEL
                    && walker->level == PT_DIRECTORY_LEVEL) {
                        metaphysical = 1;
-                       hugepage_access = *guest_ent;
+                       hugepage_access = walker->pte;
                        hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
-                       if (*guest_ent & PT64_NX_MASK)
+                       if (walker->pte & PT64_NX_MASK)
                                hugepage_access |= (1 << 2);
                        hugepage_access >>= PT_WRITABLE_SHIFT;
-                       table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
+                       table_gfn = (walker->pte & PT_BASE_ADDR_MASK)
                                >> PAGE_SHIFT;
                } else {
                        metaphysical = 0;
@@ -386,12 +404,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
        }
 
        if (walker->level == PT_DIRECTORY_LEVEL) {
-               FNAME(set_pde)(vcpu, guest_ent, shadow_ent,
+               FNAME(set_pde)(vcpu, walker->pte, shadow_ent,
                               walker->inherited_ar, user_fault, write_fault,
                               ptwrite, walker, walker->gfn);
        } else {
                ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
-               FNAME(set_pte)(vcpu, guest_ent, shadow_ent,
+               FNAME(set_pte)(vcpu, walker->pte, shadow_ent,
                               walker->inherited_ar, user_fault, write_fault,
                               ptwrite, walker, walker->gfn);
        }
@@ -442,7 +460,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
        if (!r) {
                pgprintk("%s: guest page fault\n", __FUNCTION__);
                inject_page_fault(vcpu, addr, walker.error_code);
-               FNAME(release_walker)(&walker);
                vcpu->last_pt_write_count = 0; /* reset fork detector */
                return 0;
        }
@@ -452,8 +469,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
        pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__,
                 shadow_pte, *shadow_pte, write_pt);
 
-       FNAME(release_walker)(&walker);
-
        if (!write_pt)
                vcpu->last_pt_write_count = 0; /* reset fork detector */
 
@@ -482,7 +497,6 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
                gpa |= vaddr & ~PAGE_MASK;
        }
 
-       FNAME(release_walker)(&walker);
        return gpa;
 }
 
index bc818cc126e385f7556df64614062aafc66b1102..729f1cd93606e86315b0330e0c2af7c740b22de6 100644 (file)
 
 #include "kvm_svm.h"
 #include "x86_emulate.h"
+#include "irq.h"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
-#include <linux/profile.h>
 #include <linux/sched.h>
 
 #include <asm/desc.h>
@@ -38,7 +38,6 @@ MODULE_LICENSE("GPL");
 
 #define DR7_GD_MASK (1 << 13)
 #define DR6_BD_MASK (1 << 13)
-#define CR4_DE_MASK (1UL << 3)
 
 #define SEG_TYPE_LDT 2
 #define SEG_TYPE_BUSY_TSS16 3
@@ -50,6 +49,13 @@ MODULE_LICENSE("GPL");
 #define SVM_FEATURE_LBRV (1 << 1)
 #define SVM_DEATURE_SVML (1 << 2)
 
+static void kvm_reput_irq(struct vcpu_svm *svm);
+
+static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
+{
+       return container_of(vcpu, struct vcpu_svm, vcpu);
+}
+
 unsigned long iopm_base;
 unsigned long msrpm_base;
 
@@ -94,20 +100,6 @@ static inline u32 svm_has(u32 feat)
        return svm_features & feat;
 }
 
-static unsigned get_addr_size(struct kvm_vcpu *vcpu)
-{
-       struct vmcb_save_area *sa = &vcpu->svm->vmcb->save;
-       u16 cs_attrib;
-
-       if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM))
-               return 2;
-
-       cs_attrib = sa->cs.attrib;
-
-       return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 :
-                               (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2;
-}
-
 static inline u8 pop_irq(struct kvm_vcpu *vcpu)
 {
        int word_index = __ffs(vcpu->irq_summary);
@@ -182,7 +174,7 @@ static inline void write_dr7(unsigned long val)
 
 static inline void force_new_asid(struct kvm_vcpu *vcpu)
 {
-       vcpu->svm->asid_generation--;
+       to_svm(vcpu)->asid_generation--;
 }
 
 static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
@@ -195,22 +187,24 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
        if (!(efer & KVM_EFER_LMA))
                efer &= ~KVM_EFER_LME;
 
-       vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
+       to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
        vcpu->shadow_efer = efer;
 }
 
 static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
 {
-       vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm->vmcb->control.event_inj =          SVM_EVTINJ_VALID |
                                                SVM_EVTINJ_VALID_ERR |
                                                SVM_EVTINJ_TYPE_EXEPT |
                                                GP_VECTOR;
-       vcpu->svm->vmcb->control.event_inj_err = error_code;
+       svm->vmcb->control.event_inj_err = error_code;
 }
 
 static void inject_ud(struct kvm_vcpu *vcpu)
 {
-       vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
+       to_svm(vcpu)->vmcb->control.event_inj = SVM_EVTINJ_VALID |
                                                SVM_EVTINJ_TYPE_EXEPT |
                                                UD_VECTOR;
 }
@@ -229,19 +223,21 @@ static int is_external_interrupt(u32 info)
 
 static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->svm->next_rip) {
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (!svm->next_rip) {
                printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__);
                return;
        }
-       if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) {
+       if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) {
                printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n",
                       __FUNCTION__,
-                      vcpu->svm->vmcb->save.rip,
-                      vcpu->svm->next_rip);
+                      svm->vmcb->save.rip,
+                      svm->next_rip);
        }
 
-       vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip;
-       vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+       vcpu->rip = svm->vmcb->save.rip = svm->next_rip;
+       svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
 
        vcpu->interrupt_window_open = 1;
 }
@@ -351,8 +347,8 @@ err_1:
 
 }
 
-static int set_msr_interception(u32 *msrpm, unsigned msr,
-                               int read, int write)
+static void set_msr_interception(u32 *msrpm, unsigned msr,
+                                int read, int write)
 {
        int i;
 
@@ -367,11 +363,10 @@ static int set_msr_interception(u32 *msrpm, unsigned msr,
                        u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1);
                        *base = (*base & ~(0x3 << msr_shift)) |
                                (mask << msr_shift);
-                       return 1;
+                       return;
                }
        }
-       printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr);
-       return 0;
+       BUG();
 }
 
 static __init int svm_hardware_setup(void)
@@ -382,8 +377,6 @@ static __init int svm_hardware_setup(void)
        void *iopm_va, *msrpm_va;
        int r;
 
-       kvm_emulator_want_group7_invlpg();
-
        iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
 
        if (!iopm_pages)
@@ -458,11 +451,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
        seg->base = 0;
 }
 
-static int svm_vcpu_setup(struct kvm_vcpu *vcpu)
-{
-       return 0;
-}
-
 static void init_vmcb(struct vmcb *vmcb)
 {
        struct vmcb_control_area *control = &vmcb->control;
@@ -563,59 +551,83 @@ static void init_vmcb(struct vmcb *vmcb)
         * cr0 val on cpu init should be 0x60000010, we enable cpu
         * cache by default. the orderly way is to enable cache in bios.
         */
-       save->cr0 = 0x00000010 | CR0_PG_MASK | CR0_WP_MASK;
-       save->cr4 = CR4_PAE_MASK;
+       save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP;
+       save->cr4 = X86_CR4_PAE;
        /* rdx = ?? */
 }
 
-static int svm_create_vcpu(struct kvm_vcpu *vcpu)
+static void svm_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       init_vmcb(svm->vmcb);
+}
+
+static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
 {
+       struct vcpu_svm *svm;
        struct page *page;
-       int r;
+       int err;
+
+       svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+       if (!svm) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = kvm_vcpu_init(&svm->vcpu, kvm, id);
+       if (err)
+               goto free_svm;
+
+       if (irqchip_in_kernel(kvm)) {
+               err = kvm_create_lapic(&svm->vcpu);
+               if (err < 0)
+                       goto free_svm;
+       }
 
-       r = -ENOMEM;
-       vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL);
-       if (!vcpu->svm)
-               goto out1;
        page = alloc_page(GFP_KERNEL);
-       if (!page)
-               goto out2;
-
-       vcpu->svm->vmcb = page_address(page);
-       clear_page(vcpu->svm->vmcb);
-       vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
-       vcpu->svm->asid_generation = 0;
-       memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
-       init_vmcb(vcpu->svm->vmcb);
-
-       fx_init(vcpu);
-       vcpu->fpu_active = 1;
-       vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
-       if (vcpu == &vcpu->kvm->vcpus[0])
-               vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+       if (!page) {
+               err = -ENOMEM;
+               goto uninit;
+       }
 
-       return 0;
+       svm->vmcb = page_address(page);
+       clear_page(svm->vmcb);
+       svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
+       svm->asid_generation = 0;
+       memset(svm->db_regs, 0, sizeof(svm->db_regs));
+       init_vmcb(svm->vmcb);
 
-out2:
-       kfree(vcpu->svm);
-out1:
-       return r;
+       fx_init(&svm->vcpu);
+       svm->vcpu.fpu_active = 1;
+       svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+       if (svm->vcpu.vcpu_id == 0)
+               svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP;
+
+       return &svm->vcpu;
+
+uninit:
+       kvm_vcpu_uninit(&svm->vcpu);
+free_svm:
+       kmem_cache_free(kvm_vcpu_cache, svm);
+out:
+       return ERR_PTR(err);
 }
 
 static void svm_free_vcpu(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->svm)
-               return;
-       if (vcpu->svm->vmcb)
-               __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT));
-       kfree(vcpu->svm);
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
+       kvm_vcpu_uninit(vcpu);
+       kmem_cache_free(kvm_vcpu_cache, svm);
 }
 
-static void svm_vcpu_load(struct kvm_vcpu *vcpu)
+static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
-       int cpu, i;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       int i;
 
-       cpu = get_cpu();
        if (unlikely(cpu != vcpu->cpu)) {
                u64 tsc_this, delta;
 
@@ -625,23 +637,24 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu)
                 */
                rdtscll(tsc_this);
                delta = vcpu->host_tsc - tsc_this;
-               vcpu->svm->vmcb->control.tsc_offset += delta;
+               svm->vmcb->control.tsc_offset += delta;
                vcpu->cpu = cpu;
+               kvm_migrate_apic_timer(vcpu);
        }
 
        for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
-               rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+               rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 }
 
 static void svm_vcpu_put(struct kvm_vcpu *vcpu)
 {
+       struct vcpu_svm *svm = to_svm(vcpu);
        int i;
 
        for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
-               wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+               wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 
        rdtscll(vcpu->host_tsc);
-       put_cpu();
 }
 
 static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
@@ -650,31 +663,34 @@ static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
 
 static void svm_cache_regs(struct kvm_vcpu *vcpu)
 {
-       vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax;
-       vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp;
-       vcpu->rip = vcpu->svm->vmcb->save.rip;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       vcpu->regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
+       vcpu->regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
+       vcpu->rip = svm->vmcb->save.rip;
 }
 
 static void svm_decache_regs(struct kvm_vcpu *vcpu)
 {
-       vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
-       vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
-       vcpu->svm->vmcb->save.rip = vcpu->rip;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
+       svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
+       svm->vmcb->save.rip = vcpu->rip;
 }
 
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
 {
-       return vcpu->svm->vmcb->save.rflags;
+       return to_svm(vcpu)->vmcb->save.rflags;
 }
 
 static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
-       vcpu->svm->vmcb->save.rflags = rflags;
+       to_svm(vcpu)->vmcb->save.rflags = rflags;
 }
 
 static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
 {
-       struct vmcb_save_area *save = &vcpu->svm->vmcb->save;
+       struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save;
 
        switch (seg) {
        case VCPU_SREG_CS: return &save->cs;
@@ -716,36 +732,36 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
        var->unusable = !var->present;
 }
 
-static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
-{
-       struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS);
-
-       *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
-       *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
-}
-
 static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
 {
-       dt->limit = vcpu->svm->vmcb->save.idtr.limit;
-       dt->base = vcpu->svm->vmcb->save.idtr.base;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       dt->limit = svm->vmcb->save.idtr.limit;
+       dt->base = svm->vmcb->save.idtr.base;
 }
 
 static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
 {
-       vcpu->svm->vmcb->save.idtr.limit = dt->limit;
-       vcpu->svm->vmcb->save.idtr.base = dt->base ;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm->vmcb->save.idtr.limit = dt->limit;
+       svm->vmcb->save.idtr.base = dt->base ;
 }
 
 static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
 {
-       dt->limit = vcpu->svm->vmcb->save.gdtr.limit;
-       dt->base = vcpu->svm->vmcb->save.gdtr.base;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       dt->limit = svm->vmcb->save.gdtr.limit;
+       dt->base = svm->vmcb->save.gdtr.base;
 }
 
 static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
 {
-       vcpu->svm->vmcb->save.gdtr.limit = dt->limit;
-       vcpu->svm->vmcb->save.gdtr.base = dt->base ;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm->vmcb->save.gdtr.limit = dt->limit;
+       svm->vmcb->save.gdtr.base = dt->base ;
 }
 
 static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
@@ -754,39 +770,42 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 
 static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
+       struct vcpu_svm *svm = to_svm(vcpu);
+
 #ifdef CONFIG_X86_64
        if (vcpu->shadow_efer & KVM_EFER_LME) {
-               if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+               if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
                        vcpu->shadow_efer |= KVM_EFER_LMA;
-                       vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
+                       svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
                }
 
-               if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) {
+               if (is_paging(vcpu) && !(cr0 & X86_CR0_PG) ) {
                        vcpu->shadow_efer &= ~KVM_EFER_LMA;
-                       vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
+                       svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
                }
        }
 #endif
-       if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) {
-               vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+       if ((vcpu->cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) {
+               svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
                vcpu->fpu_active = 1;
        }
 
        vcpu->cr0 = cr0;
-       cr0 |= CR0_PG_MASK | CR0_WP_MASK;
-       cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK);
-       vcpu->svm->vmcb->save.cr0 = cr0;
+       cr0 |= X86_CR0_PG | X86_CR0_WP;
+       cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
+       svm->vmcb->save.cr0 = cr0;
 }
 
 static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
        vcpu->cr4 = cr4;
-       vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK;
+       to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE;
 }
 
 static void svm_set_segment(struct kvm_vcpu *vcpu,
                            struct kvm_segment *var, int seg)
 {
+       struct vcpu_svm *svm = to_svm(vcpu);
        struct vmcb_seg *s = svm_seg(vcpu, seg);
 
        s->base = var->base;
@@ -805,16 +824,16 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
                s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
        }
        if (seg == VCPU_SREG_CS)
-               vcpu->svm->vmcb->save.cpl
-                       = (vcpu->svm->vmcb->save.cs.attrib
+               svm->vmcb->save.cpl
+                       = (svm->vmcb->save.cs.attrib
                           >> SVM_SELECTOR_DPL_SHIFT) & 3;
 
 }
 
 /* FIXME:
 
-       vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
-       vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
+       svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK;
+       svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
 
 */
 
@@ -823,61 +842,68 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
        return -EOPNOTSUPP;
 }
 
+static int svm_get_irq(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 exit_int_info = svm->vmcb->control.exit_int_info;
+
+       if (is_external_interrupt(exit_int_info))
+               return exit_int_info & SVM_EVTINJ_VEC_MASK;
+       return -1;
+}
+
 static void load_host_msrs(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_X86_64
-       wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+       wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
 #endif
 }
 
 static void save_host_msrs(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_X86_64
-       rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+       rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
 #endif
 }
 
-static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data)
+static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
 {
        if (svm_data->next_asid > svm_data->max_asid) {
                ++svm_data->asid_generation;
                svm_data->next_asid = 1;
-               vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
+               svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
        }
 
-       vcpu->cpu = svm_data->cpu;
-       vcpu->svm->asid_generation = svm_data->asid_generation;
-       vcpu->svm->vmcb->control.asid = svm_data->next_asid++;
-}
-
-static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address)
-{
-       invlpga(address, vcpu->svm->vmcb->control.asid); // is needed?
+       svm->vcpu.cpu = svm_data->cpu;
+       svm->asid_generation = svm_data->asid_generation;
+       svm->vmcb->control.asid = svm_data->next_asid++;
 }
 
 static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
 {
-       return vcpu->svm->db_regs[dr];
+       return to_svm(vcpu)->db_regs[dr];
 }
 
 static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
                       int *exception)
 {
+       struct vcpu_svm *svm = to_svm(vcpu);
+
        *exception = 0;
 
-       if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) {
-               vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
-               vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK;
+       if (svm->vmcb->save.dr7 & DR7_GD_MASK) {
+               svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
+               svm->vmcb->save.dr6 |= DR6_BD_MASK;
                *exception = DB_VECTOR;
                return;
        }
 
        switch (dr) {
        case 0 ... 3:
-               vcpu->svm->db_regs[dr] = value;
+               svm->db_regs[dr] = value;
                return;
        case 4 ... 5:
-               if (vcpu->cr4 & CR4_DE_MASK) {
+               if (vcpu->cr4 & X86_CR4_DE) {
                        *exception = UD_VECTOR;
                        return;
                }
@@ -886,7 +912,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
                        *exception = GP_VECTOR;
                        return;
                }
-               vcpu->svm->vmcb->save.dr7 = value;
+               svm->vmcb->save.dr7 = value;
                return;
        }
        default:
@@ -897,42 +923,44 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
        }
 }
 
-static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+       u32 exit_int_info = svm->vmcb->control.exit_int_info;
+       struct kvm *kvm = svm->vcpu.kvm;
        u64 fault_address;
        u32 error_code;
        enum emulation_result er;
        int r;
 
-       if (is_external_interrupt(exit_int_info))
-               push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
+       if (!irqchip_in_kernel(kvm) &&
+               is_external_interrupt(exit_int_info))
+               push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
 
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&kvm->lock);
 
-       fault_address  = vcpu->svm->vmcb->control.exit_info_2;
-       error_code = vcpu->svm->vmcb->control.exit_info_1;
-       r = kvm_mmu_page_fault(vcpu, fault_address, error_code);
+       fault_address  = svm->vmcb->control.exit_info_2;
+       error_code = svm->vmcb->control.exit_info_1;
+       r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
        if (r < 0) {
-               spin_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&kvm->lock);
                return r;
        }
        if (!r) {
-               spin_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&kvm->lock);
                return 1;
        }
-       er = emulate_instruction(vcpu, kvm_run, fault_address, error_code);
-       spin_unlock(&vcpu->kvm->lock);
+       er = emulate_instruction(&svm->vcpu, kvm_run, fault_address,
+                                error_code);
+       mutex_unlock(&kvm->lock);
 
        switch (er) {
        case EMULATE_DONE:
                return 1;
        case EMULATE_DO_MMIO:
-               ++vcpu->stat.mmio_exits;
-               kvm_run->exit_reason = KVM_EXIT_MMIO;
+               ++svm->vcpu.stat.mmio_exits;
                return 0;
        case EMULATE_FAIL:
-               vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+               kvm_report_emulation_failure(&svm->vcpu, "pagetable");
                break;
        default:
                BUG();
@@ -942,252 +970,142 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 0;
 }
 
-static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
-       if (!(vcpu->cr0 & CR0_TS_MASK))
-               vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK;
-       vcpu->fpu_active = 1;
+       svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+       if (!(svm->vcpu.cr0 & X86_CR0_TS))
+               svm->vmcb->save.cr0 &= ~X86_CR0_TS;
+       svm->vcpu.fpu_active = 1;
 
-       return 1;
+       return 1;
 }
 
-static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
        /*
         * VMCB is undefined after a SHUTDOWN intercept
         * so reinitialize it.
         */
-       clear_page(vcpu->svm->vmcb);
-       init_vmcb(vcpu->svm->vmcb);
+       clear_page(svm->vmcb);
+       init_vmcb(svm->vmcb);
 
        kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
        return 0;
 }
 
-static int io_get_override(struct kvm_vcpu *vcpu,
-                         struct vmcb_seg **seg,
-                         int *addr_override)
-{
-       u8 inst[MAX_INST_SIZE];
-       unsigned ins_length;
-       gva_t rip;
-       int i;
-
-       rip =  vcpu->svm->vmcb->save.rip;
-       ins_length = vcpu->svm->next_rip - rip;
-       rip += vcpu->svm->vmcb->save.cs.base;
-
-       if (ins_length > MAX_INST_SIZE)
-               printk(KERN_DEBUG
-                      "%s: inst length err, cs base 0x%llx rip 0x%llx "
-                      "next rip 0x%llx ins_length %u\n",
-                      __FUNCTION__,
-                      vcpu->svm->vmcb->save.cs.base,
-                      vcpu->svm->vmcb->save.rip,
-                      vcpu->svm->vmcb->control.exit_info_2,
-                      ins_length);
-
-       if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length)
-               /* #PF */
-               return 0;
-
-       *addr_override = 0;
-       *seg = NULL;
-       for (i = 0; i < ins_length; i++)
-               switch (inst[i]) {
-               case 0xf0:
-               case 0xf2:
-               case 0xf3:
-               case 0x66:
-                       continue;
-               case 0x67:
-                       *addr_override = 1;
-                       continue;
-               case 0x2e:
-                       *seg = &vcpu->svm->vmcb->save.cs;
-                       continue;
-               case 0x36:
-                       *seg = &vcpu->svm->vmcb->save.ss;
-                       continue;
-               case 0x3e:
-                       *seg = &vcpu->svm->vmcb->save.ds;
-                       continue;
-               case 0x26:
-                       *seg = &vcpu->svm->vmcb->save.es;
-                       continue;
-               case 0x64:
-                       *seg = &vcpu->svm->vmcb->save.fs;
-                       continue;
-               case 0x65:
-                       *seg = &vcpu->svm->vmcb->save.gs;
-                       continue;
-               default:
-                       return 1;
-               }
-       printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__);
-       return 0;
-}
-
-static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address)
+static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       unsigned long addr_mask;
-       unsigned long *reg;
-       struct vmcb_seg *seg;
-       int addr_override;
-       struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save;
-       u16 cs_attrib = save_area->cs.attrib;
-       unsigned addr_size = get_addr_size(vcpu);
-
-       if (!io_get_override(vcpu, &seg, &addr_override))
-               return 0;
-
-       if (addr_override)
-               addr_size = (addr_size == 2) ? 4: (addr_size >> 1);
+       u32 io_info = svm->vmcb->control.exit_info_1; //address size bug?
+       int size, down, in, string, rep;
+       unsigned port;
 
-       if (ins) {
-               reg = &vcpu->regs[VCPU_REGS_RDI];
-               seg = &vcpu->svm->vmcb->save.es;
-       } else {
-               reg = &vcpu->regs[VCPU_REGS_RSI];
-               seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds;
-       }
+       ++svm->vcpu.stat.io_exits;
 
-       addr_mask = ~0ULL >> (64 - (addr_size * 8));
+       svm->next_rip = svm->vmcb->control.exit_info_2;
 
-       if ((cs_attrib & SVM_SELECTOR_L_MASK) &&
-           !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) {
-               *address = (*reg & addr_mask);
-               return addr_mask;
-       }
+       string = (io_info & SVM_IOIO_STR_MASK) != 0;
 
-       if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) {
-               svm_inject_gp(vcpu, 0);
-               return 0;
+       if (string) {
+               if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
+                       return 0;
+               return 1;
        }
 
-       *address = (*reg & addr_mask) + seg->base;
-       return addr_mask;
-}
-
-static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-       u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug?
-       int size, down, in, string, rep;
-       unsigned port;
-       unsigned long count;
-       gva_t address = 0;
-
-       ++vcpu->stat.io_exits;
-
-       vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
-
        in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
        port = io_info >> 16;
        size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
-       string = (io_info & SVM_IOIO_STR_MASK) != 0;
        rep = (io_info & SVM_IOIO_REP_MASK) != 0;
-       count = 1;
-       down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
+       down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
 
-       if (string) {
-               unsigned addr_mask;
-
-               addr_mask = io_adress(vcpu, in, &address);
-               if (!addr_mask) {
-                       printk(KERN_DEBUG "%s: get io address failed\n",
-                              __FUNCTION__);
-                       return 1;
-               }
-
-               if (rep)
-                       count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
-       }
-       return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
-                            address, rep, port);
+       return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
 }
 
-static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
        return 1;
 }
 
-static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
-       skip_emulated_instruction(vcpu);
-       return kvm_emulate_halt(vcpu);
+       svm->next_rip = svm->vmcb->save.rip + 1;
+       skip_emulated_instruction(&svm->vcpu);
+       return kvm_emulate_halt(&svm->vcpu);
 }
 
-static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3;
-       skip_emulated_instruction(vcpu);
-       return kvm_hypercall(vcpu, kvm_run);
+       svm->next_rip = svm->vmcb->save.rip + 3;
+       skip_emulated_instruction(&svm->vcpu);
+       return kvm_hypercall(&svm->vcpu, kvm_run);
 }
 
-static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int invalid_op_interception(struct vcpu_svm *svm,
+                                  struct kvm_run *kvm_run)
 {
-       inject_ud(vcpu);
+       inject_ud(&svm->vcpu);
        return 1;
 }
 
-static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int task_switch_interception(struct vcpu_svm *svm,
+                                   struct kvm_run *kvm_run)
 {
-       printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__);
+       pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__);
        kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
        return 0;
 }
 
-static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
-       kvm_emulate_cpuid(vcpu);
+       svm->next_rip = svm->vmcb->save.rip + 2;
+       kvm_emulate_cpuid(&svm->vcpu);
        return 1;
 }
 
-static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int emulate_on_interception(struct vcpu_svm *svm,
+                                  struct kvm_run *kvm_run)
 {
-       if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE)
-               printk(KERN_ERR "%s: failed\n", __FUNCTION__);
+       if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE)
+               pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__);
        return 1;
 }
 
 static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
 {
+       struct vcpu_svm *svm = to_svm(vcpu);
+
        switch (ecx) {
        case MSR_IA32_TIME_STAMP_COUNTER: {
                u64 tsc;
 
                rdtscll(tsc);
-               *data = vcpu->svm->vmcb->control.tsc_offset + tsc;
+               *data = svm->vmcb->control.tsc_offset + tsc;
                break;
        }
        case MSR_K6_STAR:
-               *data = vcpu->svm->vmcb->save.star;
+               *data = svm->vmcb->save.star;
                break;
 #ifdef CONFIG_X86_64
        case MSR_LSTAR:
-               *data = vcpu->svm->vmcb->save.lstar;
+               *data = svm->vmcb->save.lstar;
                break;
        case MSR_CSTAR:
-               *data = vcpu->svm->vmcb->save.cstar;
+               *data = svm->vmcb->save.cstar;
                break;
        case MSR_KERNEL_GS_BASE:
-               *data = vcpu->svm->vmcb->save.kernel_gs_base;
+               *data = svm->vmcb->save.kernel_gs_base;
                break;
        case MSR_SYSCALL_MASK:
-               *data = vcpu->svm->vmcb->save.sfmask;
+               *data = svm->vmcb->save.sfmask;
                break;
 #endif
        case MSR_IA32_SYSENTER_CS:
-               *data = vcpu->svm->vmcb->save.sysenter_cs;
+               *data = svm->vmcb->save.sysenter_cs;
                break;
        case MSR_IA32_SYSENTER_EIP:
-               *data = vcpu->svm->vmcb->save.sysenter_eip;
+               *data = svm->vmcb->save.sysenter_eip;
                break;
        case MSR_IA32_SYSENTER_ESP:
-               *data = vcpu->svm->vmcb->save.sysenter_esp;
+               *data = svm->vmcb->save.sysenter_esp;
                break;
        default:
                return kvm_get_msr_common(vcpu, ecx, data);
@@ -1195,57 +1113,59 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
        return 0;
 }
 
-static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+       u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
        u64 data;
 
-       if (svm_get_msr(vcpu, ecx, &data))
-               svm_inject_gp(vcpu, 0);
+       if (svm_get_msr(&svm->vcpu, ecx, &data))
+               svm_inject_gp(&svm->vcpu, 0);
        else {
-               vcpu->svm->vmcb->save.rax = data & 0xffffffff;
-               vcpu->regs[VCPU_REGS_RDX] = data >> 32;
-               vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
-               skip_emulated_instruction(vcpu);
+               svm->vmcb->save.rax = data & 0xffffffff;
+               svm->vcpu.regs[VCPU_REGS_RDX] = data >> 32;
+               svm->next_rip = svm->vmcb->save.rip + 2;
+               skip_emulated_instruction(&svm->vcpu);
        }
        return 1;
 }
 
 static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
 {
+       struct vcpu_svm *svm = to_svm(vcpu);
+
        switch (ecx) {
        case MSR_IA32_TIME_STAMP_COUNTER: {
                u64 tsc;
 
                rdtscll(tsc);
-               vcpu->svm->vmcb->control.tsc_offset = data - tsc;
+               svm->vmcb->control.tsc_offset = data - tsc;
                break;
        }
        case MSR_K6_STAR:
-               vcpu->svm->vmcb->save.star = data;
+               svm->vmcb->save.star = data;
                break;
 #ifdef CONFIG_X86_64
        case MSR_LSTAR:
-               vcpu->svm->vmcb->save.lstar = data;
+               svm->vmcb->save.lstar = data;
                break;
        case MSR_CSTAR:
-               vcpu->svm->vmcb->save.cstar = data;
+               svm->vmcb->save.cstar = data;
                break;
        case MSR_KERNEL_GS_BASE:
-               vcpu->svm->vmcb->save.kernel_gs_base = data;
+               svm->vmcb->save.kernel_gs_base = data;
                break;
        case MSR_SYSCALL_MASK:
-               vcpu->svm->vmcb->save.sfmask = data;
+               svm->vmcb->save.sfmask = data;
                break;
 #endif
        case MSR_IA32_SYSENTER_CS:
-               vcpu->svm->vmcb->save.sysenter_cs = data;
+               svm->vmcb->save.sysenter_cs = data;
                break;
        case MSR_IA32_SYSENTER_EIP:
-               vcpu->svm->vmcb->save.sysenter_eip = data;
+               svm->vmcb->save.sysenter_eip = data;
                break;
        case MSR_IA32_SYSENTER_ESP:
-               vcpu->svm->vmcb->save.sysenter_esp = data;
+               svm->vmcb->save.sysenter_esp = data;
                break;
        default:
                return kvm_set_msr_common(vcpu, ecx, data);
@@ -1253,37 +1173,39 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
        return 0;
 }
 
-static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       u32 ecx = vcpu->regs[VCPU_REGS_RCX];
-       u64 data = (vcpu->svm->vmcb->save.rax & -1u)
-               | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
-       vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
-       if (svm_set_msr(vcpu, ecx, data))
-               svm_inject_gp(vcpu, 0);
+       u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
+       u64 data = (svm->vmcb->save.rax & -1u)
+               | ((u64)(svm->vcpu.regs[VCPU_REGS_RDX] & -1u) << 32);
+       svm->next_rip = svm->vmcb->save.rip + 2;
+       if (svm_set_msr(&svm->vcpu, ecx, data))
+               svm_inject_gp(&svm->vcpu, 0);
        else
-               skip_emulated_instruction(vcpu);
+               skip_emulated_instruction(&svm->vcpu);
        return 1;
 }
 
-static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
-       if (vcpu->svm->vmcb->control.exit_info_1)
-               return wrmsr_interception(vcpu, kvm_run);
+       if (svm->vmcb->control.exit_info_1)
+               return wrmsr_interception(svm, kvm_run);
        else
-               return rdmsr_interception(vcpu, kvm_run);
+               return rdmsr_interception(svm, kvm_run);
 }
 
-static int interrupt_window_interception(struct kvm_vcpu *vcpu,
+static int interrupt_window_interception(struct vcpu_svm *svm,
                                   struct kvm_run *kvm_run)
 {
+       svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
+       svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
        /*
         * If the user space waits to inject interrupts, exit as soon as
         * possible
         */
        if (kvm_run->request_interrupt_window &&
-           !vcpu->irq_summary) {
-               ++vcpu->stat.irq_window_exits;
+           !svm->vcpu.irq_summary) {
+               ++svm->vcpu.stat.irq_window_exits;
                kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
                return 0;
        }
@@ -1291,7 +1213,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu,
        return 1;
 }
 
-static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
+static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
                                      struct kvm_run *kvm_run) = {
        [SVM_EXIT_READ_CR0]                     = emulate_on_interception,
        [SVM_EXIT_READ_CR3]                     = emulate_on_interception,
@@ -1338,15 +1260,25 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
 };
 
 
-static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
-       u32 exit_code = vcpu->svm->vmcb->control.exit_code;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 exit_code = svm->vmcb->control.exit_code;
+
+       kvm_reput_irq(svm);
 
-       if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) &&
+       if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
+               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+               kvm_run->fail_entry.hardware_entry_failure_reason
+                       = svm->vmcb->control.exit_code;
+               return 0;
+       }
+
+       if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
            exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
                printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
                       "exit_code 0x%x\n",
-                      __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info,
+                      __FUNCTION__, svm->vmcb->control.exit_int_info,
                       exit_code);
 
        if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
@@ -1356,7 +1288,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                return 0;
        }
 
-       return svm_exit_handlers[exit_code](vcpu, kvm_run);
+       return svm_exit_handlers[exit_code](svm, kvm_run);
 }
 
 static void reload_tss(struct kvm_vcpu *vcpu)
@@ -1368,93 +1300,126 @@ static void reload_tss(struct kvm_vcpu *vcpu)
        load_TR_desc();
 }
 
-static void pre_svm_run(struct kvm_vcpu *vcpu)
+static void pre_svm_run(struct vcpu_svm *svm)
 {
        int cpu = raw_smp_processor_id();
 
        struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
 
-       vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
-       if (vcpu->cpu != cpu ||
-           vcpu->svm->asid_generation != svm_data->asid_generation)
-               new_asid(vcpu, svm_data);
+       svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
+       if (svm->vcpu.cpu != cpu ||
+           svm->asid_generation != svm_data->asid_generation)
+               new_asid(svm, svm_data);
 }
 
 
-static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
+static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
 {
        struct vmcb_control_area *control;
 
-       control = &vcpu->svm->vmcb->control;
-       control->int_vector = pop_irq(vcpu);
+       control = &svm->vmcb->control;
+       control->int_vector = irq;
        control->int_ctl &= ~V_INTR_PRIO_MASK;
        control->int_ctl |= V_IRQ_MASK |
                ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
 }
 
-static void kvm_reput_irq(struct kvm_vcpu *vcpu)
+static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm_inject_irq(svm, irq);
+}
+
+static void svm_intr_assist(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb *vmcb = svm->vmcb;
+       int intr_vector = -1;
+
+       kvm_inject_pending_timer_irqs(vcpu);
+       if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
+           ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
+               intr_vector = vmcb->control.exit_int_info &
+                             SVM_EVTINJ_VEC_MASK;
+               vmcb->control.exit_int_info = 0;
+               svm_inject_irq(svm, intr_vector);
+               return;
+       }
+
+       if (vmcb->control.int_ctl & V_IRQ_MASK)
+               return;
+
+       if (!kvm_cpu_has_interrupt(vcpu))
+               return;
+
+       if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
+           (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
+           (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
+               /* unable to deliver irq, set pending irq */
+               vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
+               svm_inject_irq(svm, 0x0);
+               return;
+       }
+       /* Okay, we can deliver the interrupt: grab it and update PIC state. */
+       intr_vector = kvm_cpu_get_interrupt(vcpu);
+       svm_inject_irq(svm, intr_vector);
+       kvm_timer_intr_post(vcpu, intr_vector);
+}
+
+static void kvm_reput_irq(struct vcpu_svm *svm)
 {
-       struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+       struct vmcb_control_area *control = &svm->vmcb->control;
 
-       if (control->int_ctl & V_IRQ_MASK) {
+       if ((control->int_ctl & V_IRQ_MASK)
+           && !irqchip_in_kernel(svm->vcpu.kvm)) {
                control->int_ctl &= ~V_IRQ_MASK;
-               push_irq(vcpu, control->int_vector);
+               push_irq(&svm->vcpu, control->int_vector);
        }
 
-       vcpu->interrupt_window_open =
+       svm->vcpu.interrupt_window_open =
                !(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
 }
 
+static void svm_do_inject_vector(struct vcpu_svm *svm)
+{
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+       int word_index = __ffs(vcpu->irq_summary);
+       int bit_index = __ffs(vcpu->irq_pending[word_index]);
+       int irq = word_index * BITS_PER_LONG + bit_index;
+
+       clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+       if (!vcpu->irq_pending[word_index])
+               clear_bit(word_index, &vcpu->irq_summary);
+       svm_inject_irq(svm, irq);
+}
+
 static void do_interrupt_requests(struct kvm_vcpu *vcpu,
                                       struct kvm_run *kvm_run)
 {
-       struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb_control_area *control = &svm->vmcb->control;
 
-       vcpu->interrupt_window_open =
+       svm->vcpu.interrupt_window_open =
                (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-                (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
+                (svm->vmcb->save.rflags & X86_EFLAGS_IF));
 
-       if (vcpu->interrupt_window_open && vcpu->irq_summary)
+       if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary)
                /*
                 * If interrupts enabled, and not blocked by sti or mov ss. Good.
                 */
-               kvm_do_inject_irq(vcpu);
+               svm_do_inject_vector(svm);
 
        /*
         * Interrupts blocked.  Wait for unblock.
         */
-       if (!vcpu->interrupt_window_open &&
-           (vcpu->irq_summary || kvm_run->request_interrupt_window)) {
+       if (!svm->vcpu.interrupt_window_open &&
+           (svm->vcpu.irq_summary || kvm_run->request_interrupt_window)) {
                control->intercept |= 1ULL << INTERCEPT_VINTR;
        } else
                control->intercept &= ~(1ULL << INTERCEPT_VINTR);
 }
 
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
-                             struct kvm_run *kvm_run)
-{
-       kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
-                                                 vcpu->irq_summary == 0);
-       kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
-       kvm_run->cr8 = vcpu->cr8;
-       kvm_run->apic_base = vcpu->apic_base;
-}
-
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
-                                         struct kvm_run *kvm_run)
-{
-       return (!vcpu->irq_summary &&
-               kvm_run->request_interrupt_window &&
-               vcpu->interrupt_window_open &&
-               (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
-}
-
 static void save_db_regs(unsigned long *db_regs)
 {
        asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0]));
@@ -1476,49 +1441,37 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu)
        force_new_asid(vcpu);
 }
 
-static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
+{
+}
+
+static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
+       struct vcpu_svm *svm = to_svm(vcpu);
        u16 fs_selector;
        u16 gs_selector;
        u16 ldt_selector;
-       int r;
-
-again:
-       r = kvm_mmu_reload(vcpu);
-       if (unlikely(r))
-               return r;
-
-       if (!vcpu->mmio_read_completed)
-               do_interrupt_requests(vcpu, kvm_run);
 
-       clgi();
-
-       vcpu->guest_mode = 1;
-       if (vcpu->requests)
-               if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
-                   svm_flush_tlb(vcpu);
-
-       pre_svm_run(vcpu);
+       pre_svm_run(svm);
 
        save_host_msrs(vcpu);
        fs_selector = read_fs();
        gs_selector = read_gs();
        ldt_selector = read_ldt();
-       vcpu->svm->host_cr2 = kvm_read_cr2();
-       vcpu->svm->host_dr6 = read_dr6();
-       vcpu->svm->host_dr7 = read_dr7();
-       vcpu->svm->vmcb->save.cr2 = vcpu->cr2;
+       svm->host_cr2 = kvm_read_cr2();
+       svm->host_dr6 = read_dr6();
+       svm->host_dr7 = read_dr7();
+       svm->vmcb->save.cr2 = vcpu->cr2;
 
-       if (vcpu->svm->vmcb->save.dr7 & 0xff) {
+       if (svm->vmcb->save.dr7 & 0xff) {
                write_dr7(0);
-               save_db_regs(vcpu->svm->host_db_regs);
-               load_db_regs(vcpu->svm->db_regs);
+               save_db_regs(svm->host_db_regs);
+               load_db_regs(svm->db_regs);
        }
 
-       if (vcpu->fpu_active) {
-               fx_save(vcpu->host_fx_image);
-               fx_restore(vcpu->guest_fx_image);
-       }
+       clgi();
+
+       local_irq_enable();
 
        asm volatile (
 #ifdef CONFIG_X86_64
@@ -1532,34 +1485,33 @@ again:
 #endif
 
 #ifdef CONFIG_X86_64
-               "mov %c[rbx](%[vcpu]), %%rbx \n\t"
-               "mov %c[rcx](%[vcpu]), %%rcx \n\t"
-               "mov %c[rdx](%[vcpu]), %%rdx \n\t"
-               "mov %c[rsi](%[vcpu]), %%rsi \n\t"
-               "mov %c[rdi](%[vcpu]), %%rdi \n\t"
-               "mov %c[rbp](%[vcpu]), %%rbp \n\t"
-               "mov %c[r8](%[vcpu]),  %%r8  \n\t"
-               "mov %c[r9](%[vcpu]),  %%r9  \n\t"
-               "mov %c[r10](%[vcpu]), %%r10 \n\t"
-               "mov %c[r11](%[vcpu]), %%r11 \n\t"
-               "mov %c[r12](%[vcpu]), %%r12 \n\t"
-               "mov %c[r13](%[vcpu]), %%r13 \n\t"
-               "mov %c[r14](%[vcpu]), %%r14 \n\t"
-               "mov %c[r15](%[vcpu]), %%r15 \n\t"
+               "mov %c[rbx](%[svm]), %%rbx \n\t"
+               "mov %c[rcx](%[svm]), %%rcx \n\t"
+               "mov %c[rdx](%[svm]), %%rdx \n\t"
+               "mov %c[rsi](%[svm]), %%rsi \n\t"
+               "mov %c[rdi](%[svm]), %%rdi \n\t"
+               "mov %c[rbp](%[svm]), %%rbp \n\t"
+               "mov %c[r8](%[svm]),  %%r8  \n\t"
+               "mov %c[r9](%[svm]),  %%r9  \n\t"
+               "mov %c[r10](%[svm]), %%r10 \n\t"
+               "mov %c[r11](%[svm]), %%r11 \n\t"
+               "mov %c[r12](%[svm]), %%r12 \n\t"
+               "mov %c[r13](%[svm]), %%r13 \n\t"
+               "mov %c[r14](%[svm]), %%r14 \n\t"
+               "mov %c[r15](%[svm]), %%r15 \n\t"
 #else
-               "mov %c[rbx](%[vcpu]), %%ebx \n\t"
-               "mov %c[rcx](%[vcpu]), %%ecx \n\t"
-               "mov %c[rdx](%[vcpu]), %%edx \n\t"
-               "mov %c[rsi](%[vcpu]), %%esi \n\t"
-               "mov %c[rdi](%[vcpu]), %%edi \n\t"
-               "mov %c[rbp](%[vcpu]), %%ebp \n\t"
+               "mov %c[rbx](%[svm]), %%ebx \n\t"
+               "mov %c[rcx](%[svm]), %%ecx \n\t"
+               "mov %c[rdx](%[svm]), %%edx \n\t"
+               "mov %c[rsi](%[svm]), %%esi \n\t"
+               "mov %c[rdi](%[svm]), %%edi \n\t"
+               "mov %c[rbp](%[svm]), %%ebp \n\t"
 #endif
 
 #ifdef CONFIG_X86_64
                /* Enter guest mode */
                "push %%rax \n\t"
-               "mov %c[svm](%[vcpu]), %%rax \n\t"
-               "mov %c[vmcb](%%rax), %%rax \n\t"
+               "mov %c[vmcb](%[svm]), %%rax \n\t"
                SVM_VMLOAD "\n\t"
                SVM_VMRUN "\n\t"
                SVM_VMSAVE "\n\t"
@@ -1567,8 +1519,7 @@ again:
 #else
                /* Enter guest mode */
                "push %%eax \n\t"
-               "mov %c[svm](%[vcpu]), %%eax \n\t"
-               "mov %c[vmcb](%%eax), %%eax \n\t"
+               "mov %c[vmcb](%[svm]), %%eax \n\t"
                SVM_VMLOAD "\n\t"
                SVM_VMRUN "\n\t"
                SVM_VMSAVE "\n\t"
@@ -1577,73 +1528,69 @@ again:
 
                /* Save guest registers, load host registers */
 #ifdef CONFIG_X86_64
-               "mov %%rbx, %c[rbx](%[vcpu]) \n\t"
-               "mov %%rcx, %c[rcx](%[vcpu]) \n\t"
-               "mov %%rdx, %c[rdx](%[vcpu]) \n\t"
-               "mov %%rsi, %c[rsi](%[vcpu]) \n\t"
-               "mov %%rdi, %c[rdi](%[vcpu]) \n\t"
-               "mov %%rbp, %c[rbp](%[vcpu]) \n\t"
-               "mov %%r8,  %c[r8](%[vcpu]) \n\t"
-               "mov %%r9,  %c[r9](%[vcpu]) \n\t"
-               "mov %%r10, %c[r10](%[vcpu]) \n\t"
-               "mov %%r11, %c[r11](%[vcpu]) \n\t"
-               "mov %%r12, %c[r12](%[vcpu]) \n\t"
-               "mov %%r13, %c[r13](%[vcpu]) \n\t"
-               "mov %%r14, %c[r14](%[vcpu]) \n\t"
-               "mov %%r15, %c[r15](%[vcpu]) \n\t"
+               "mov %%rbx, %c[rbx](%[svm]) \n\t"
+               "mov %%rcx, %c[rcx](%[svm]) \n\t"
+               "mov %%rdx, %c[rdx](%[svm]) \n\t"
+               "mov %%rsi, %c[rsi](%[svm]) \n\t"
+               "mov %%rdi, %c[rdi](%[svm]) \n\t"
+               "mov %%rbp, %c[rbp](%[svm]) \n\t"
+               "mov %%r8,  %c[r8](%[svm]) \n\t"
+               "mov %%r9,  %c[r9](%[svm]) \n\t"
+               "mov %%r10, %c[r10](%[svm]) \n\t"
+               "mov %%r11, %c[r11](%[svm]) \n\t"
+               "mov %%r12, %c[r12](%[svm]) \n\t"
+               "mov %%r13, %c[r13](%[svm]) \n\t"
+               "mov %%r14, %c[r14](%[svm]) \n\t"
+               "mov %%r15, %c[r15](%[svm]) \n\t"
 
                "pop  %%r15; pop  %%r14; pop  %%r13; pop  %%r12;"
                "pop  %%r11; pop  %%r10; pop  %%r9;  pop  %%r8;"
                "pop  %%rbp; pop  %%rdi; pop  %%rsi;"
                "pop  %%rdx; pop  %%rcx; pop  %%rbx; \n\t"
 #else
-               "mov %%ebx, %c[rbx](%[vcpu]) \n\t"
-               "mov %%ecx, %c[rcx](%[vcpu]) \n\t"
-               "mov %%edx, %c[rdx](%[vcpu]) \n\t"
-               "mov %%esi, %c[rsi](%[vcpu]) \n\t"
-               "mov %%edi, %c[rdi](%[vcpu]) \n\t"
-               "mov %%ebp, %c[rbp](%[vcpu]) \n\t"
+               "mov %%ebx, %c[rbx](%[svm]) \n\t"
+               "mov %%ecx, %c[rcx](%[svm]) \n\t"
+               "mov %%edx, %c[rdx](%[svm]) \n\t"
+               "mov %%esi, %c[rsi](%[svm]) \n\t"
+               "mov %%edi, %c[rdi](%[svm]) \n\t"
+               "mov %%ebp, %c[rbp](%[svm]) \n\t"
 
                "pop  %%ebp; pop  %%edi; pop  %%esi;"
                "pop  %%edx; pop  %%ecx; pop  %%ebx; \n\t"
 #endif
                :
-               : [vcpu]"a"(vcpu),
-                 [svm]"i"(offsetof(struct kvm_vcpu, svm)),
+               : [svm]"a"(svm),
                  [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
-                 [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
-                 [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
-                 [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
-                 [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
-                 [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
-                 [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP]))
+                 [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])),
+                 [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])),
+                 [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])),
+                 [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])),
+                 [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])),
+                 [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP]))
 #ifdef CONFIG_X86_64
-                 ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
-                 [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
-                 [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
-                 [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
-                 [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
-                 [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
-                 [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
-                 [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15]))
+                 ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])),
+                 [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])),
+                 [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])),
+                 [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])),
+                 [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])),
+                 [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])),
+                 [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])),
+                 [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15]))
 #endif
                : "cc", "memory" );
 
-       vcpu->guest_mode = 0;
+       local_irq_disable();
 
-       if (vcpu->fpu_active) {
-               fx_save(vcpu->guest_fx_image);
-               fx_restore(vcpu->host_fx_image);
-       }
+       stgi();
 
-       if ((vcpu->svm->vmcb->save.dr7 & 0xff))
-               load_db_regs(vcpu->svm->host_db_regs);
+       if ((svm->vmcb->save.dr7 & 0xff))
+               load_db_regs(svm->host_db_regs);
 
-       vcpu->cr2 = vcpu->svm->vmcb->save.cr2;
+       vcpu->cr2 = svm->vmcb->save.cr2;
 
-       write_dr6(vcpu->svm->host_dr6);
-       write_dr7(vcpu->svm->host_dr7);
-       kvm_write_cr2(vcpu->svm->host_cr2);
+       write_dr6(svm->host_dr6);
+       write_dr7(svm->host_dr7);
+       kvm_write_cr2(svm->host_cr2);
 
        load_fs(fs_selector);
        load_gs(gs_selector);
@@ -1652,57 +1599,19 @@ again:
 
        reload_tss(vcpu);
 
-       /*
-        * Profile KVM exit RIPs:
-        */
-       if (unlikely(prof_on == KVM_PROFILING))
-               profile_hit(KVM_PROFILING,
-                       (void *)(unsigned long)vcpu->svm->vmcb->save.rip);
-
-       stgi();
-
-       kvm_reput_irq(vcpu);
-
-       vcpu->svm->next_rip = 0;
-
-       if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
-               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-               kvm_run->fail_entry.hardware_entry_failure_reason
-                       = vcpu->svm->vmcb->control.exit_code;
-               post_kvm_run_save(vcpu, kvm_run);
-               return 0;
-       }
-
-       r = handle_exit(vcpu, kvm_run);
-       if (r > 0) {
-               if (signal_pending(current)) {
-                       ++vcpu->stat.signal_exits;
-                       post_kvm_run_save(vcpu, kvm_run);
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
-                       return -EINTR;
-               }
-
-               if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-                       ++vcpu->stat.request_irq_exits;
-                       post_kvm_run_save(vcpu, kvm_run);
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
-                       return -EINTR;
-               }
-               kvm_resched(vcpu);
-               goto again;
-       }
-       post_kvm_run_save(vcpu, kvm_run);
-       return r;
+       svm->next_rip = 0;
 }
 
 static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
 {
-       vcpu->svm->vmcb->save.cr3 = root;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm->vmcb->save.cr3 = root;
        force_new_asid(vcpu);
 
        if (vcpu->fpu_active) {
-               vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
-               vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK;
+               svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
+               svm->vmcb->save.cr0 |= X86_CR0_TS;
                vcpu->fpu_active = 0;
        }
 }
@@ -1711,26 +1620,27 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
                                  unsigned long  addr,
                                  uint32_t err_code)
 {
-       uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       uint32_t exit_int_info = svm->vmcb->control.exit_int_info;
 
        ++vcpu->stat.pf_guest;
 
        if (is_page_fault(exit_int_info)) {
 
-               vcpu->svm->vmcb->control.event_inj_err = 0;
-               vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
-                                                       SVM_EVTINJ_VALID_ERR |
-                                                       SVM_EVTINJ_TYPE_EXEPT |
-                                                       DF_VECTOR;
+               svm->vmcb->control.event_inj_err = 0;
+               svm->vmcb->control.event_inj =  SVM_EVTINJ_VALID |
+                                               SVM_EVTINJ_VALID_ERR |
+                                               SVM_EVTINJ_TYPE_EXEPT |
+                                               DF_VECTOR;
                return;
        }
        vcpu->cr2 = addr;
-       vcpu->svm->vmcb->save.cr2 = addr;
-       vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
-                                               SVM_EVTINJ_VALID_ERR |
-                                               SVM_EVTINJ_TYPE_EXEPT |
-                                               PF_VECTOR;
-       vcpu->svm->vmcb->control.event_inj_err = err_code;
+       svm->vmcb->save.cr2 = addr;
+       svm->vmcb->control.event_inj =  SVM_EVTINJ_VALID |
+                                       SVM_EVTINJ_VALID_ERR |
+                                       SVM_EVTINJ_TYPE_EXEPT |
+                                       PF_VECTOR;
+       svm->vmcb->control.event_inj_err = err_code;
 }
 
 
@@ -1757,17 +1667,25 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
        hypercall[3] = 0xc3;
 }
 
-static struct kvm_arch_ops svm_arch_ops = {
+static void svm_check_processor_compat(void *rtn)
+{
+       *(int *)rtn = 0;
+}
+
+static struct kvm_x86_ops svm_x86_ops = {
        .cpu_has_kvm_support = has_svm,
        .disabled_by_bios = is_disabled,
        .hardware_setup = svm_hardware_setup,
        .hardware_unsetup = svm_hardware_unsetup,
+       .check_processor_compatibility = svm_check_processor_compat,
        .hardware_enable = svm_hardware_enable,
        .hardware_disable = svm_hardware_disable,
 
        .vcpu_create = svm_create_vcpu,
        .vcpu_free = svm_free_vcpu,
+       .vcpu_reset = svm_vcpu_reset,
 
+       .prepare_guest_switch = svm_prepare_guest_switch,
        .vcpu_load = svm_vcpu_load,
        .vcpu_put = svm_vcpu_put,
        .vcpu_decache = svm_vcpu_decache,
@@ -1778,7 +1696,7 @@ static struct kvm_arch_ops svm_arch_ops = {
        .get_segment_base = svm_get_segment_base,
        .get_segment = svm_get_segment,
        .set_segment = svm_set_segment,
-       .get_cs_db_l_bits = svm_get_cs_db_l_bits,
+       .get_cs_db_l_bits = kvm_get_cs_db_l_bits,
        .decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
        .set_cr0 = svm_set_cr0,
        .set_cr3 = svm_set_cr3,
@@ -1795,26 +1713,30 @@ static struct kvm_arch_ops svm_arch_ops = {
        .get_rflags = svm_get_rflags,
        .set_rflags = svm_set_rflags,
 
-       .invlpg = svm_invlpg,
        .tlb_flush = svm_flush_tlb,
        .inject_page_fault = svm_inject_page_fault,
 
        .inject_gp = svm_inject_gp,
 
        .run = svm_vcpu_run,
+       .handle_exit = handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
-       .vcpu_setup = svm_vcpu_setup,
        .patch_hypercall = svm_patch_hypercall,
+       .get_irq = svm_get_irq,
+       .set_irq = svm_set_irq,
+       .inject_pending_irq = svm_intr_assist,
+       .inject_pending_vectors = do_interrupt_requests,
 };
 
 static int __init svm_init(void)
 {
-       return kvm_init_arch(&svm_arch_ops, THIS_MODULE);
+       return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm),
+                             THIS_MODULE);
 }
 
 static void __exit svm_exit(void)
 {
-       kvm_exit_arch();
+       kvm_exit_x86();
 }
 
 module_init(svm_init)
index 80628f69916d85c0c58f02f126ff62cf778ea855..4f115a8e45ef803ae1b1f1d494690bd98b9488c4 100644 (file)
@@ -16,6 +16,8 @@
  */
 
 #include "kvm.h"
+#include "x86_emulate.h"
+#include "irq.h"
 #include "vmx.h"
 #include "segment_descriptor.h"
 
@@ -23,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
-#include <linux/profile.h>
 #include <linux/sched.h>
 
 #include <asm/io.h>
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+struct vmcs {
+       u32 revision_id;
+       u32 abort;
+       char data[0];
+};
+
+struct vcpu_vmx {
+       struct kvm_vcpu       vcpu;
+       int                   launched;
+       u8                    fail;
+       struct kvm_msr_entry *guest_msrs;
+       struct kvm_msr_entry *host_msrs;
+       int                   nmsrs;
+       int                   save_nmsrs;
+       int                   msr_offset_efer;
+#ifdef CONFIG_X86_64
+       int                   msr_offset_kernel_gs_base;
+#endif
+       struct vmcs          *vmcs;
+       struct {
+               int           loaded;
+               u16           fs_sel, gs_sel, ldt_sel;
+               int           gs_ldt_reload_needed;
+               int           fs_reload_needed;
+       }host_state;
+
+};
+
+static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
+{
+       return container_of(vcpu, struct vcpu_vmx, vcpu);
+}
+
 static int init_rmode_tss(struct kvm *kvm);
 
 static DEFINE_PER_CPU(struct vmcs *, vmxarea);
@@ -40,18 +74,17 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 static struct page *vmx_io_bitmap_a;
 static struct page *vmx_io_bitmap_b;
 
-#ifdef CONFIG_X86_64
-#define HOST_IS_64 1
-#else
-#define HOST_IS_64 0
-#endif
 #define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
 
-static struct vmcs_descriptor {
+static struct vmcs_config {
        int size;
        int order;
        u32 revision_id;
-} vmcs_descriptor;
+       u32 pin_based_exec_ctrl;
+       u32 cpu_based_exec_ctrl;
+       u32 vmexit_ctrl;
+       u32 vmentry_ctrl;
+} vmcs_config;
 
 #define VMX_SEGMENT_FIELD(seg)                                 \
        [VCPU_SREG_##seg] = {                                   \
@@ -89,16 +122,32 @@ static const u32 vmx_msr_index[] = {
 };
 #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
 
-static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr)
+static void load_msrs(struct kvm_msr_entry *e, int n)
+{
+       int i;
+
+       for (i = 0; i < n; ++i)
+               wrmsrl(e[i].index, e[i].data);
+}
+
+static void save_msrs(struct kvm_msr_entry *e, int n)
+{
+       int i;
+
+       for (i = 0; i < n; ++i)
+               rdmsrl(e[i].index, e[i].data);
+}
+
+static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr)
 {
        return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
 }
 
-static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu)
+static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx)
 {
-       int efer_offset = vcpu->msr_offset_efer;
-       return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) !=
-               msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]);
+       int efer_offset = vmx->msr_offset_efer;
+       return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) !=
+               msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
 }
 
 static inline int is_page_fault(u32 intr_info)
@@ -121,23 +170,33 @@ static inline int is_external_interrupt(u32 intr_info)
                == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
-static int __find_msr_index(struct kvm_vcpu *vcpu, u32 msr)
+static inline int cpu_has_vmx_tpr_shadow(void)
+{
+       return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
+}
+
+static inline int vm_need_tpr_shadow(struct kvm *kvm)
+{
+       return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
+}
+
+static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
 {
        int i;
 
-       for (i = 0; i < vcpu->nmsrs; ++i)
-               if (vcpu->guest_msrs[i].index == msr)
+       for (i = 0; i < vmx->nmsrs; ++i)
+               if (vmx->guest_msrs[i].index == msr)
                        return i;
        return -1;
 }
 
-static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
 {
        int i;
 
-       i = __find_msr_index(vcpu, msr);
+       i = __find_msr_index(vmx, msr);
        if (i >= 0)
-               return &vcpu->guest_msrs[i];
+               return &vmx->guest_msrs[i];
        return NULL;
 }
 
@@ -156,23 +215,24 @@ static void vmcs_clear(struct vmcs *vmcs)
 
 static void __vcpu_clear(void *arg)
 {
-       struct kvm_vcpu *vcpu = arg;
+       struct vcpu_vmx *vmx = arg;
        int cpu = raw_smp_processor_id();
 
-       if (vcpu->cpu == cpu)
-               vmcs_clear(vcpu->vmcs);
-       if (per_cpu(current_vmcs, cpu) == vcpu->vmcs)
+       if (vmx->vcpu.cpu == cpu)
+               vmcs_clear(vmx->vmcs);
+       if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
                per_cpu(current_vmcs, cpu) = NULL;
-       rdtscll(vcpu->host_tsc);
+       rdtscll(vmx->vcpu.host_tsc);
 }
 
-static void vcpu_clear(struct kvm_vcpu *vcpu)
+static void vcpu_clear(struct vcpu_vmx *vmx)
 {
-       if (vcpu->cpu != raw_smp_processor_id() && vcpu->cpu != -1)
-               smp_call_function_single(vcpu->cpu, __vcpu_clear, vcpu, 0, 1);
+       if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1)
+               smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear,
+                                        vmx, 0, 1);
        else
-               __vcpu_clear(vcpu);
-       vcpu->launched = 0;
+               __vcpu_clear(vmx);
+       vmx->launched = 0;
 }
 
 static unsigned long vmcs_readl(unsigned long field)
@@ -282,121 +342,122 @@ static void reload_tss(void)
 #endif
 }
 
-static void load_transition_efer(struct kvm_vcpu *vcpu)
+static void load_transition_efer(struct vcpu_vmx *vmx)
 {
        u64 trans_efer;
-       int efer_offset = vcpu->msr_offset_efer;
+       int efer_offset = vmx->msr_offset_efer;
 
-       trans_efer = vcpu->host_msrs[efer_offset].data;
+       trans_efer = vmx->host_msrs[efer_offset].data;
        trans_efer &= ~EFER_SAVE_RESTORE_BITS;
-       trans_efer |= msr_efer_save_restore_bits(
-                               vcpu->guest_msrs[efer_offset]);
+       trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
        wrmsrl(MSR_EFER, trans_efer);
-       vcpu->stat.efer_reload++;
+       vmx->vcpu.stat.efer_reload++;
 }
 
 static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 {
-       struct vmx_host_state *hs = &vcpu->vmx_host_state;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       if (hs->loaded)
+       if (vmx->host_state.loaded)
                return;
 
-       hs->loaded = 1;
+       vmx->host_state.loaded = 1;
        /*
         * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
         * allow segment selectors with cpl > 0 or ti == 1.
         */
-       hs->ldt_sel = read_ldt();
-       hs->fs_gs_ldt_reload_needed = hs->ldt_sel;
-       hs->fs_sel = read_fs();
-       if (!(hs->fs_sel & 7))
-               vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel);
-       else {
+       vmx->host_state.ldt_sel = read_ldt();
+       vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
+       vmx->host_state.fs_sel = read_fs();
+       if (!(vmx->host_state.fs_sel & 7)) {
+               vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
+               vmx->host_state.fs_reload_needed = 0;
+       } else {
                vmcs_write16(HOST_FS_SELECTOR, 0);
-               hs->fs_gs_ldt_reload_needed = 1;
+               vmx->host_state.fs_reload_needed = 1;
        }
-       hs->gs_sel = read_gs();
-       if (!(hs->gs_sel & 7))
-               vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel);
+       vmx->host_state.gs_sel = read_gs();
+       if (!(vmx->host_state.gs_sel & 7))
+               vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
        else {
                vmcs_write16(HOST_GS_SELECTOR, 0);
-               hs->fs_gs_ldt_reload_needed = 1;
+               vmx->host_state.gs_ldt_reload_needed = 1;
        }
 
 #ifdef CONFIG_X86_64
        vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
        vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
 #else
-       vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel));
-       vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel));
+       vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel));
+       vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel));
 #endif
 
 #ifdef CONFIG_X86_64
-       if (is_long_mode(vcpu)) {
-               save_msrs(vcpu->host_msrs + vcpu->msr_offset_kernel_gs_base, 1);
+       if (is_long_mode(&vmx->vcpu)) {
+               save_msrs(vmx->host_msrs +
+                         vmx->msr_offset_kernel_gs_base, 1);
        }
 #endif
-       load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
-       if (msr_efer_need_save_restore(vcpu))
-               load_transition_efer(vcpu);
+       load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
+       if (msr_efer_need_save_restore(vmx))
+               load_transition_efer(vmx);
 }
 
-static void vmx_load_host_state(struct kvm_vcpu *vcpu)
+static void vmx_load_host_state(struct vcpu_vmx *vmx)
 {
-       struct vmx_host_state *hs = &vcpu->vmx_host_state;
+       unsigned long flags;
 
-       if (!hs->loaded)
+       if (!vmx->host_state.loaded)
                return;
 
-       hs->loaded = 0;
-       if (hs->fs_gs_ldt_reload_needed) {
-               load_ldt(hs->ldt_sel);
-               load_fs(hs->fs_sel);
+       vmx->host_state.loaded = 0;
+       if (vmx->host_state.fs_reload_needed)
+               load_fs(vmx->host_state.fs_sel);
+       if (vmx->host_state.gs_ldt_reload_needed) {
+               load_ldt(vmx->host_state.ldt_sel);
                /*
                 * If we have to reload gs, we must take care to
                 * preserve our gs base.
                 */
-               local_irq_disable();
-               load_gs(hs->gs_sel);
+               local_irq_save(flags);
+               load_gs(vmx->host_state.gs_sel);
 #ifdef CONFIG_X86_64
                wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
 #endif
-               local_irq_enable();
-
-               reload_tss();
+               local_irq_restore(flags);
        }
-       save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
-       load_msrs(vcpu->host_msrs, vcpu->save_nmsrs);
-       if (msr_efer_need_save_restore(vcpu))
-               load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1);
+       reload_tss();
+       save_msrs(vmx->guest_msrs, vmx->save_nmsrs);
+       load_msrs(vmx->host_msrs, vmx->save_nmsrs);
+       if (msr_efer_need_save_restore(vmx))
+               load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
 }
 
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
  */
-static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
+static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
-       u64 phys_addr = __pa(vcpu->vmcs);
-       int cpu;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u64 phys_addr = __pa(vmx->vmcs);
        u64 tsc_this, delta;
 
-       cpu = get_cpu();
-
-       if (vcpu->cpu != cpu)
-               vcpu_clear(vcpu);
+       if (vcpu->cpu != cpu) {
+               vcpu_clear(vmx);
+               kvm_migrate_apic_timer(vcpu);
+       }
 
-       if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) {
+       if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
                u8 error;
 
-               per_cpu(current_vmcs, cpu) = vcpu->vmcs;
+               per_cpu(current_vmcs, cpu) = vmx->vmcs;
                asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0"
                              : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
                              : "cc");
                if (error)
                        printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
-                              vcpu->vmcs, phys_addr);
+                              vmx->vmcs, phys_addr);
        }
 
        if (vcpu->cpu != cpu) {
@@ -426,9 +487,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
 
 static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
 {
-       vmx_load_host_state(vcpu);
+       vmx_load_host_state(to_vmx(vcpu));
        kvm_put_guest_fpu(vcpu);
-       put_cpu();
 }
 
 static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
@@ -436,9 +496,9 @@ static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
        if (vcpu->fpu_active)
                return;
        vcpu->fpu_active = 1;
-       vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
-       if (vcpu->cr0 & CR0_TS_MASK)
-               vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+       vmcs_clear_bits(GUEST_CR0, X86_CR0_TS);
+       if (vcpu->cr0 & X86_CR0_TS)
+               vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
        update_exception_bitmap(vcpu);
 }
 
@@ -447,13 +507,13 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
        if (!vcpu->fpu_active)
                return;
        vcpu->fpu_active = 0;
-       vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+       vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
        update_exception_bitmap(vcpu);
 }
 
 static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
 {
-       vcpu_clear(vcpu);
+       vcpu_clear(to_vmx(vcpu));
 }
 
 static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
@@ -501,59 +561,62 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
 /*
  * Swap MSR entry in host/guest MSR entry array.
  */
-void move_msr_up(struct kvm_vcpu *vcpu, int from, int to)
+#ifdef CONFIG_X86_64
+static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
 {
-       struct vmx_msr_entry tmp;
-       tmp = vcpu->guest_msrs[to];
-       vcpu->guest_msrs[to] = vcpu->guest_msrs[from];
-       vcpu->guest_msrs[from] = tmp;
-       tmp = vcpu->host_msrs[to];
-       vcpu->host_msrs[to] = vcpu->host_msrs[from];
-       vcpu->host_msrs[from] = tmp;
+       struct kvm_msr_entry tmp;
+
+       tmp = vmx->guest_msrs[to];
+       vmx->guest_msrs[to] = vmx->guest_msrs[from];
+       vmx->guest_msrs[from] = tmp;
+       tmp = vmx->host_msrs[to];
+       vmx->host_msrs[to] = vmx->host_msrs[from];
+       vmx->host_msrs[from] = tmp;
 }
+#endif
 
 /*
  * Set up the vmcs to automatically save and restore system
  * msrs.  Don't touch the 64-bit msrs if the guest is in legacy
  * mode, as fiddling with msrs is very expensive.
  */
-static void setup_msrs(struct kvm_vcpu *vcpu)
+static void setup_msrs(struct vcpu_vmx *vmx)
 {
        int save_nmsrs;
 
        save_nmsrs = 0;
 #ifdef CONFIG_X86_64
-       if (is_long_mode(vcpu)) {
+       if (is_long_mode(&vmx->vcpu)) {
                int index;
 
-               index = __find_msr_index(vcpu, MSR_SYSCALL_MASK);
+               index = __find_msr_index(vmx, MSR_SYSCALL_MASK);
                if (index >= 0)
-                       move_msr_up(vcpu, index, save_nmsrs++);
-               index = __find_msr_index(vcpu, MSR_LSTAR);
+                       move_msr_up(vmx, index, save_nmsrs++);
+               index = __find_msr_index(vmx, MSR_LSTAR);
                if (index >= 0)
-                       move_msr_up(vcpu, index, save_nmsrs++);
-               index = __find_msr_index(vcpu, MSR_CSTAR);
+                       move_msr_up(vmx, index, save_nmsrs++);
+               index = __find_msr_index(vmx, MSR_CSTAR);
                if (index >= 0)
-                       move_msr_up(vcpu, index, save_nmsrs++);
-               index = __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+                       move_msr_up(vmx, index, save_nmsrs++);
+               index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
                if (index >= 0)
-                       move_msr_up(vcpu, index, save_nmsrs++);
+                       move_msr_up(vmx, index, save_nmsrs++);
                /*
                 * MSR_K6_STAR is only needed on long mode guests, and only
                 * if efer.sce is enabled.
                 */
-               index = __find_msr_index(vcpu, MSR_K6_STAR);
-               if ((index >= 0) && (vcpu->shadow_efer & EFER_SCE))
-                       move_msr_up(vcpu, index, save_nmsrs++);
+               index = __find_msr_index(vmx, MSR_K6_STAR);
+               if ((index >= 0) && (vmx->vcpu.shadow_efer & EFER_SCE))
+                       move_msr_up(vmx, index, save_nmsrs++);
        }
 #endif
-       vcpu->save_nmsrs = save_nmsrs;
+       vmx->save_nmsrs = save_nmsrs;
 
 #ifdef CONFIG_X86_64
-       vcpu->msr_offset_kernel_gs_base =
-               __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+       vmx->msr_offset_kernel_gs_base =
+               __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
 #endif
-       vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER);
+       vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER);
 }
 
 /*
@@ -589,7 +652,7 @@ static void guest_write_tsc(u64 guest_tsc)
 static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
        u64 data;
-       struct vmx_msr_entry *msr;
+       struct kvm_msr_entry *msr;
 
        if (!pdata) {
                printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
@@ -620,7 +683,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
                data = vmcs_readl(GUEST_SYSENTER_ESP);
                break;
        default:
-               msr = find_msr_entry(vcpu, msr_index);
+               msr = find_msr_entry(to_vmx(vcpu), msr_index);
                if (msr) {
                        data = msr->data;
                        break;
@@ -639,15 +702,16 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
  */
 static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
-       struct vmx_msr_entry *msr;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct kvm_msr_entry *msr;
        int ret = 0;
 
        switch (msr_index) {
 #ifdef CONFIG_X86_64
        case MSR_EFER:
                ret = kvm_set_msr_common(vcpu, msr_index, data);
-               if (vcpu->vmx_host_state.loaded)
-                       load_transition_efer(vcpu);
+               if (vmx->host_state.loaded)
+                       load_transition_efer(vmx);
                break;
        case MSR_FS_BASE:
                vmcs_writel(GUEST_FS_BASE, data);
@@ -669,11 +733,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
                guest_write_tsc(data);
                break;
        default:
-               msr = find_msr_entry(vcpu, msr_index);
+               msr = find_msr_entry(vmx, msr_index);
                if (msr) {
                        msr->data = data;
-                       if (vcpu->vmx_host_state.loaded)
-                               load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
+                       if (vmx->host_state.loaded)
+                               load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
                        break;
                }
                ret = kvm_set_msr_common(vcpu, msr_index, data);
@@ -740,6 +804,20 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
        return 0;
 }
 
+static int vmx_get_irq(struct kvm_vcpu *vcpu)
+{
+       u32 idtv_info_field;
+
+       idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       if (idtv_info_field & INTR_INFO_VALID_MASK) {
+               if (is_external_interrupt(idtv_info_field))
+                       return idtv_info_field & VECTORING_INFO_VECTOR_MASK;
+               else
+                       printk("pending exception: not handled yet\n");
+       }
+       return -1;
+}
+
 static __init int cpu_has_kvm_support(void)
 {
        unsigned long ecx = cpuid_ecx(1);
@@ -751,7 +829,10 @@ static __init int vmx_disabled_by_bios(void)
        u64 msr;
 
        rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
-       return (msr & 5) == 1; /* locked but not enabled */
+       return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED |
+                      MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
+           == MSR_IA32_FEATURE_CONTROL_LOCKED;
+       /* locked but not enabled */
 }
 
 static void hardware_enable(void *garbage)
@@ -761,10 +842,15 @@ static void hardware_enable(void *garbage)
        u64 old;
 
        rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
-       if ((old & 5) != 5)
+       if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED |
+                   MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
+           != (MSR_IA32_FEATURE_CONTROL_LOCKED |
+               MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
                /* enable and lock */
-               wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5);
-       write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */
+               wrmsrl(MSR_IA32_FEATURE_CONTROL, old |
+                      MSR_IA32_FEATURE_CONTROL_LOCKED |
+                      MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED);
+       write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
        asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
                      : "memory", "cc");
 }
@@ -774,14 +860,102 @@ static void hardware_disable(void *garbage)
        asm volatile (ASM_VMX_VMXOFF : : : "cc");
 }
 
-static __init void setup_vmcs_descriptor(void)
+static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
+                                     u32 msr, u32* result)
+{
+       u32 vmx_msr_low, vmx_msr_high;
+       u32 ctl = ctl_min | ctl_opt;
+
+       rdmsr(msr, vmx_msr_low, vmx_msr_high);
+
+       ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */
+       ctl |= vmx_msr_low;  /* bit == 1 in low word  ==> must be one  */
+
+       /* Ensure minimum (required) set of control bits are supported. */
+       if (ctl_min & ~ctl)
+               return -EIO;
+
+       *result = ctl;
+       return 0;
+}
+
+static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
 {
        u32 vmx_msr_low, vmx_msr_high;
+       u32 min, opt;
+       u32 _pin_based_exec_control = 0;
+       u32 _cpu_based_exec_control = 0;
+       u32 _vmexit_control = 0;
+       u32 _vmentry_control = 0;
+
+       min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING;
+       opt = 0;
+       if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS,
+                               &_pin_based_exec_control) < 0)
+               return -EIO;
+
+       min = CPU_BASED_HLT_EXITING |
+#ifdef CONFIG_X86_64
+             CPU_BASED_CR8_LOAD_EXITING |
+             CPU_BASED_CR8_STORE_EXITING |
+#endif
+             CPU_BASED_USE_IO_BITMAPS |
+             CPU_BASED_MOV_DR_EXITING |
+             CPU_BASED_USE_TSC_OFFSETING;
+#ifdef CONFIG_X86_64
+       opt = CPU_BASED_TPR_SHADOW;
+#else
+       opt = 0;
+#endif
+       if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
+                               &_cpu_based_exec_control) < 0)
+               return -EIO;
+#ifdef CONFIG_X86_64
+       if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
+               _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
+                                          ~CPU_BASED_CR8_STORE_EXITING;
+#endif
+
+       min = 0;
+#ifdef CONFIG_X86_64
+       min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
+#endif
+       opt = 0;
+       if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
+                               &_vmexit_control) < 0)
+               return -EIO;
+
+       min = opt = 0;
+       if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
+                               &_vmentry_control) < 0)
+               return -EIO;
 
        rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high);
-       vmcs_descriptor.size = vmx_msr_high & 0x1fff;
-       vmcs_descriptor.order = get_order(vmcs_descriptor.size);
-       vmcs_descriptor.revision_id = vmx_msr_low;
+
+       /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
+       if ((vmx_msr_high & 0x1fff) > PAGE_SIZE)
+               return -EIO;
+
+#ifdef CONFIG_X86_64
+       /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */
+       if (vmx_msr_high & (1u<<16))
+               return -EIO;
+#endif
+
+       /* Require Write-Back (WB) memory type for VMCS accesses. */
+       if (((vmx_msr_high >> 18) & 15) != 6)
+               return -EIO;
+
+       vmcs_conf->size = vmx_msr_high & 0x1fff;
+       vmcs_conf->order = get_order(vmcs_config.size);
+       vmcs_conf->revision_id = vmx_msr_low;
+
+       vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
+       vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
+       vmcs_conf->vmexit_ctrl         = _vmexit_control;
+       vmcs_conf->vmentry_ctrl        = _vmentry_control;
+
+       return 0;
 }
 
 static struct vmcs *alloc_vmcs_cpu(int cpu)
@@ -790,12 +964,12 @@ static struct vmcs *alloc_vmcs_cpu(int cpu)
        struct page *pages;
        struct vmcs *vmcs;
 
-       pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order);
+       pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order);
        if (!pages)
                return NULL;
        vmcs = page_address(pages);
-       memset(vmcs, 0, vmcs_descriptor.size);
-       vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */
+       memset(vmcs, 0, vmcs_config.size);
+       vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */
        return vmcs;
 }
 
@@ -806,7 +980,7 @@ static struct vmcs *alloc_vmcs(void)
 
 static void free_vmcs(struct vmcs *vmcs)
 {
-       free_pages((unsigned long)vmcs, vmcs_descriptor.order);
+       free_pages((unsigned long)vmcs, vmcs_config.order);
 }
 
 static void free_kvm_area(void)
@@ -817,8 +991,6 @@ static void free_kvm_area(void)
                free_vmcs(per_cpu(vmxarea, cpu));
 }
 
-extern struct vmcs *alloc_vmcs_cpu(int cpu);
-
 static __init int alloc_kvm_area(void)
 {
        int cpu;
@@ -839,7 +1011,8 @@ static __init int alloc_kvm_area(void)
 
 static __init int hardware_setup(void)
 {
-       setup_vmcs_descriptor();
+       if (setup_vmcs_config(&vmcs_config) < 0)
+               return -EIO;
        return alloc_kvm_area();
 }
 
@@ -879,8 +1052,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
        flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT);
        vmcs_writel(GUEST_RFLAGS, flags);
 
-       vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) |
-                       (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK));
+       vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
+                       (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME));
 
        update_exception_bitmap(vcpu);
 
@@ -897,7 +1070,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
        vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
 }
 
-static int rmode_tss_base(struct kvm* kvm)
+static gva_t rmode_tss_base(struct kvm* kvm)
 {
        gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3;
        return base_gfn << PAGE_SHIFT;
@@ -937,7 +1110,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
        flags |= IOPL_MASK | X86_EFLAGS_VM;
 
        vmcs_writel(GUEST_RFLAGS, flags);
-       vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK);
+       vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
        update_exception_bitmap(vcpu);
 
        vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4);
@@ -975,10 +1148,10 @@ static void enter_lmode(struct kvm_vcpu *vcpu)
 
        vcpu->shadow_efer |= EFER_LMA;
 
-       find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME;
+       find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME;
        vmcs_write32(VM_ENTRY_CONTROLS,
                     vmcs_read32(VM_ENTRY_CONTROLS)
-                    | VM_ENTRY_CONTROLS_IA32E_MASK);
+                    | VM_ENTRY_IA32E_MODE);
 }
 
 static void exit_lmode(struct kvm_vcpu *vcpu)
@@ -987,7 +1160,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
 
        vmcs_write32(VM_ENTRY_CONTROLS,
                     vmcs_read32(VM_ENTRY_CONTROLS)
-                    & ~VM_ENTRY_CONTROLS_IA32E_MASK);
+                    & ~VM_ENTRY_IA32E_MODE);
 }
 
 #endif
@@ -1002,17 +1175,17 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
        vmx_fpu_deactivate(vcpu);
 
-       if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
+       if (vcpu->rmode.active && (cr0 & X86_CR0_PE))
                enter_pmode(vcpu);
 
-       if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
+       if (!vcpu->rmode.active && !(cr0 & X86_CR0_PE))
                enter_rmode(vcpu);
 
 #ifdef CONFIG_X86_64
        if (vcpu->shadow_efer & EFER_LME) {
-               if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK))
+               if (!is_paging(vcpu) && (cr0 & X86_CR0_PG))
                        enter_lmode(vcpu);
-               if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK))
+               if (is_paging(vcpu) && !(cr0 & X86_CR0_PG))
                        exit_lmode(vcpu);
        }
 #endif
@@ -1022,14 +1195,14 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
                    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
        vcpu->cr0 = cr0;
 
-       if (!(cr0 & CR0_TS_MASK) || !(cr0 & CR0_PE_MASK))
+       if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE))
                vmx_fpu_activate(vcpu);
 }
 
 static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
        vmcs_writel(GUEST_CR3, cr3);
-       if (vcpu->cr0 & CR0_PE_MASK)
+       if (vcpu->cr0 & X86_CR0_PE)
                vmx_fpu_deactivate(vcpu);
 }
 
@@ -1045,23 +1218,24 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 
 static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
-       struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
 
        vcpu->shadow_efer = efer;
        if (efer & EFER_LMA) {
                vmcs_write32(VM_ENTRY_CONTROLS,
                                     vmcs_read32(VM_ENTRY_CONTROLS) |
-                                    VM_ENTRY_CONTROLS_IA32E_MASK);
+                                    VM_ENTRY_IA32E_MODE);
                msr->data = efer;
 
        } else {
                vmcs_write32(VM_ENTRY_CONTROLS,
                                     vmcs_read32(VM_ENTRY_CONTROLS) &
-                                    ~VM_ENTRY_CONTROLS_IA32E_MASK);
+                                    ~VM_ENTRY_IA32E_MODE);
 
                msr->data = efer & ~EFER_LME;
        }
-       setup_msrs(vcpu);
+       setup_msrs(vmx);
 }
 
 #endif
@@ -1210,17 +1384,6 @@ static int init_rmode_tss(struct kvm* kvm)
        return 1;
 }
 
-static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val)
-{
-       u32 msr_high, msr_low;
-
-       rdmsr(msr, msr_low, msr_high);
-
-       val &= msr_high;
-       val |= msr_low;
-       vmcs_write32(vmcs_field, val);
-}
-
 static void seg_setup(int seg)
 {
        struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -1234,7 +1397,7 @@ static void seg_setup(int seg)
 /*
  * Sets up the vmcs for emulated real mode.
  */
-static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
+static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 {
        u32 host_sysenter_cs;
        u32 junk;
@@ -1243,27 +1406,36 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
        int i;
        int ret = 0;
        unsigned long kvm_vmx_return;
+       u64 msr;
+       u32 exec_control;
 
-       if (!init_rmode_tss(vcpu->kvm)) {
+       if (!init_rmode_tss(vmx->vcpu.kvm)) {
                ret = -ENOMEM;
                goto out;
        }
 
-       memset(vcpu->regs, 0, sizeof(vcpu->regs));
-       vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val();
-       vcpu->cr8 = 0;
-       vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
-       if (vcpu == &vcpu->kvm->vcpus[0])
-               vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+       vmx->vcpu.rmode.active = 0;
 
-       fx_init(vcpu);
+       vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val();
+       set_cr8(&vmx->vcpu, 0);
+       msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+       if (vmx->vcpu.vcpu_id == 0)
+               msr |= MSR_IA32_APICBASE_BSP;
+       kvm_set_apic_base(&vmx->vcpu, msr);
+
+       fx_init(&vmx->vcpu);
 
        /*
         * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
         * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4.  Sigh.
         */
-       vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
-       vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+       if (vmx->vcpu.vcpu_id == 0) {
+               vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
+               vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+       } else {
+               vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8);
+               vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12);
+       }
        vmcs_write32(GUEST_CS_LIMIT, 0xffff);
        vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
 
@@ -1288,7 +1460,10 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
        vmcs_writel(GUEST_SYSENTER_EIP, 0);
 
        vmcs_writel(GUEST_RFLAGS, 0x02);
-       vmcs_writel(GUEST_RIP, 0xfff0);
+       if (vmx->vcpu.vcpu_id == 0)
+               vmcs_writel(GUEST_RIP, 0xfff0);
+       else
+               vmcs_writel(GUEST_RIP, 0);
        vmcs_writel(GUEST_RSP, 0);
 
        //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0
@@ -1316,20 +1491,18 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
        vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 
        /* Control */
-       vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS,
-                              PIN_BASED_VM_EXEC_CONTROL,
-                              PIN_BASED_EXT_INTR_MASK   /* 20.6.1 */
-                              | PIN_BASED_NMI_EXITING   /* 20.6.1 */
-                       );
-       vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS,
-                              CPU_BASED_VM_EXEC_CONTROL,
-                              CPU_BASED_HLT_EXITING         /* 20.6.2 */
-                              | CPU_BASED_CR8_LOAD_EXITING    /* 20.6.2 */
-                              | CPU_BASED_CR8_STORE_EXITING   /* 20.6.2 */
-                              | CPU_BASED_ACTIVATE_IO_BITMAP  /* 20.6.2 */
-                              | CPU_BASED_MOV_DR_EXITING
-                              | CPU_BASED_USE_TSC_OFFSETING   /* 21.3 */
-                       );
+       vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
+               vmcs_config.pin_based_exec_ctrl);
+
+       exec_control = vmcs_config.cpu_based_exec_ctrl;
+       if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
+               exec_control &= ~CPU_BASED_TPR_SHADOW;
+#ifdef CONFIG_X86_64
+               exec_control |= CPU_BASED_CR8_STORE_EXITING |
+                               CPU_BASED_CR8_LOAD_EXITING;
+#endif
+       }
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
 
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
@@ -1377,46 +1550,48 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
                u32 index = vmx_msr_index[i];
                u32 data_low, data_high;
                u64 data;
-               int j = vcpu->nmsrs;
+               int j = vmx->nmsrs;
 
                if (rdmsr_safe(index, &data_low, &data_high) < 0)
                        continue;
                if (wrmsr_safe(index, data_low, data_high) < 0)
                        continue;
                data = data_low | ((u64)data_high << 32);
-               vcpu->host_msrs[j].index = index;
-               vcpu->host_msrs[j].reserved = 0;
-               vcpu->host_msrs[j].data = data;
-               vcpu->guest_msrs[j] = vcpu->host_msrs[j];
-               ++vcpu->nmsrs;
+               vmx->host_msrs[j].index = index;
+               vmx->host_msrs[j].reserved = 0;
+               vmx->host_msrs[j].data = data;
+               vmx->guest_msrs[j] = vmx->host_msrs[j];
+               ++vmx->nmsrs;
        }
 
-       setup_msrs(vcpu);
+       setup_msrs(vmx);
 
-       vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS,
-                              (HOST_IS_64 << 9));  /* 22.2,1, 20.7.1 */
+       vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
 
        /* 22.2.1, 20.8.1 */
-       vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS,
-                               VM_ENTRY_CONTROLS, 0);
+       vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl);
+
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);  /* 22.2.1 */
 
 #ifdef CONFIG_X86_64
-       vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0);
-       vmcs_writel(TPR_THRESHOLD, 0);
+       vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
+       if (vm_need_tpr_shadow(vmx->vcpu.kvm))
+               vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
+                            page_to_phys(vmx->vcpu.apic->regs_page));
+       vmcs_write32(TPR_THRESHOLD, 0);
 #endif
 
        vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
        vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
 
-       vcpu->cr0 = 0x60000010;
-       vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode
-       vmx_set_cr4(vcpu, 0);
+       vmx->vcpu.cr0 = 0x60000010;
+       vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode
+       vmx_set_cr4(&vmx->vcpu, 0);
 #ifdef CONFIG_X86_64
-       vmx_set_efer(vcpu, 0);
+       vmx_set_efer(&vmx->vcpu, 0);
 #endif
-       vmx_fpu_activate(vcpu);
-       update_exception_bitmap(vcpu);
+       vmx_fpu_activate(&vmx->vcpu);
+       update_exception_bitmap(&vmx->vcpu);
 
        return 0;
 
@@ -1424,6 +1599,13 @@ out:
        return ret;
 }
 
+static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       vmx_vcpu_setup(vmx);
+}
+
 static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
 {
        u16 ent[2];
@@ -1443,8 +1625,8 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
                return;
        }
 
-       if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) !=
-                                                               sizeof(ent)) {
+       if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) !=
+                                                       X86EMUL_CONTINUE) {
                vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__);
                return;
        }
@@ -1454,9 +1636,9 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
        ip =  vmcs_readl(GUEST_RIP);
 
 
-       if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 ||
-           kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 ||
-           kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) {
+       if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE ||
+           emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE ||
+           emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) {
                vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__);
                return;
        }
@@ -1469,6 +1651,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
        vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
 }
 
+static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
+{
+       if (vcpu->rmode.active) {
+               inject_rmode_irq(vcpu, irq);
+               return;
+       }
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                       irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
 static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
 {
        int word_index = __ffs(vcpu->irq_summary);
@@ -1478,13 +1670,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
        clear_bit(bit_index, &vcpu->irq_pending[word_index]);
        if (!vcpu->irq_pending[word_index])
                clear_bit(word_index, &vcpu->irq_summary);
-
-       if (vcpu->rmode.active) {
-               inject_rmode_irq(vcpu, irq);
-               return;
-       }
-       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-                       irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+       vmx_inject_irq(vcpu, irq);
 }
 
 
@@ -1568,7 +1754,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                       "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
        }
 
-       if (is_external_interrupt(vect_info)) {
+       if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
                int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
                set_bit(irq, vcpu->irq_pending);
                set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
@@ -1591,29 +1777,28 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        if (is_page_fault(intr_info)) {
                cr2 = vmcs_readl(EXIT_QUALIFICATION);
 
-               spin_lock(&vcpu->kvm->lock);
+               mutex_lock(&vcpu->kvm->lock);
                r = kvm_mmu_page_fault(vcpu, cr2, error_code);
                if (r < 0) {
-                       spin_unlock(&vcpu->kvm->lock);
+                       mutex_unlock(&vcpu->kvm->lock);
                        return r;
                }
                if (!r) {
-                       spin_unlock(&vcpu->kvm->lock);
+                       mutex_unlock(&vcpu->kvm->lock);
                        return 1;
                }
 
                er = emulate_instruction(vcpu, kvm_run, cr2, error_code);
-               spin_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&vcpu->kvm->lock);
 
                switch (er) {
                case EMULATE_DONE:
                        return 1;
                case EMULATE_DO_MMIO:
                        ++vcpu->stat.mmio_exits;
-                       kvm_run->exit_reason = KVM_EXIT_MMIO;
                        return 0;
                 case EMULATE_FAIL:
-                       vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+                       kvm_report_emulation_failure(vcpu, "pagetable");
                        break;
                default:
                        BUG();
@@ -1653,80 +1838,29 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 0;
 }
 
-static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count)
-{
-       u64 inst;
-       gva_t rip;
-       int countr_size;
-       int i, n;
-
-       if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) {
-               countr_size = 2;
-       } else {
-               u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
-
-               countr_size = (cs_ar & AR_L_MASK) ? 8:
-                             (cs_ar & AR_DB_MASK) ? 4: 2;
-       }
-
-       rip =  vmcs_readl(GUEST_RIP);
-       if (countr_size != 8)
-               rip += vmcs_readl(GUEST_CS_BASE);
-
-       n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst);
-
-       for (i = 0; i < n; i++) {
-               switch (((u8*)&inst)[i]) {
-               case 0xf0:
-               case 0xf2:
-               case 0xf3:
-               case 0x2e:
-               case 0x36:
-               case 0x3e:
-               case 0x26:
-               case 0x64:
-               case 0x65:
-               case 0x66:
-                       break;
-               case 0x67:
-                       countr_size = (countr_size == 2) ? 4: (countr_size >> 1);
-               default:
-                       goto done;
-               }
-       }
-       return 0;
-done:
-       countr_size *= 8;
-       *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size));
-       //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]);
-       return 1;
-}
-
 static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        int size, down, in, string, rep;
        unsigned port;
-       unsigned long count;
-       gva_t address;
 
        ++vcpu->stat.io_exits;
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
-       in = (exit_qualification & 8) != 0;
-       size = (exit_qualification & 7) + 1;
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        string = (exit_qualification & 16) != 0;
+
+       if (string) {
+               if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
+                       return 0;
+               return 1;
+       }
+
+       size = (exit_qualification & 7) + 1;
+       in = (exit_qualification & 8) != 0;
        down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
-       count = 1;
        rep = (exit_qualification & 32) != 0;
        port = exit_qualification >> 16;
-       address = 0;
-       if (string) {
-               if (rep && !get_io_count(vcpu, &count))
-                       return 1;
-               address = vmcs_readl(GUEST_LINEAR_ADDRESS);
-       }
-       return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
-                            address, rep, port);
+
+       return kvm_emulate_pio(vcpu, kvm_run, in, size, port);
 }
 
 static void
@@ -1743,11 +1877,11 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
 
 static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        int cr;
        int reg;
 
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        cr = exit_qualification & 15;
        reg = (exit_qualification >> 8) & 15;
        switch ((exit_qualification >> 4) & 3) {
@@ -1772,13 +1906,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        vcpu_load_rsp_rip(vcpu);
                        set_cr8(vcpu, vcpu->regs[reg]);
                        skip_emulated_instruction(vcpu);
-                       return 1;
+                       kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+                       return 0;
                };
                break;
        case 2: /* clts */
                vcpu_load_rsp_rip(vcpu);
                vmx_fpu_deactivate(vcpu);
-               vcpu->cr0 &= ~CR0_TS_MASK;
+               vcpu->cr0 &= ~X86_CR0_TS;
                vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
                vmx_fpu_activate(vcpu);
                skip_emulated_instruction(vcpu);
@@ -1793,7 +1928,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        return 1;
                case 8:
                        vcpu_load_rsp_rip(vcpu);
-                       vcpu->regs[reg] = vcpu->cr8;
+                       vcpu->regs[reg] = get_cr8(vcpu);
                        vcpu_put_rsp_rip(vcpu);
                        skip_emulated_instruction(vcpu);
                        return 1;
@@ -1808,14 +1943,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                break;
        }
        kvm_run->exit_reason = 0;
-       printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n",
+       pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
               (int)(exit_qualification >> 4) & 3, cr);
        return 0;
 }
 
 static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        unsigned long val;
        int dr, reg;
 
@@ -1823,7 +1958,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
         * FIXME: this code assumes the host is debugging the guest.
         *        need to deal with guest debugging itself too.
         */
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        dr = exit_qualification & 7;
        reg = (exit_qualification >> 8) & 15;
        vcpu_load_rsp_rip(vcpu);
@@ -1886,19 +2021,21 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
-                             struct kvm_run *kvm_run)
+static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
+                                     struct kvm_run *kvm_run)
 {
-       kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
-       kvm_run->cr8 = vcpu->cr8;
-       kvm_run->apic_base = vcpu->apic_base;
-       kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
-                                                 vcpu->irq_summary == 0);
+       return 1;
 }
 
 static int handle_interrupt_window(struct kvm_vcpu *vcpu,
                                   struct kvm_run *kvm_run)
 {
+       u32 cpu_based_vm_exec_control;
+
+       /* clear pending irq */
+       cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+       cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
        /*
         * If the user space waits to inject interrupts, exit as soon as
         * possible
@@ -1943,6 +2080,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
        [EXIT_REASON_PENDING_INTERRUPT]       = handle_interrupt_window,
        [EXIT_REASON_HLT]                     = handle_halt,
        [EXIT_REASON_VMCALL]                  = handle_vmcall,
+       [EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -1956,6 +2094,14 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
        u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
        u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (unlikely(vmx->fail)) {
+               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+               kvm_run->fail_entry.hardware_entry_failure_reason
+                       = vmcs_read32(VM_INSTRUCTION_ERROR);
+               return 0;
+       }
 
        if ( (vectoring_info & VECTORING_INFO_VALID_MASK) &&
                                exit_reason != EXIT_REASON_EXCEPTION_NMI )
@@ -1971,57 +2117,91 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        return 0;
 }
 
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
-                                         struct kvm_run *kvm_run)
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
 {
-       return (!vcpu->irq_summary &&
-               kvm_run->request_interrupt_window &&
-               vcpu->interrupt_window_open &&
-               (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
 }
 
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+static void update_tpr_threshold(struct kvm_vcpu *vcpu)
 {
+       int max_irr, tpr;
+
+       if (!vm_need_tpr_shadow(vcpu->kvm))
+               return;
+
+       if (!kvm_lapic_enabled(vcpu) ||
+           ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) {
+               vmcs_write32(TPR_THRESHOLD, 0);
+               return;
+       }
+
+       tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4;
+       vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
 }
 
-static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
-       u8 fail;
-       int r;
+       u32 cpu_based_vm_exec_control;
 
-preempted:
-       if (vcpu->guest_debug.enabled)
-               kvm_guest_debug_pre(vcpu);
+       cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+       cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
 
-again:
-       if (!vcpu->mmio_read_completed)
-               do_interrupt_requests(vcpu, kvm_run);
+static void vmx_intr_assist(struct kvm_vcpu *vcpu)
+{
+       u32 idtv_info_field, intr_info_field;
+       int has_ext_irq, interrupt_window_open;
+       int vector;
 
-       vmx_save_host_state(vcpu);
-       kvm_load_guest_fpu(vcpu);
+       kvm_inject_pending_timer_irqs(vcpu);
+       update_tpr_threshold(vcpu);
 
-       r = kvm_mmu_reload(vcpu);
-       if (unlikely(r))
-               goto out;
+       has_ext_irq = kvm_cpu_has_interrupt(vcpu);
+       intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
+       idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       if (intr_info_field & INTR_INFO_VALID_MASK) {
+               if (idtv_info_field & INTR_INFO_VALID_MASK) {
+                       /* TODO: fault when IDT_Vectoring */
+                       printk(KERN_ERR "Fault when IDT_Vectoring\n");
+               }
+               if (has_ext_irq)
+                       enable_irq_window(vcpu);
+               return;
+       }
+       if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
+               vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+                               vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
+
+               if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
+                       vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
+                               vmcs_read32(IDT_VECTORING_ERROR_CODE));
+               if (unlikely(has_ext_irq))
+                       enable_irq_window(vcpu);
+               return;
+       }
+       if (!has_ext_irq)
+               return;
+       interrupt_window_open =
+               ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+                (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
+       if (interrupt_window_open) {
+               vector = kvm_cpu_get_interrupt(vcpu);
+               vmx_inject_irq(vcpu, vector);
+               kvm_timer_intr_post(vcpu, vector);
+       } else
+               enable_irq_window(vcpu);
+}
+
+static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
 
        /*
         * Loading guest fpu may have cleared host cr0.ts
         */
        vmcs_writel(HOST_CR0, read_cr0());
 
-       local_irq_disable();
-
-       vcpu->guest_mode = 1;
-       if (vcpu->requests)
-               if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
-                   vmx_flush_tlb(vcpu);
-
        asm (
                /* Store host registers */
 #ifdef CONFIG_X86_64
@@ -2115,8 +2295,8 @@ again:
                "pop %%ecx; popa \n\t"
 #endif
                "setbe %0 \n\t"
-             : "=q" (fail)
-             : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
+             : "=q" (vmx->fail)
+             : "r"(vmx->launched), "d"((unsigned long)HOST_RSP),
                "c"(vcpu),
                [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
                [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
@@ -2138,59 +2318,10 @@ again:
                [cr2]"i"(offsetof(struct kvm_vcpu, cr2))
              : "cc", "memory" );
 
-       vcpu->guest_mode = 0;
-       local_irq_enable();
-
-       ++vcpu->stat.exits;
-
        vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
 
        asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
-
-       if (unlikely(fail)) {
-               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-               kvm_run->fail_entry.hardware_entry_failure_reason
-                       = vmcs_read32(VM_INSTRUCTION_ERROR);
-               r = 0;
-               goto out;
-       }
-       /*
-        * Profile KVM exit RIPs:
-        */
-       if (unlikely(prof_on == KVM_PROFILING))
-               profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
-
-       vcpu->launched = 1;
-       r = kvm_handle_exit(kvm_run, vcpu);
-       if (r > 0) {
-               /* Give scheduler a change to reschedule. */
-               if (signal_pending(current)) {
-                       r = -EINTR;
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
-                       ++vcpu->stat.signal_exits;
-                       goto out;
-               }
-
-               if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-                       r = -EINTR;
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
-                       ++vcpu->stat.request_irq_exits;
-                       goto out;
-               }
-               if (!need_resched()) {
-                       ++vcpu->stat.light_exits;
-                       goto again;
-               }
-       }
-
-out:
-       if (r > 0) {
-               kvm_resched(vcpu);
-               goto preempted;
-       }
-
-       post_kvm_run_save(vcpu, kvm_run);
-       return r;
+       vmx->launched = 1;
 }
 
 static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
@@ -2225,67 +2356,118 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
 
 static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
 {
-       if (vcpu->vmcs) {
-               on_each_cpu(__vcpu_clear, vcpu, 0, 1);
-               free_vmcs(vcpu->vmcs);
-               vcpu->vmcs = NULL;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (vmx->vmcs) {
+               on_each_cpu(__vcpu_clear, vmx, 0, 1);
+               free_vmcs(vmx->vmcs);
+               vmx->vmcs = NULL;
        }
 }
 
 static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
 {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
        vmx_free_vmcs(vcpu);
+       kfree(vmx->host_msrs);
+       kfree(vmx->guest_msrs);
+       kvm_vcpu_uninit(vcpu);
+       kmem_cache_free(kvm_vcpu_cache, vmx);
 }
 
-static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
+static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 {
-       struct vmcs *vmcs;
+       int err;
+       struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+       int cpu;
 
-       vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!vcpu->guest_msrs)
-               return -ENOMEM;
+       if (!vmx)
+               return ERR_PTR(-ENOMEM);
 
-       vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!vcpu->host_msrs)
-               goto out_free_guest_msrs;
+       err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
+       if (err)
+               goto free_vcpu;
 
-       vmcs = alloc_vmcs();
-       if (!vmcs)
-               goto out_free_msrs;
+       if (irqchip_in_kernel(kvm)) {
+               err = kvm_create_lapic(&vmx->vcpu);
+               if (err < 0)
+                       goto free_vcpu;
+       }
 
-       vmcs_clear(vmcs);
-       vcpu->vmcs = vmcs;
-       vcpu->launched = 0;
+       vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!vmx->guest_msrs) {
+               err = -ENOMEM;
+               goto uninit_vcpu;
+       }
 
-       return 0;
+       vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!vmx->host_msrs)
+               goto free_guest_msrs;
 
-out_free_msrs:
-       kfree(vcpu->host_msrs);
-       vcpu->host_msrs = NULL;
+       vmx->vmcs = alloc_vmcs();
+       if (!vmx->vmcs)
+               goto free_msrs;
 
-out_free_guest_msrs:
-       kfree(vcpu->guest_msrs);
-       vcpu->guest_msrs = NULL;
+       vmcs_clear(vmx->vmcs);
 
-       return -ENOMEM;
+       cpu = get_cpu();
+       vmx_vcpu_load(&vmx->vcpu, cpu);
+       err = vmx_vcpu_setup(vmx);
+       vmx_vcpu_put(&vmx->vcpu);
+       put_cpu();
+       if (err)
+               goto free_vmcs;
+
+       return &vmx->vcpu;
+
+free_vmcs:
+       free_vmcs(vmx->vmcs);
+free_msrs:
+       kfree(vmx->host_msrs);
+free_guest_msrs:
+       kfree(vmx->guest_msrs);
+uninit_vcpu:
+       kvm_vcpu_uninit(&vmx->vcpu);
+free_vcpu:
+       kmem_cache_free(kvm_vcpu_cache, vmx);
+       return ERR_PTR(err);
+}
+
+static void __init vmx_check_processor_compat(void *rtn)
+{
+       struct vmcs_config vmcs_conf;
+
+       *(int *)rtn = 0;
+       if (setup_vmcs_config(&vmcs_conf) < 0)
+               *(int *)rtn = -EIO;
+       if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
+               printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
+                               smp_processor_id());
+               *(int *)rtn = -EIO;
+       }
 }
 
-static struct kvm_arch_ops vmx_arch_ops = {
+static struct kvm_x86_ops vmx_x86_ops = {
        .cpu_has_kvm_support = cpu_has_kvm_support,
        .disabled_by_bios = vmx_disabled_by_bios,
        .hardware_setup = hardware_setup,
        .hardware_unsetup = hardware_unsetup,
+       .check_processor_compatibility = vmx_check_processor_compat,
        .hardware_enable = hardware_enable,
        .hardware_disable = hardware_disable,
 
        .vcpu_create = vmx_create_vcpu,
        .vcpu_free = vmx_free_vcpu,
+       .vcpu_reset = vmx_vcpu_reset,
 
+       .prepare_guest_switch = vmx_save_host_state,
        .vcpu_load = vmx_vcpu_load,
        .vcpu_put = vmx_vcpu_put,
        .vcpu_decache = vmx_vcpu_decache,
 
        .set_guest_debug = set_guest_debug,
+       .guest_debug_pre = kvm_guest_debug_pre,
        .get_msr = vmx_get_msr,
        .set_msr = vmx_set_msr,
        .get_segment_base = vmx_get_segment_base,
@@ -2314,9 +2496,13 @@ static struct kvm_arch_ops vmx_arch_ops = {
        .inject_gp = vmx_inject_gp,
 
        .run = vmx_vcpu_run,
+       .handle_exit = kvm_handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
-       .vcpu_setup = vmx_vcpu_setup,
        .patch_hypercall = vmx_patch_hypercall,
+       .get_irq = vmx_get_irq,
+       .set_irq = vmx_inject_irq,
+       .inject_pending_irq = vmx_intr_assist,
+       .inject_pending_vectors = do_interrupt_requests,
 };
 
 static int __init vmx_init(void)
@@ -2347,7 +2533,7 @@ static int __init vmx_init(void)
        memset(iova, 0xff, PAGE_SIZE);
        kunmap(vmx_io_bitmap_b);
 
-       r = kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+       r = kvm_init_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
        if (r)
                goto out1;
 
@@ -2365,7 +2551,7 @@ static void __exit vmx_exit(void)
        __free_page(vmx_io_bitmap_b);
        __free_page(vmx_io_bitmap_a);
 
-       kvm_exit_arch();
+       kvm_exit_x86();
 }
 
 module_init(vmx_init)
index d0dc93df411b2dd940054539cbafab15a049edaa..fd4e14666088098f7af7d337bc5bc66bbd5e177c 100644 (file)
  *
  */
 
-#define CPU_BASED_VIRTUAL_INTR_PENDING  0x00000004
-#define CPU_BASED_USE_TSC_OFFSETING     0x00000008
-#define CPU_BASED_HLT_EXITING           0x00000080
-#define CPU_BASED_INVDPG_EXITING        0x00000200
-#define CPU_BASED_MWAIT_EXITING         0x00000400
-#define CPU_BASED_RDPMC_EXITING         0x00000800
-#define CPU_BASED_RDTSC_EXITING         0x00001000
-#define CPU_BASED_CR8_LOAD_EXITING      0x00080000
-#define CPU_BASED_CR8_STORE_EXITING     0x00100000
-#define CPU_BASED_TPR_SHADOW            0x00200000
-#define CPU_BASED_MOV_DR_EXITING        0x00800000
-#define CPU_BASED_UNCOND_IO_EXITING     0x01000000
-#define CPU_BASED_ACTIVATE_IO_BITMAP    0x02000000
-#define CPU_BASED_MSR_BITMAPS           0x10000000
-#define CPU_BASED_MONITOR_EXITING       0x20000000
-#define CPU_BASED_PAUSE_EXITING         0x40000000
+#define CPU_BASED_VIRTUAL_INTR_PENDING          0x00000004
+#define CPU_BASED_USE_TSC_OFFSETING             0x00000008
+#define CPU_BASED_HLT_EXITING                   0x00000080
+#define CPU_BASED_INVLPG_EXITING                0x00000200
+#define CPU_BASED_MWAIT_EXITING                 0x00000400
+#define CPU_BASED_RDPMC_EXITING                 0x00000800
+#define CPU_BASED_RDTSC_EXITING                 0x00001000
+#define CPU_BASED_CR8_LOAD_EXITING              0x00080000
+#define CPU_BASED_CR8_STORE_EXITING             0x00100000
+#define CPU_BASED_TPR_SHADOW                    0x00200000
+#define CPU_BASED_MOV_DR_EXITING                0x00800000
+#define CPU_BASED_UNCOND_IO_EXITING             0x01000000
+#define CPU_BASED_USE_IO_BITMAPS                0x02000000
+#define CPU_BASED_USE_MSR_BITMAPS               0x10000000
+#define CPU_BASED_MONITOR_EXITING               0x20000000
+#define CPU_BASED_PAUSE_EXITING                 0x40000000
+#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS   0x80000000
 
-#define PIN_BASED_EXT_INTR_MASK 0x1
-#define PIN_BASED_NMI_EXITING   0x8
+#define PIN_BASED_EXT_INTR_MASK                 0x00000001
+#define PIN_BASED_NMI_EXITING                   0x00000008
+#define PIN_BASED_VIRTUAL_NMIS                  0x00000020
 
-#define VM_EXIT_ACK_INTR_ON_EXIT        0x00008000
-#define VM_EXIT_HOST_ADD_SPACE_SIZE     0x00000200
+#define VM_EXIT_HOST_ADDR_SPACE_SIZE            0x00000200
+#define VM_EXIT_ACK_INTR_ON_EXIT                0x00008000
 
+#define VM_ENTRY_IA32E_MODE                     0x00000200
+#define VM_ENTRY_SMM                            0x00000400
+#define VM_ENTRY_DEACT_DUAL_MONITOR             0x00000800
+
+#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
 
 /* VMCS Encodings */
 enum vmcs_field {
@@ -206,6 +213,7 @@ enum vmcs_field {
 #define EXIT_REASON_MSR_READ            31
 #define EXIT_REASON_MSR_WRITE           32
 #define EXIT_REASON_MWAIT_INSTRUCTION   36
+#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
 
 /*
  * Interruption-information format
@@ -261,9 +269,6 @@ enum vmcs_field {
 /* segment AR */
 #define SEGMENT_AR_L_MASK (1 << 13)
 
-/* entry controls */
-#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9)
-
 #define AR_TYPE_ACCESSES_MASK 1
 #define AR_TYPE_READABLE_MASK (1 << 1)
 #define AR_TYPE_WRITEABLE_MASK (1 << 2)
@@ -285,13 +290,21 @@ enum vmcs_field {
 
 #define AR_RESERVD_MASK 0xfffe0f00
 
-#define CR4_VMXE 0x2000
+#define MSR_IA32_VMX_BASIC                      0x480
+#define MSR_IA32_VMX_PINBASED_CTLS              0x481
+#define MSR_IA32_VMX_PROCBASED_CTLS             0x482
+#define MSR_IA32_VMX_EXIT_CTLS                  0x483
+#define MSR_IA32_VMX_ENTRY_CTLS                 0x484
+#define MSR_IA32_VMX_MISC                       0x485
+#define MSR_IA32_VMX_CR0_FIXED0                 0x486
+#define MSR_IA32_VMX_CR0_FIXED1                 0x487
+#define MSR_IA32_VMX_CR4_FIXED0                 0x488
+#define MSR_IA32_VMX_CR4_FIXED1                 0x489
+#define MSR_IA32_VMX_VMCS_ENUM                  0x48a
+#define MSR_IA32_VMX_PROCBASED_CTLS2            0x48b
 
-#define MSR_IA32_VMX_BASIC             0x480
-#define MSR_IA32_FEATURE_CONTROL               0x03a
-#define MSR_IA32_VMX_PINBASED_CTLS             0x481
-#define MSR_IA32_VMX_PROCBASED_CTLS            0x482
-#define MSR_IA32_VMX_EXIT_CTLS         0x483
-#define MSR_IA32_VMX_ENTRY_CTLS                0x484
+#define MSR_IA32_FEATURE_CONTROL                0x3a
+#define MSR_IA32_FEATURE_CONTROL_LOCKED         0x1
+#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED  0x4
 
 #endif
index 4b8a0cc9665eda6662c5248782ec846e1e6367e7..9737c3b2f48c1a2006cd6420ce192f04a323c7e3 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (c) 2005 Keir Fraser
  *
  * Linux coding style, mod r/m decoder, segment base fixes, real-mode
- * privieged instructions:
+ * privileged instructions:
  *
  * Copyright (C) 2006 Qumranet
  *
@@ -83,7 +83,7 @@ static u8 opcode_table[256] = {
        /* 0x20 - 0x27 */
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-       0, 0, 0, 0,
+       SrcImmByte, SrcImm, 0, 0,
        /* 0x28 - 0x2F */
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -99,15 +99,24 @@ static u8 opcode_table[256] = {
        /* 0x40 - 0x4F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x50 - 0x57 */
-       0, 0, 0, 0, 0, 0, 0, 0,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
        /* 0x58 - 0x5F */
        ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
        ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-       /* 0x60 - 0x6F */
+       /* 0x60 - 0x67 */
        0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       /* 0x70 - 0x7F */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0,
+       /* 0x68 - 0x6F */
+       0, 0, ImplicitOps|Mov, 0,
+       SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* insb, insw/insd */
+       SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* outsb, outsw/outsd */
+       /* 0x70 - 0x77 */
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       /* 0x78 - 0x7F */
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
        /* 0x80 - 0x87 */
        ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
        ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
@@ -116,9 +125,9 @@ static u8 opcode_table[256] = {
        /* 0x88 - 0x8F */
        ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
        ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-       0, 0, 0, DstMem | SrcNone | ModRM | Mov,
+       0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov,
        /* 0x90 - 0x9F */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0,
        /* 0xA0 - 0xA7 */
        ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov,
        ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov,
@@ -142,8 +151,10 @@ static u8 opcode_table[256] = {
        0, 0, 0, 0,
        /* 0xD8 - 0xDF */
        0, 0, 0, 0, 0, 0, 0, 0,
-       /* 0xE0 - 0xEF */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xE0 - 0xE7 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xE8 - 0xEF */
+       ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0,
        /* 0xF0 - 0xF7 */
        0, 0, 0, 0,
        ImplicitOps, 0,
@@ -181,7 +192,10 @@ static u16 twobyte_table[256] = {
        /* 0x70 - 0x7F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x80 - 0x8F */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
        /* 0x90 - 0x9F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xA0 - 0xA7 */
@@ -207,19 +221,6 @@ static u16 twobyte_table[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
-/*
- * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we
- * are interested only in invlpg and not in any of the rest.
- *
- * invlpg is a special instruction in that the data it references may not
- * be mapped.
- */
-void kvm_emulator_want_group7_invlpg(void)
-{
-       twobyte_table[1] &= ~SrcMem;
-}
-EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg);
-
 /* Type, address-of, and value of an instruction's operand. */
 struct operand {
        enum { OP_REG, OP_MEM, OP_IMM } type;
@@ -420,7 +421,7 @@ struct operand {
 #define insn_fetch(_type, _size, _eip)                                  \
 ({     unsigned long _x;                                               \
        rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x,  \
-                                                  (_size), ctxt);       \
+                                                  (_size), ctxt->vcpu); \
        if ( rc != 0 )                                                  \
                goto done;                                              \
        (_eip) += (_size);                                              \
@@ -428,10 +429,11 @@ struct operand {
 })
 
 /* Access/update address held in a register, based on addressing mode. */
+#define address_mask(reg)                                              \
+       ((ad_bytes == sizeof(unsigned long)) ?                          \
+               (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1)))
 #define register_address(base, reg)                                     \
-       ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) :        \
-                  ((reg) & ((1UL << (ad_bytes << 3)) - 1))))
-
+       ((base) + address_mask(reg))
 #define register_address_increment(reg, inc)                            \
        do {                                                            \
                /* signed type ensures sign extension to long */        \
@@ -443,8 +445,19 @@ struct operand {
                           (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
        } while (0)
 
-void *decode_register(u8 modrm_reg, unsigned long *regs,
-                     int highbyte_regs)
+#define JMP_REL(rel)                                                   \
+       do {                                                            \
+               _eip += (int)(rel);                                     \
+               _eip = ((op_bytes == 2) ? (uint16_t)_eip : (uint32_t)_eip); \
+       } while (0)
+
+/*
+ * Given the 'reg' portion of a ModRM byte, and a register block, return a
+ * pointer into the block that addresses the relevant register.
+ * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
+ */
+static void *decode_register(u8 modrm_reg, unsigned long *regs,
+                            int highbyte_regs)
 {
        void *p;
 
@@ -464,13 +477,50 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
        if (op_bytes == 2)
                op_bytes = 3;
        *address = 0;
-       rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt);
+       rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
+                          ctxt->vcpu);
        if (rc)
                return rc;
-       rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt);
+       rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
+                          ctxt->vcpu);
        return rc;
 }
 
+static int test_cc(unsigned int condition, unsigned int flags)
+{
+       int rc = 0;
+
+       switch ((condition & 15) >> 1) {
+       case 0: /* o */
+               rc |= (flags & EFLG_OF);
+               break;
+       case 1: /* b/c/nae */
+               rc |= (flags & EFLG_CF);
+               break;
+       case 2: /* z/e */
+               rc |= (flags & EFLG_ZF);
+               break;
+       case 3: /* be/na */
+               rc |= (flags & (EFLG_CF|EFLG_ZF));
+               break;
+       case 4: /* s */
+               rc |= (flags & EFLG_SF);
+               break;
+       case 5: /* p/pe */
+               rc |= (flags & EFLG_PF);
+               break;
+       case 7: /* le/ng */
+               rc |= (flags & EFLG_ZF);
+               /* fall through */
+       case 6: /* l/nge */
+               rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));
+               break;
+       }
+
+       /* Odd condition identifiers (lsb == 1) have inverted sense. */
+       return (!!rc ^ (condition & 1));
+}
+
 int
 x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
@@ -771,11 +821,15 @@ done_prefixes:
                goto srcmem_common;
        case SrcMem:
                src.bytes = (d & ByteOp) ? 1 : op_bytes;
+               /* Don't fetch the address for invlpg: it could be unmapped. */
+               if (twobyte && b == 0x01 && modrm_reg == 7)
+                       break;
              srcmem_common:
                src.type = OP_MEM;
                src.ptr = (unsigned long *)cr2;
+               src.val = 0;
                if ((rc = ops->read_emulated((unsigned long)src.ptr,
-                                            &src.val, src.bytes, ctxt)) != 0)
+                                            &src.val, src.bytes, ctxt->vcpu)) != 0)
                        goto done;
                src.orig_val = src.val;
                break;
@@ -814,7 +868,7 @@ done_prefixes:
        case DstReg:
                dst.type = OP_REG;
                if ((d & ByteOp)
-                   && !(twobyte_table && (b == 0xb6 || b == 0xb7))) {
+                   && !(twobyte && (b == 0xb6 || b == 0xb7))) {
                        dst.ptr = decode_register(modrm_reg, _regs,
                                                  (rex_prefix == 0));
                        dst.val = *(u8 *) dst.ptr;
@@ -838,6 +892,7 @@ done_prefixes:
                dst.type = OP_MEM;
                dst.ptr = (unsigned long *)cr2;
                dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+               dst.val = 0;
                if (d & BitOp) {
                        unsigned long mask = ~(dst.bytes * 8 - 1);
 
@@ -845,7 +900,7 @@ done_prefixes:
                }
                if (!(d & Mov) && /* optimisation - avoid slow emulated read */
                    ((rc = ops->read_emulated((unsigned long)dst.ptr,
-                                             &dst.val, dst.bytes, ctxt)) != 0))
+                                             &dst.val, dst.bytes, ctxt->vcpu)) != 0))
                        goto done;
                break;
        }
@@ -871,10 +926,27 @@ done_prefixes:
              sbb:              /* sbb */
                emulate_2op_SrcV("sbb", src, dst, _eflags);
                break;
-       case 0x20 ... 0x25:
+       case 0x20 ... 0x23:
              and:              /* and */
                emulate_2op_SrcV("and", src, dst, _eflags);
                break;
+       case 0x24:              /* and al imm8 */
+               dst.type = OP_REG;
+               dst.ptr = &_regs[VCPU_REGS_RAX];
+               dst.val = *(u8 *)dst.ptr;
+               dst.bytes = 1;
+               dst.orig_val = dst.val;
+               goto and;
+       case 0x25:              /* and ax imm16, or eax imm32 */
+               dst.type = OP_REG;
+               dst.bytes = op_bytes;
+               dst.ptr = &_regs[VCPU_REGS_RAX];
+               if (op_bytes == 2)
+                       dst.val = *(u16 *)dst.ptr;
+               else
+                       dst.val = *(u32 *)dst.ptr;
+               dst.orig_val = dst.val;
+               goto and;
        case 0x28 ... 0x2d:
              sub:              /* sub */
                emulate_2op_SrcV("sub", src, dst, _eflags);
@@ -892,6 +964,17 @@ done_prefixes:
                        goto cannot_emulate;
                dst.val = (s32) src.val;
                break;
+       case 0x6a: /* push imm8 */
+               src.val = 0L;
+               src.val = insn_fetch(s8, 1, _eip);
+push:
+               dst.type  = OP_MEM;
+               dst.bytes = op_bytes;
+               dst.val = src.val;
+               register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
+               dst.ptr = (void *) register_address(ctxt->ss_base,
+                                                       _regs[VCPU_REGS_RSP]);
+               break;
        case 0x80 ... 0x83:     /* Grp1 */
                switch (modrm_reg) {
                case 0:
@@ -939,18 +1022,10 @@ done_prefixes:
                dst.val = src.val;
                lock_prefix = 1;
                break;
-       case 0xa0 ... 0xa1:     /* mov */
-               dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
-               dst.val = src.val;
-               _eip += ad_bytes;       /* skip src displacement */
-               break;
-       case 0xa2 ... 0xa3:     /* mov */
-               dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
-               _eip += ad_bytes;       /* skip dst displacement */
-               break;
        case 0x88 ... 0x8b:     /* mov */
-       case 0xc6 ... 0xc7:     /* mov (sole member of Grp11) */
-               dst.val = src.val;
+               goto mov;
+       case 0x8d: /* lea r16/r32, m */
+               dst.val = modrm_val;
                break;
        case 0x8f:              /* pop (sole member of Grp1a) */
                /* 64-bit mode: POP always pops a 64-bit operand. */
@@ -958,10 +1033,19 @@ done_prefixes:
                        dst.bytes = 8;
                if ((rc = ops->read_std(register_address(ctxt->ss_base,
                                                         _regs[VCPU_REGS_RSP]),
-                                       &dst.val, dst.bytes, ctxt)) != 0)
+                                       &dst.val, dst.bytes, ctxt->vcpu)) != 0)
                        goto done;
                register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes);
                break;
+       case 0xa0 ... 0xa1:     /* mov */
+               dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+               dst.val = src.val;
+               _eip += ad_bytes;       /* skip src displacement */
+               break;
+       case 0xa2 ... 0xa3:     /* mov */
+               dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
+               _eip += ad_bytes;       /* skip dst displacement */
+               break;
        case 0xc0 ... 0xc1:
              grp2:             /* Grp2 */
                switch (modrm_reg) {
@@ -989,12 +1073,41 @@ done_prefixes:
                        break;
                }
                break;
+       case 0xc6 ... 0xc7:     /* mov (sole member of Grp11) */
+       mov:
+               dst.val = src.val;
+               break;
        case 0xd0 ... 0xd1:     /* Grp2 */
                src.val = 1;
                goto grp2;
        case 0xd2 ... 0xd3:     /* Grp2 */
                src.val = _regs[VCPU_REGS_RCX];
                goto grp2;
+       case 0xe8: /* call (near) */ {
+               long int rel;
+               switch (op_bytes) {
+               case 2:
+                       rel = insn_fetch(s16, 2, _eip);
+                       break;
+               case 4:
+                       rel = insn_fetch(s32, 4, _eip);
+                       break;
+               case 8:
+                       rel = insn_fetch(s64, 8, _eip);
+                       break;
+               default:
+                       DPRINTF("Call: Invalid op_bytes\n");
+                       goto cannot_emulate;
+               }
+               src.val = (unsigned long) _eip;
+               JMP_REL(rel);
+               goto push;
+       }
+       case 0xe9: /* jmp rel */
+       case 0xeb: /* jmp rel short */
+               JMP_REL(src.val);
+               no_wb = 1; /* Disable writeback. */
+               break;
        case 0xf6 ... 0xf7:     /* Grp3 */
                switch (modrm_reg) {
                case 0 ... 1:   /* test */
@@ -1037,13 +1150,19 @@ done_prefixes:
                case 1: /* dec */
                        emulate_1op("dec", dst, _eflags);
                        break;
+               case 4: /* jmp abs */
+                       if (b == 0xff)
+                               _eip = dst.val;
+                       else
+                               goto cannot_emulate;
+                       break;
                case 6: /* push */
                        /* 64-bit mode: PUSH always pushes a 64-bit operand. */
                        if (mode == X86EMUL_MODE_PROT64) {
                                dst.bytes = 8;
                                if ((rc = ops->read_std((unsigned long)dst.ptr,
                                                        &dst.val, 8,
-                                                       ctxt)) != 0)
+                                                       ctxt->vcpu)) != 0)
                                        goto done;
                        }
                        register_address_increment(_regs[VCPU_REGS_RSP],
@@ -1051,7 +1170,7 @@ done_prefixes:
                        if ((rc = ops->write_std(
                                     register_address(ctxt->ss_base,
                                                      _regs[VCPU_REGS_RSP]),
-                                    &dst.val, dst.bytes, ctxt)) != 0)
+                                    &dst.val, dst.bytes, ctxt->vcpu)) != 0)
                                goto done;
                        no_wb = 1;
                        break;
@@ -1086,11 +1205,11 @@ writeback:
                                rc = ops->cmpxchg_emulated((unsigned long)dst.
                                                           ptr, &dst.orig_val,
                                                           &dst.val, dst.bytes,
-                                                          ctxt);
+                                                          ctxt->vcpu);
                        else
                                rc = ops->write_emulated((unsigned long)dst.ptr,
                                                         &dst.val, dst.bytes,
-                                                        ctxt);
+                                                        ctxt->vcpu);
                        if (rc != 0)
                                goto done;
                default:
@@ -1109,6 +1228,81 @@ done:
 special_insn:
        if (twobyte)
                goto twobyte_special_insn;
+       switch(b) {
+       case 0x50 ... 0x57:  /* push reg */
+               if (op_bytes == 2)
+                       src.val = (u16) _regs[b & 0x7];
+               else
+                       src.val = (u32) _regs[b & 0x7];
+               dst.type  = OP_MEM;
+               dst.bytes = op_bytes;
+               dst.val = src.val;
+               register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
+               dst.ptr = (void *) register_address(
+                       ctxt->ss_base, _regs[VCPU_REGS_RSP]);
+               break;
+       case 0x58 ... 0x5f: /* pop reg */
+               dst.ptr = (unsigned long *)&_regs[b & 0x7];
+       pop_instruction:
+               if ((rc = ops->read_std(register_address(ctxt->ss_base,
+                       _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu))
+                       != 0)
+                       goto done;
+
+               register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
+               no_wb = 1; /* Disable writeback. */
+               break;
+       case 0x6c:              /* insb */
+       case 0x6d:              /* insw/insd */
+                if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+                               1,                                      /* in */
+                               (d & ByteOp) ? 1 : op_bytes,            /* size */
+                               rep_prefix ?
+                               address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */
+                               (_eflags & EFLG_DF),                    /* down */
+                               register_address(ctxt->es_base,
+                                                _regs[VCPU_REGS_RDI]), /* address */
+                               rep_prefix,
+                               _regs[VCPU_REGS_RDX]                    /* port */
+                               ) == 0)
+                       return -1;
+               return 0;
+       case 0x6e:              /* outsb */
+       case 0x6f:              /* outsw/outsd */
+               if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+                               0,                                      /* in */
+                               (d & ByteOp) ? 1 : op_bytes,            /* size */
+                               rep_prefix ?
+                               address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */
+                               (_eflags & EFLG_DF),                    /* down */
+                               register_address(override_base ?
+                                                *override_base : ctxt->ds_base,
+                                                _regs[VCPU_REGS_RSI]), /* address */
+                               rep_prefix,
+                               _regs[VCPU_REGS_RDX]                    /* port */
+                               ) == 0)
+                       return -1;
+               return 0;
+       case 0x70 ... 0x7f: /* jcc (short) */ {
+               int rel = insn_fetch(s8, 1, _eip);
+
+               if (test_cc(b, _eflags))
+               JMP_REL(rel);
+               break;
+       }
+       case 0x9c: /* pushf */
+               src.val =  (unsigned long) _eflags;
+               goto push;
+       case 0x9d: /* popf */
+               dst.ptr = (unsigned long *) &_eflags;
+               goto pop_instruction;
+       case 0xc3: /* ret */
+               dst.ptr = &_eip;
+               goto pop_instruction;
+       case 0xf4:              /* hlt */
+               ctxt->vcpu->halt_request = 1;
+               goto done;
+       }
        if (rep_prefix) {
                if (_regs[VCPU_REGS_RCX] == 0) {
                        ctxt->vcpu->rip = _eip;
@@ -1125,7 +1319,7 @@ special_insn:
                                                        _regs[VCPU_REGS_RDI]);
                if ((rc = ops->read_emulated(register_address(
                      override_base ? *override_base : ctxt->ds_base,
-                     _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0)
+                     _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0)
                        goto done;
                register_address_increment(_regs[VCPU_REGS_RSI],
                             (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1147,7 +1341,8 @@ special_insn:
                dst.type = OP_REG;
                dst.bytes = (d & ByteOp) ? 1 : op_bytes;
                dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
-               if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0)
+               if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes,
+                                            ctxt->vcpu)) != 0)
                        goto done;
                register_address_increment(_regs[VCPU_REGS_RSI],
                           (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1155,23 +1350,7 @@ special_insn:
        case 0xae ... 0xaf:     /* scas */
                DPRINTF("Urk! I don't handle SCAS.\n");
                goto cannot_emulate;
-       case 0xf4:              /* hlt */
-               ctxt->vcpu->halt_request = 1;
-               goto done;
-       case 0xc3: /* ret */
-               dst.ptr = &_eip;
-               goto pop_instruction;
-       case 0x58 ... 0x5f: /* pop reg */
-               dst.ptr = (unsigned long *)&_regs[b & 0x7];
 
-pop_instruction:
-               if ((rc = ops->read_std(register_address(ctxt->ss_base,
-                       _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt)) != 0)
-                       goto done;
-
-               register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
-               no_wb = 1; /* Disable writeback. */
-               break;
        }
        goto writeback;
 
@@ -1230,40 +1409,50 @@ twobyte_insn:
                break;
        case 0x40 ... 0x4f:     /* cmov */
                dst.val = dst.orig_val = src.val;
-               d &= ~Mov;      /* default to no move */
+               no_wb = 1;
                /*
                 * First, assume we're decoding an even cmov opcode
                 * (lsb == 0).
                 */
                switch ((b & 15) >> 1) {
                case 0: /* cmovo */
-                       d |= (_eflags & EFLG_OF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_OF) ? 0 : 1;
                        break;
                case 1: /* cmovb/cmovc/cmovnae */
-                       d |= (_eflags & EFLG_CF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_CF) ? 0 : 1;
                        break;
                case 2: /* cmovz/cmove */
-                       d |= (_eflags & EFLG_ZF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
                        break;
                case 3: /* cmovbe/cmovna */
-                       d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0;
+                       no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1;
                        break;
                case 4: /* cmovs */
-                       d |= (_eflags & EFLG_SF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_SF) ? 0 : 1;
                        break;
                case 5: /* cmovp/cmovpe */
-                       d |= (_eflags & EFLG_PF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_PF) ? 0 : 1;
                        break;
                case 7: /* cmovle/cmovng */
-                       d |= (_eflags & EFLG_ZF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
                        /* fall through */
                case 6: /* cmovl/cmovnge */
-                       d |= (!(_eflags & EFLG_SF) !=
-                             !(_eflags & EFLG_OF)) ? Mov : 0;
+                       no_wb &= (!(_eflags & EFLG_SF) !=
+                             !(_eflags & EFLG_OF)) ? 0 : 1;
                        break;
                }
                /* Odd cmov opcodes (lsb == 1) have inverted sense. */
-               d ^= (b & 1) ? Mov : 0;
+               no_wb ^= b & 1;
+               break;
+       case 0xa3:
+             bt:               /* bt */
+               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+               emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
+               break;
+       case 0xab:
+             bts:              /* bts */
+               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+               emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
                break;
        case 0xb0 ... 0xb1:     /* cmpxchg */
                /*
@@ -1273,8 +1462,6 @@ twobyte_insn:
                src.orig_val = src.val;
                src.val = _regs[VCPU_REGS_RAX];
                emulate_2op_SrcV("cmp", src, dst, _eflags);
-               /* Always write back. The question is: where to? */
-               d |= Mov;
                if (_eflags & EFLG_ZF) {
                        /* Success: write back to memory. */
                        dst.val = src.orig_val;
@@ -1284,30 +1471,15 @@ twobyte_insn:
                        dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
                }
                break;
-       case 0xa3:
-             bt:               /* bt */
-               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
-               emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
-               break;
        case 0xb3:
              btr:              /* btr */
                src.val &= (dst.bytes << 3) - 1; /* only subword offset */
                emulate_2op_SrcV_nobyte("btr", src, dst, _eflags);
                break;
-       case 0xab:
-             bts:              /* bts */
-               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
-               emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
-               break;
        case 0xb6 ... 0xb7:     /* movzx */
                dst.bytes = op_bytes;
                dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val;
                break;
-       case 0xbb:
-             btc:              /* btc */
-               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
-               emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
-               break;
        case 0xba:              /* Grp8 */
                switch (modrm_reg & 3) {
                case 0:
@@ -1320,6 +1492,11 @@ twobyte_insn:
                        goto btc;
                }
                break;
+       case 0xbb:
+             btc:              /* btc */
+               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+               emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
+               break;
        case 0xbe ... 0xbf:     /* movsx */
                dst.bytes = op_bytes;
                dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val;
@@ -1331,14 +1508,14 @@ twobyte_special_insn:
        /* Disable writeback. */
        no_wb = 1;
        switch (b) {
+       case 0x06:
+               emulate_clts(ctxt->vcpu);
+               break;
        case 0x09:              /* wbinvd */
                break;
        case 0x0d:              /* GrpP (prefetch) */
        case 0x18:              /* Grp16 (prefetch/nop) */
                break;
-       case 0x06:
-               emulate_clts(ctxt->vcpu);
-               break;
        case 0x20: /* mov cr, reg */
                if (modrm_mod != 3)
                        goto cannot_emulate;
@@ -1355,7 +1532,7 @@ twobyte_special_insn:
                        | ((u64)_regs[VCPU_REGS_RDX] << 32);
                rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
                if (rc) {
-                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
                        _eip = ctxt->vcpu->rip;
                }
                rc = X86EMUL_CONTINUE;
@@ -1364,7 +1541,7 @@ twobyte_special_insn:
                /* rdmsr */
                rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
                if (rc) {
-                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
                        _eip = ctxt->vcpu->rip;
                } else {
                        _regs[VCPU_REGS_RAX] = (u32)msr_data;
@@ -1372,10 +1549,32 @@ twobyte_special_insn:
                }
                rc = X86EMUL_CONTINUE;
                break;
+       case 0x80 ... 0x8f: /* jnz rel, etc*/ {
+               long int rel;
+
+               switch (op_bytes) {
+               case 2:
+                       rel = insn_fetch(s16, 2, _eip);
+                       break;
+               case 4:
+                       rel = insn_fetch(s32, 4, _eip);
+                       break;
+               case 8:
+                       rel = insn_fetch(s64, 8, _eip);
+                       break;
+               default:
+                       DPRINTF("jnz: Invalid op_bytes\n");
+                       goto cannot_emulate;
+               }
+               if (test_cc(b, _eflags))
+                       JMP_REL(rel);
+               break;
+       }
        case 0xc7:              /* Grp9 (cmpxchg8b) */
                {
                        u64 old, new;
-                       if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
+                       if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu))
+                                                                       != 0)
                                goto done;
                        if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
                            ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) {
@@ -1386,7 +1585,7 @@ twobyte_special_insn:
                                new = ((u64)_regs[VCPU_REGS_RCX] << 32)
                                        | (u32) _regs[VCPU_REGS_RBX];
                                if ((rc = ops->cmpxchg_emulated(cr2, &old,
-                                                         &new, 8, ctxt)) != 0)
+                                                         &new, 8, ctxt->vcpu)) != 0)
                                        goto done;
                                _eflags |= EFLG_ZF;
                        }
index ea3407d7feeed4083b4e3a4387b767584d9cb0b6..92c73aa7f9ac4f81ed863177e40c551385477ee4 100644 (file)
@@ -60,7 +60,7 @@ struct x86_emulate_ops {
         *  @bytes: [IN ] Number of bytes to read from memory.
         */
        int (*read_std)(unsigned long addr, void *val,
-                       unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+                       unsigned int bytes, struct kvm_vcpu *vcpu);
 
        /*
         * write_std: Write bytes of standard (non-emulated/special) memory.
@@ -71,7 +71,7 @@ struct x86_emulate_ops {
         *  @bytes: [IN ] Number of bytes to write to memory.
         */
        int (*write_std)(unsigned long addr, const void *val,
-                        unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+                        unsigned int bytes, struct kvm_vcpu *vcpu);
 
        /*
         * read_emulated: Read bytes from emulated/special memory area.
@@ -82,7 +82,7 @@ struct x86_emulate_ops {
        int (*read_emulated) (unsigned long addr,
                              void *val,
                              unsigned int bytes,
-                             struct x86_emulate_ctxt * ctxt);
+                             struct kvm_vcpu *vcpu);
 
        /*
         * write_emulated: Read bytes from emulated/special memory area.
@@ -94,7 +94,7 @@ struct x86_emulate_ops {
        int (*write_emulated) (unsigned long addr,
                               const void *val,
                               unsigned int bytes,
-                              struct x86_emulate_ctxt * ctxt);
+                              struct kvm_vcpu *vcpu);
 
        /*
         * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
@@ -108,12 +108,10 @@ struct x86_emulate_ops {
                                 const void *old,
                                 const void *new,
                                 unsigned int bytes,
-                                struct x86_emulate_ctxt * ctxt);
+                                struct kvm_vcpu *vcpu);
 
 };
 
-struct cpu_user_regs;
-
 struct x86_emulate_ctxt {
        /* Register state before/after emulation. */
        struct kvm_vcpu *vcpu;
@@ -154,12 +152,4 @@ struct x86_emulate_ctxt {
 int x86_emulate_memop(struct x86_emulate_ctxt *ctxt,
                      struct x86_emulate_ops *ops);
 
-/*
- * Given the 'reg' portion of a ModRM byte, and a register block, return a
- * pointer into the block that addresses the relevant register.
- * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
- */
-void *decode_register(u8 modrm_reg, unsigned long *regs,
-                     int highbyte_regs);
-
 #endif                         /* __X86_EMULATE_H__ */
index a2191a4fcf77120d6d9033b0cedb58ab3adc1c3a..342517261ece129dd115f34897b1ff762a1fd78b 100644 (file)
@@ -54,8 +54,6 @@ static void emc_endio(struct bio *bio, int error)
 
        /* request is freed in block layer */
        free_bio(bio);
-
-       return 0;
 }
 
 static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size)
index 844f1762c45ab516cc99dbaf7383a2a53d2382c5..4d5b8035e46634d31ade156cbee392130299be09 100644 (file)
@@ -124,12 +124,6 @@ static struct i2c_adapter bttv_i2c_adap_sw_template = {
 /* ----------------------------------------------------------------------- */
 /* I2C functions - hardware i2c                                            */
 
-static int algo_control(struct i2c_adapter *adapter,
-                       unsigned int cmd, unsigned long arg)
-{
-       return 0;
-}
-
 static u32 functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_SMBUS_EMUL;
@@ -278,7 +272,6 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
 
 static struct i2c_algorithm bttv_algo = {
        .master_xfer   = bttv_i2c_xfer,
-       .algo_control  = algo_control,
        .functionality = functionality,
 };
 
index b517c8b5a5668cba8970dbcb62a40627d0f2818b..71da528932df99fd6196bef22af67f147ec71785 100644 (file)
@@ -272,12 +272,6 @@ void cx23885_call_i2c_clients(struct cx23885_i2c *bus,
        i2c_clients_command(&bus->i2c_adap, cmd, arg);
 }
 
-static int cx23885_algo_control(struct i2c_adapter *adap,
-                               unsigned int cmd, unsigned long arg)
-{
-       return 0;
-}
-
 static u32 cx23885_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
@@ -285,7 +279,6 @@ static u32 cx23885_functionality(struct i2c_adapter *adap)
 
 static struct i2c_algorithm cx23885_i2c_algo_template = {
        .master_xfer    = i2c_xfer,
-       .algo_control   = cx23885_algo_control,
        .functionality  = cx23885_functionality,
 };
 
index 54ccc6e1f92e05e00beb9327285ba1d2b4c3cd24..997d067e32e07e839eaa548a112639c99cd4d73a 100644 (file)
@@ -382,15 +382,6 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
 
 /* ----------------------------------------------------------- */
 
-/*
- * algo_control()
- */
-static int algo_control(struct i2c_adapter *adapter,
-                       unsigned int cmd, unsigned long arg)
-{
-       return 0;
-}
-
 /*
  * functionality()
  */
@@ -475,7 +466,6 @@ static int attach_inform(struct i2c_client *client)
 
 static struct i2c_algorithm em28xx_algo = {
        .master_xfer   = em28xx_i2c_xfer,
-       .algo_control  = algo_control,
        .functionality = functionality,
 };
 
index 511a66252413842527b288a0fc229164601fe5bf..fd7a932e1d3384653c2e9e2363c411d3aee0d943 100644 (file)
@@ -98,9 +98,9 @@ static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1 };
 
-static int cardtype_c = 1;
-static int tuner_c = 1;
-static int radio_c = 1;
+static unsigned int cardtype_c = 1;
+static unsigned int tuner_c = 1;
+static unsigned int radio_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
index 9eb2562347a8dd19622ae94b53ef43c1255ff41e..b8d4ac0d938e472a9118c7b1ceec7a5f1b9ada34 100644 (file)
@@ -181,7 +181,7 @@ module_param(force_palette, int, 0);
 MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
 module_param(backlight, int, 0);
 MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static int num_uv;
+static unsigned int num_uv;
 module_param_array(unit_video, int, &num_uv, 0);
 MODULE_PARM_DESC(unit_video,
   "Force use of specific minor number(s). 0 is not allowed.");
index 898c9d2e4cdfb6f25420c404cd8937cc2b0030b0..c817c864e6a020b94ee5039744190fe4193c2642 100644 (file)
@@ -520,12 +520,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
        return ret;
 }
 
-static int pvr2_i2c_control(struct i2c_adapter *adapter,
-                           unsigned int cmd, unsigned long arg)
-{
-       return 0;
-}
-
 static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
@@ -942,7 +936,6 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client)
 
 static struct i2c_algorithm pvr2_i2c_algo_template = {
        .master_xfer   = pvr2_i2c_xfer,
-       .algo_control  = pvr2_i2c_control,
        .functionality = pvr2_i2c_functionality,
 };
 
index 0b67d4ec0318f7ab9ef675940cb45057aad12524..950da254214870a366a39dc26843b66cb90f962e 100644 (file)
@@ -1903,9 +1903,9 @@ static int fbufs;
 static int mbufs;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
-static int leds_nargs;
+static unsigned int leds_nargs;
 static char *dev_hint[MAX_DEV_HINTS];
-static int dev_hint_nargs;
+static unsigned int dev_hint_nargs;
 
 module_param(size, charp, 0444);
 module_param(fps, int, 0444);
index cc87f5855a211101188a89377f06902d481d28b9..6deaad1a5480c34471c0b4a728719c3e4d452d0e 100644 (file)
@@ -314,12 +314,6 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
 
 /* ----------------------------------------------------------- */
 
-static int algo_control(struct i2c_adapter *adapter,
-                       unsigned int cmd, unsigned long arg)
-{
-       return 0;
-}
-
 static u32 functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_SMBUS_EMUL;
@@ -387,7 +381,6 @@ static int attach_inform(struct i2c_client *client)
 
 static struct i2c_algorithm saa7134_algo = {
        .master_xfer   = saa7134_i2c_xfer,
-       .algo_control  = algo_control,
        .functionality = functionality,
 };
 
index c66aef63916f5b246a1948642966f12f21b00465..aabc42cae9c7be63b38b6fa3bc9f26b6f12570ba 100644 (file)
@@ -183,11 +183,6 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
        return num;
 }
 
-static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg)
-{
-       return 0;
-}
-
 static u32 functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
@@ -199,7 +194,6 @@ static u32 functionality(struct i2c_adapter *adap)
 static struct i2c_algorithm usbvision_algo = {
        .master_xfer   = usbvision_i2c_xfer,
        .smbus_xfer    = NULL,
-       .algo_control  = algo_control,
        .functionality = functionality,
 };
 
index c606332512b60e9edf01382591da8206eb64497e..5599a36490fc964239dd01f4473c7f523b60105f 100644 (file)
@@ -674,7 +674,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* Copy to userspace */
-       retval=CALL(q,copy_to_user,q,data,count,nonblocking);
+       retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
        if (retval<0)
                goto done;
 
index 8bb7fdd306d63d7c793066079a9e1ad1db9c570e..3eb6123227b2277225dabb51bbe62c9963ad26a6 100644 (file)
@@ -670,7 +670,7 @@ static struct videobuf_qtype_ops pci_ops = {
        .sync         = __videobuf_sync,
        .mmap_free    = __videobuf_mmap_free,
        .mmap_mapper  = __videobuf_mmap_mapper,
-       .copy_to_user = __videobuf_copy_to_user,
+       .video_copy_to_user = __videobuf_copy_to_user,
        .copy_stream  = __videobuf_copy_stream,
 };
 
index 2e3689a12a28b4a150b58bedd70d346c4582e9bb..cd74341c984fd0cd37678c955e5689b2b55697ea 100644 (file)
@@ -320,7 +320,7 @@ static struct videobuf_qtype_ops qops = {
        .sync         = __videobuf_sync,
        .mmap_free    = __videobuf_mmap_free,
        .mmap_mapper  = __videobuf_mmap_mapper,
-       .copy_to_user = __videobuf_copy_to_user,
+       .video_copy_to_user = __videobuf_copy_to_user,
        .copy_stream  = __videobuf_copy_stream,
 };
 
index 5a1b5f5a7d463e11cab98c6197b38646e18101f7..9e7f3e685d73a1c6bae57fee2cbf593f577a7b0f 100644 (file)
@@ -444,8 +444,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
 static u32 w9968cf_i2c_func(struct i2c_adapter*);
 static int w9968cf_i2c_attach_inform(struct i2c_client*);
 static int w9968cf_i2c_detach_inform(struct i2c_client*);
-static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
-                              unsigned long arg);
 
 /* Memory management */
 static void* rvmalloc(unsigned long size);
@@ -1543,21 +1541,12 @@ static int w9968cf_i2c_detach_inform(struct i2c_client* client)
 }
 
 
-static int
-w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
-                   unsigned long arg)
-{
-       return 0;
-}
-
-
 static int w9968cf_i2c_init(struct w9968cf_device* cam)
 {
        int err = 0;
 
        static struct i2c_algorithm algo = {
                .smbus_xfer =    w9968cf_i2c_smbus_xfer,
-               .algo_control =  w9968cf_i2c_control,
                .functionality = w9968cf_i2c_func,
        };
 
index f55cc03a75c9a8a5135a670ad3ad7f320b9b7a1f..a34a11d2fef2dff5d8b76d062ae1d3d401d29053 100644 (file)
@@ -1,15 +1,19 @@
 
-menu "Fusion MPT device support"
+menuconfig FUSION
+       bool "Fusion MPT device support"
        depends on PCI
+       ---help---
+       Say Y here to get to see options for Fusion Message
+       Passing Technology (MPT) drivers.
+       This option alone does not add any kernel code.
+
+       If you say N, all options in this submenu will be skipped and disabled.
 
-config FUSION
-       bool
-       default n
+if FUSION
 
 config FUSION_SPI
        tristate "Fusion MPT ScsiHost drivers for SPI"
        depends on PCI && SCSI
-       select FUSION
        select SCSI_SPI_ATTRS
        ---help---
          SCSI HOST support for a parallel SCSI host adapters.
@@ -20,11 +24,11 @@ config FUSION_SPI
          LSI53C1020A
          LSI53C1030
          LSI53C1035
+         ATTO UL4D
 
 config FUSION_FC
        tristate "Fusion MPT ScsiHost drivers for FC"
        depends on PCI && SCSI
-       select FUSION
        select SCSI_FC_ATTRS
        ---help---
          SCSI HOST support for a Fiber Channel host adapters.
@@ -37,12 +41,13 @@ config FUSION_FC
          LSIFC929
          LSIFC929X
          LSIFC929XL
+         LSIFC949X
+         LSIFC949E
          Brocade FC 410/420
 
 config FUSION_SAS
        tristate "Fusion MPT ScsiHost drivers for SAS"
        depends on PCI && SCSI
-       select FUSION
        select SCSI_SAS_ATTRS
        ---help---
          SCSI HOST support for a SAS host adapters.
@@ -53,10 +58,10 @@ config FUSION_SAS
          LSISAS1068
          LSISAS1064E
          LSISAS1068E
+         LSISAS1078
 
 config FUSION_MAX_SGE
        int "Maximum number of scatter gather entries (16 - 128)"
-       depends on FUSION
        default "128"
        range 16 128
        help
@@ -104,7 +109,6 @@ config FUSION_LAN
 
 config FUSION_LOGGING
        bool "Fusion MPT logging facility"
-       depends on FUSION
        ---help---
          This turns on a logging facility that can be used to debug a number
          of Fusion MPT related problems.
@@ -113,7 +117,7 @@ config FUSION_LOGGING
 
          echo [level] > /sys/class/scsi_host/host#/debug_level
 
-         There are various debug levels that an be found in the source:
+         There are various debug levels that can be found in the source:
          file:drivers/message/fusion/mptdebug.h
 
-endmenu
+endif # FUSION
index 6a92e3d118fed008fd6c93bcb37794b97d25cc21..1acbdd61b670e421c7f410e44c56c16821589362 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2007 LSI Logic Corporation.
+ *  Copyright (c) 2000-2007 LSI Corporation.
  *
  *
  *           Name:  mpi.h
index eda769730e39d3e6f789906f4ce27d95d6648e56..2bd8adae0f002f0a01f3b052be8da4898bff2ac2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2007 LSI Logic Corporation.
+ *  Copyright (c) 2000-2007 LSI Corporation.
  *
  *
  *           Name:  mpi_cnfg.h
index 51a6aeb990ba0bc5c8580b38dad8b72d4ab4bb0f..627acfbb86231fc7ea07fb6b95d2b5e83629382f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2004 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Corporation.
  *
  *
  *           Name:  mpi_fc.h
index a1f479057ea3ad1c3d0eabcc4ab907dae391518b..241592ab13adb6bc8ceddb9e3c9beec78c6c6f18 100644 (file)
@@ -3,7 +3,7 @@
  MPI Header File Change History
  ==============================
 
- Copyright (c) 2000-2007 LSI Logic Corporation.
+ Copyright (c) 2000-2007 LSI Corporation.
 
  ---------------------------------------
  Header Set Release Version:    01.05.16
index 3a02615f12d6f501eeead8a30e12efc0fe18c473..a9e3693601a7e57daeea38128256020328490b27 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2007 LSI Logic Corporation.
+ *  Copyright (c) 2000-2007 LSI Corporation.
  *
  *
  *           Name:  mpi_init.h
index b1893d185bc43d9d15916c335e41e5cd8cbfa135..5cbb6bd048e146ae2e508661edfe9272b82ae31c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2007 LSI Logic Corporation.
+ *  Copyright (c) 2000-2007 LSI Corporation.
  *
  *
  *           Name:  mpi_ioc.h
index dc0b52ae83ddae767d8920adc839fcb72b415a28..03253b53b7855d8b7a7d279bf677653ab5d3ab16 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2004 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Corporation.
  *
  *
  *           Name:  mpi_lan.h
index dc98d46f9071159d0af811f20c05a7127a857fb6..e4dafcefeecde600d951ea8e95445e875f489352 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ *  Copyright (c) 2000-2001 LSI Corporation. All rights reserved.
  *
  *  NAME:           fc_log.h
  *  SUMMARY:        MPI IocLogInfo definitions for the SYMFC9xx chips
index 635bbe04513e44ac04893c5b0a3609fdd63d3e9c..6be1f6b65777a07208da7ad26eb084c7c8308b7e 100644 (file)
@@ -1,6 +1,6 @@
 /***************************************************************************
  *                                                                         *
- *  Copyright 2003 LSI Logic Corporation.  All rights reserved.            *
+ *  Copyright 2003 LSI Corporation.  All rights reserved.            *
  *                                                                         *
  * Description                                                             *
  * ------------                                                            *
index 32819b1ec8ec5f7f40c36c15c9010282bc5ea2cd..2856108421d71fa1b88d73a45e7f38765cf012d8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2001-2007 LSI Logic Corporation.
+ *  Copyright (c) 2001-2007 LSI Corporation.
  *
  *
  *           Name:  mpi_raid.h
index 8e990a0fa7a214287e17eef7ad60adc79739cadd..33fca83cefc24f86286712979c4102d4ea71a3cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2004-2006 LSI Logic Corporation.
+ *  Copyright (c) 2004-2006 LSI Corporation.
  *
  *
  *           Name:  mpi_sas.h
index 20b66731577334746b83a1ee643346850d955ab3..ff8c37d3fdcb8e6a4fd660dddcaa70942cbb5186 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2004 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Corporation.
  *
  *
  *           Name:  mpi_targ.h
index aa9053da1f58c580b767410b508db6a41a7dd679..8834ae6ce0f2b7cd66691729032829c5147f0f8d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2001-2005 LSI Logic Corporation.
+ *  Copyright (c) 2001-2005 LSI Corporation.
  *
  *
  *           Name:  mpi_tool.h
index 32cc9b1151b8b2bdfdb5294463c8388e95322db0..08dad9c1e4465e9bd3db4c03fe4c16bfeb0df621 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2004 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Corporation.
  *
  *
  *           Name:  mpi_type.h
index 414c109f4cf5f8ef92ac17cd56790574d760cf3d..52fb216dfe7448ee0c5dbdfdac3db24c4787db2f 100644 (file)
@@ -2,10 +2,10 @@
  *  linux/drivers/message/fusion/mptbase.c
  *      This is the Fusion MPT base driver which supports multiple
  *      (SCSI + LAN) specialized protocol drivers.
- *      For use with LSI Logic PCI chip/adapter(s)
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI PCI chip/adapter(s)
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -102,8 +102,6 @@ static int mfcounter = 0;
 /*
  *  Public data...
  */
-int mpt_lan_index = -1;
-int mpt_stm_index = -1;
 
 struct proc_dir_entry *mpt_proc_root_dir;
 
@@ -125,11 +123,14 @@ static MPT_EVHANDLER               MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 static MPT_RESETHANDLER                 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 static struct mpt_pci_driver   *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 
-static int     mpt_base_index = -1;
-static int     last_drv_idx = -1;
-
 static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
 
+/*
+ *  Driver Callback Index's
+ */
+static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 last_drv_idx;
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Forward protos...
@@ -235,6 +236,23 @@ static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
        return 0;
 }
 
+/**
+ *     mpt_get_cb_idx - obtain cb_idx for registered driver
+ *     @dclass: class driver enum
+ *
+ *     Returns cb_idx, or zero means it wasn't found
+ **/
+static u8
+mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
+{
+       u8 cb_idx;
+
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
+               if (MptDriverClass[cb_idx] == dclass)
+                       return cb_idx;
+       return 0;
+}
+
 /*
  *  Process turbo (context) reply...
  */
@@ -243,8 +261,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
 {
        MPT_FRAME_HDR *mf = NULL;
        MPT_FRAME_HDR *mr = NULL;
-       int req_idx = 0;
-       int cb_idx;
+       u16 req_idx = 0;
+       u8 cb_idx;
 
        dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
                                ioc->name, pa));
@@ -256,7 +274,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
                mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
                break;
        case MPI_CONTEXT_REPLY_TYPE_LAN:
-               cb_idx = mpt_lan_index;
+               cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
                /*
                 *  Blind set of mf to NULL here was fatal
                 *  after lan_reply says "freeme"
@@ -277,7 +295,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
                mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
                break;
        case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
-               cb_idx = mpt_stm_index;
+               cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
                mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
                break;
        default:
@@ -286,8 +304,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
        }
 
        /*  Check for (valid) IO callback!  */
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
-                       MptCallbacks[cb_idx] == NULL) {
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+               MptCallbacks[cb_idx] == NULL) {
                printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
                                __FUNCTION__, ioc->name, cb_idx);
                goto out;
@@ -304,8 +322,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
 {
        MPT_FRAME_HDR   *mf;
        MPT_FRAME_HDR   *mr;
-       int              req_idx;
-       int              cb_idx;
+       u16              req_idx;
+       u8               cb_idx;
        int              freeme;
 
        u32 reply_dma_low;
@@ -331,7 +349,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
 
        dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
                        ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
-       DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr)
+       DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
 
         /*  Check/log IOC log info
         */
@@ -350,8 +368,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
                mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
 
        /*  Check for (valid) IO callback!  */
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
-                       MptCallbacks[cb_idx] == NULL) {
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+               MptCallbacks[cb_idx] == NULL) {
                printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
                                __FUNCTION__, ioc->name, cb_idx);
                freeme = 0;
@@ -433,8 +451,9 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
 #ifdef CONFIG_FUSION_LOGGING
        if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
                        !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
-               dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
-               DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf)
+               dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
+                   ioc->name, mf));
+               DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
        }
 #endif
 
@@ -499,8 +518,8 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                                u16              status;
 
                                status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-                               dcprintk(ioc, printk(KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
-                                    status, le32_to_cpu(pReply->IOCLogInfo)));
+                               dcprintk(ioc, printk(MYIOC_s_NOTE_FMT "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+                                    ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
 
                                pCfg->status = status;
                                if (status == MPI_IOCSTATUS_SUCCESS) {
@@ -563,28 +582,27 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
  *     in order to register separate callbacks; one for "normal" SCSI IO;
  *     one for MptScsiTaskMgmt requests; one for Scan/DV requests.
  *
- *     Returns a positive integer valued "handle" in the
- *     range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
- *     Any non-positive return value (including zero!) should be considered
- *     an error by the caller.
+ *     Returns u8 valued "handle" in the range (and S.O.D. order)
+ *     {N,...,7,6,5,...,1} if successful.
+ *     A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
+ *     considered an error by the caller.
  */
-int
+u8
 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
 {
-       int i;
-
-       last_drv_idx = -1;
+       u8 cb_idx;
+       last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
 
        /*
         *  Search for empty callback slot in this order: {N,...,7,6,5,...,1}
         *  (slot/handle 0 is reserved!)
         */
-       for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
-               if (MptCallbacks[i] == NULL) {
-                       MptCallbacks[i] = cbfunc;
-                       MptDriverClass[i] = dclass;
-                       MptEvHandlers[i] = NULL;
-                       last_drv_idx = i;
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptCallbacks[cb_idx] == NULL) {
+                       MptCallbacks[cb_idx] = cbfunc;
+                       MptDriverClass[cb_idx] = dclass;
+                       MptEvHandlers[cb_idx] = NULL;
+                       last_drv_idx = cb_idx;
                        break;
                }
        }
@@ -601,9 +619,9 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
  *     module is unloaded.
  */
 void
-mpt_deregister(int cb_idx)
+mpt_deregister(u8 cb_idx)
 {
-       if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+       if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
                MptCallbacks[cb_idx] = NULL;
                MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
                MptEvHandlers[cb_idx] = NULL;
@@ -625,9 +643,9 @@ mpt_deregister(int cb_idx)
  *     Returns 0 for success.
  */
 int
-mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
+mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
 {
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
                return -1;
 
        MptEvHandlers[cb_idx] = ev_cbfunc;
@@ -645,9 +663,9 @@ mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
  *     or when its module is unloaded.
  */
 void
-mpt_event_deregister(int cb_idx)
+mpt_event_deregister(u8 cb_idx)
 {
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
                return;
 
        MptEvHandlers[cb_idx] = NULL;
@@ -665,9 +683,9 @@ mpt_event_deregister(int cb_idx)
  *     Returns 0 for success.
  */
 int
-mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
+mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
 {
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
                return -1;
 
        MptResetHandlers[cb_idx] = reset_func;
@@ -684,9 +702,9 @@ mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
  *     or when its module is unloaded.
  */
 void
-mpt_reset_deregister(int cb_idx)
+mpt_reset_deregister(u8 cb_idx)
 {
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
                return;
 
        MptResetHandlers[cb_idx] = NULL;
@@ -699,12 +717,12 @@ mpt_reset_deregister(int cb_idx)
  *     @cb_idx: MPT protocol driver index
  */
 int
-mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
+mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
 {
        MPT_ADAPTER     *ioc;
        const struct pci_device_id *id;
 
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
                return -EINVAL;
 
        MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
@@ -726,12 +744,12 @@ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
  *     @cb_idx: MPT protocol driver index
  */
 void
-mpt_device_driver_deregister(int cb_idx)
+mpt_device_driver_deregister(u8 cb_idx)
 {
        struct mpt_pci_driver *dd_cbfunc;
        MPT_ADAPTER     *ioc;
 
-       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+       if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
                return;
 
        dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
@@ -749,14 +767,14 @@ mpt_device_driver_deregister(int cb_idx)
 /**
  *     mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
  *     allocated per MPT adapter.
- *     @handle: Handle of registered MPT protocol driver
+ *     @cb_idx: Handle of registered MPT protocol driver
  *     @ioc: Pointer to MPT adapter structure
  *
  *     Returns pointer to a MPT request frame or %NULL if none are available
  *     or IOC is not active.
  */
 MPT_FRAME_HDR*
-mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
+mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
 {
        MPT_FRAME_HDR *mf;
        unsigned long flags;
@@ -766,7 +784,8 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
 
 #ifdef MFCNT
        if (!ioc->active)
-               printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
+               printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
+                   "returning NULL!\n", ioc->name);
 #endif
 
        /* If interrupts are not attached, do not return a request frame */
@@ -781,13 +800,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
                                u.frame.linkage.list);
                list_del(&mf->u.frame.linkage.list);
                mf->u.frame.linkage.arg1 = 0;
-               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;  /* byte */
+               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;  /* byte */
                req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
                                                                /* u16! */
                req_idx = req_offset / ioc->req_sz;
                mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
                mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
-               ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
+               /* Default, will be changed if necessary in SG generation */
+               ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
 #ifdef MFCNT
                ioc->mfcnt++;
 #endif
@@ -798,14 +818,17 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
 
 #ifdef MFCNT
        if (mf == NULL)
-               printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
+               printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
+                   "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
+                   ioc->req_depth);
        mfcounter++;
        if (mfcounter == PRINT_MF_COUNT)
-               printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
+               printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
+                   ioc->mfcnt, ioc->req_depth);
 #endif
 
-       dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
-                       ioc->name, handle, ioc->id, mf));
+       dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
+           ioc->name, cb_idx, ioc->id, mf));
        return mf;
 }
 
@@ -813,7 +836,7 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
 /**
  *     mpt_put_msg_frame - Send a protocol specific MPT request frame
  *     to a IOC.
- *     @handle: Handle of registered MPT protocol driver
+ *     @cb_idx: Handle of registered MPT protocol driver
  *     @ioc: Pointer to MPT adapter structure
  *     @mf: Pointer to MPT request frame
  *
@@ -821,14 +844,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
  *     specific MPT adapter.
  */
 void
-mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 {
        u32 mf_dma_addr;
        int req_offset;
        u16      req_idx;       /* Request index */
 
        /* ensure values are reset properly! */
-       mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;          /* byte */
+       mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;          /* byte */
        req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
                                                                /* u16! */
        req_idx = req_offset / ioc->req_sz;
@@ -838,10 +861,44 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
        DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
 
        mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
-       dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
+       dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
+           "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
+           ioc->RequestNB[req_idx]));
        CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
 }
 
+/**
+ *     mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
+ *     to a IOC using hi priority request queue.
+ *     @cb_idx: Handle of registered MPT protocol driver
+ *     @ioc: Pointer to MPT adapter structure
+ *     @mf: Pointer to MPT request frame
+ *
+ *     This routine posts a MPT request frame to the request post FIFO of a
+ *     specific MPT adapter.
+ **/
+void
+mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+{
+       u32 mf_dma_addr;
+       int req_offset;
+       u16      req_idx;       /* Request index */
+
+       /* ensure values are reset properly! */
+       mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
+       req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
+       req_idx = req_offset / ioc->req_sz;
+       mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
+       mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+       DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
+
+       mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
+       dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
+               ioc->name, mf_dma_addr, req_idx));
+       CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_free_msg_frame - Place MPT request frame back on FreeQ.
@@ -899,7 +956,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_send_handshake_request - Send MPT request via doorbell handshake method.
- *     @handle: Handle of registered MPT protocol driver
+ *     @cb_idx: Handle of registered MPT protocol driver
  *     @ioc: Pointer to MPT adapter structure
  *     @reqBytes: Size of the request in bytes
  *     @req: Pointer to MPT request frame
@@ -914,7 +971,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
  *     Returns 0 for success, non-zero for failure.
  */
 int
-mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
+mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
 {
        int     r = 0;
        u8      *req_as_bytes;
@@ -934,7 +991,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
        if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
                MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
                mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
-               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
+               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
        }
 
        /* Make sure there are no doorbells */
@@ -953,7 +1010,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
        if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
                return -5;
 
-       dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+       dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
                ioc->name, ii));
 
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -1395,11 +1452,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        MPT_ADAPTER     *ioc;
        u8              __iomem *mem;
+       u8              __iomem *pmem;
        unsigned long    mem_phys;
        unsigned long    port;
        u32              msize;
        u32              psize;
        int              ii;
+       u8               cb_idx;
        int              r = -ENODEV;
        u8               revision;
        u8               pcixcmd;
@@ -1408,35 +1467,39 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        struct proc_dir_entry *dent, *ent;
 #endif
 
+       if (mpt_debug_level)
+               printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
+
+       if (pci_enable_device(pdev))
+               return r;
+
        ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
        if (ioc == NULL) {
                printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
                return -ENOMEM;
        }
-
        ioc->debug_level = mpt_debug_level;
-       if (mpt_debug_level)
-               printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
-
-       if (pci_enable_device(pdev))
-               return r;
+       ioc->id = mpt_ids++;
+       sprintf(ioc->name, "ioc%d", ioc->id);
 
-       dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
 
        if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
-               dprintk(ioc, printk(KERN_INFO MYNAM
-                       ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
+               dprintk(ioc, printk(MYIOC_s_INFO_FMT
+                       ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
        } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
-               printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+               printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
+                   ioc->name);
+               kfree(ioc);
                return r;
        }
 
        if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
-               dprintk(ioc, printk(KERN_INFO MYNAM
-                       ": Using 64 bit consistent mask\n"));
+               dprintk(ioc, printk(MYIOC_s_INFO_FMT
+                       ": Using 64 bit consistent mask\n", ioc->name));
        } else {
-               dprintk(ioc, printk(KERN_INFO MYNAM
-                       ": Not using 64 bit consistent mask\n"));
+               dprintk(ioc, printk(MYIOC_s_INFO_FMT
+                       ": Not using 64 bit consistent mask\n", ioc->name));
        }
 
        ioc->alloc_total = sizeof(MPT_ADAPTER);
@@ -1475,7 +1538,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Find lookup slot. */
        INIT_LIST_HEAD(&ioc->list);
-       ioc->id = mpt_ids++;
 
        mem_phys = msize = 0;
        port = psize = 0;
@@ -1501,25 +1563,23 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        /*mem = ioremap(mem_phys, msize);*/
        mem = ioremap(mem_phys, msize);
        if (mem == NULL) {
-               printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
+               printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
                kfree(ioc);
                return -EINVAL;
        }
        ioc->memmap = mem;
-       dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
 
-       dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
-                       &ioc->facts, &ioc->pfacts[0]));
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
+           ioc->name, &ioc->facts, &ioc->pfacts[0]));
 
        ioc->mem_phys = mem_phys;
        ioc->chip = (SYSIF_REGS __iomem *)mem;
 
        /* Save Port IO values in case we need to do downloadboot */
-       {
-               u8 *pmem = (u8*)port;
-               ioc->pio_mem_phys = port;
-               ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
-       }
+       ioc->pio_mem_phys = port;
+       pmem = (u8 __iomem *)port;
+       ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
 
        pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
        mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
@@ -1591,8 +1651,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ioc->errata_flag_1064)
                pci_disable_io_access(pdev);
 
-       sprintf(ioc->name, "ioc%d", ioc->id);
-
        spin_lock_init(&ioc->FreeQlock);
 
        /* Disable all! */
@@ -1609,9 +1667,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
            CAN_SLEEP)) != 0){
-               printk(KERN_WARNING MYNAM
-                 ": WARNING - %s did not initialize properly! (%d)\n",
-                 ioc->name, r);
+               printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
+                   ioc->name, r);
 
                list_del(&ioc->list);
                if (ioc->alt_ioc)
@@ -1623,10 +1680,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* call per device driver probe entry point */
-       for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
-               if(MptDeviceDriverHandlers[ii] &&
-                 MptDeviceDriverHandlers[ii]->probe) {
-                       MptDeviceDriverHandlers[ii]->probe(pdev,id);
+       for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+               if(MptDeviceDriverHandlers[cb_idx] &&
+                 MptDeviceDriverHandlers[cb_idx]->probe) {
+                       MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
                }
        }
 
@@ -1663,7 +1720,7 @@ mpt_detach(struct pci_dev *pdev)
 {
        MPT_ADAPTER     *ioc = pci_get_drvdata(pdev);
        char pname[32];
-       int ii;
+       u8 cb_idx;
 
        sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
        remove_proc_entry(pname, NULL);
@@ -1673,10 +1730,10 @@ mpt_detach(struct pci_dev *pdev)
        remove_proc_entry(pname, NULL);
 
        /* call per device driver remove entry point */
-       for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
-               if(MptDeviceDriverHandlers[ii] &&
-                 MptDeviceDriverHandlers[ii]->remove) {
-                       MptDeviceDriverHandlers[ii]->remove(pdev);
+       for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+               if(MptDeviceDriverHandlers[cb_idx] &&
+                 MptDeviceDriverHandlers[cb_idx]->remove) {
+                       MptDeviceDriverHandlers[cb_idx]->remove(pdev);
                }
        }
 
@@ -1788,7 +1845,7 @@ mpt_resume(struct pci_dev *pdev)
 #endif
 
 static int
-mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
+mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
 {
        if ((MptDriverClass[index] == MPTSPI_DRIVER &&
             ioc->bus_type != SPI) ||
@@ -1830,14 +1887,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        int      hard;
        int      rc=0;
        int      ii;
+       u8       cb_idx;
        int      handlers;
        int      ret = 0;
        int      reset_alt_ioc_active = 0;
        int      irq_allocated = 0;
        u8      *a;
 
-       printk(KERN_INFO MYNAM ": Initiating %s %s\n",
-                       ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
+       printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
+           reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
 
        /* Disable reply interrupts (also blocks FreeQ) */
        CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
@@ -1858,21 +1916,19 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 
        if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
                if (hard_reset_done == -4) {
-                       printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
-                                       ioc->name);
+                       printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
+                           ioc->name);
 
                        if (reset_alt_ioc_active && ioc->alt_ioc) {
                                /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
-                               dprintk(ioc, printk(KERN_INFO MYNAM
-                                       ": alt-%s reply irq re-enabled\n",
-                                               ioc->alt_ioc->name));
+                               dprintk(ioc, printk(MYIOC_s_INFO_FMT
+                                   "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
                                CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
                                ioc->alt_ioc->active = 1;
                        }
 
                } else {
-                       printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
-                                       ioc->name);
+                       printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
                }
                return -1;
        }
@@ -1884,9 +1940,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
                        alt_ioc_ready = 1;
                else
-                       printk(KERN_WARNING MYNAM
-                                       ": alt-%s: Not ready WARNING!\n",
-                                       ioc->alt_ioc->name);
+                       printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
        }
 
        for (ii=0; ii<5; ii++) {
@@ -1897,7 +1951,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 
 
        if (ii == 5) {
-               dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
+               dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "Retry IocFacts failed rc=%x\n", ioc->name, rc));
                ret = -2;
        } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
                MptDisplayIocCapabilities(ioc);
@@ -1906,14 +1961,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        if (alt_ioc_ready) {
                if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
                        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                               "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
+                           "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
                        /* Retry - alt IOC was initialized once
                         */
                        rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
                }
                if (rc) {
                        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                               "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
+                           "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
                        alt_ioc_ready = 0;
                        reset_alt_ioc_active = 0;
                } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
@@ -1931,13 +1986,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                if (ioc->pcidev->irq) {
                        if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
                                printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
-                                       ioc->name);
+                                   ioc->name);
                        rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
-                                       IRQF_SHARED, ioc->name, ioc);
+                           IRQF_SHARED, ioc->name, ioc);
                        if (rc < 0) {
                                printk(MYIOC_s_ERR_FMT "Unable to allocate "
-                                       "interrupt %d!\n", ioc->name,
-                                       ioc->pcidev->irq);
+                                   "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
                                if (mpt_msi_enable)
                                        pci_disable_msi(ioc->pcidev);
                                return -EBUSY;
@@ -1946,8 +2000,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                        ioc->pci_irq = ioc->pcidev->irq;
                        pci_set_master(ioc->pcidev);            /* ?? */
                        pci_set_drvdata(ioc->pcidev, ioc);
-                       dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
-                               "%d\n", ioc->name, ioc->pcidev->irq));
+                       dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
+                           "%d\n", ioc->name, ioc->pcidev->irq));
                }
        }
 
@@ -1966,8 +2020,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                ret = -4;
 // NEW!
        if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
-               printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
-                               ioc->alt_ioc->name, rc);
+               printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
+                   ioc->alt_ioc->name, rc);
                alt_ioc_ready = 0;
                reset_alt_ioc_active = 0;
        }
@@ -1976,16 +2030,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
                        alt_ioc_ready = 0;
                        reset_alt_ioc_active = 0;
-                       printk(KERN_WARNING MYNAM
-                               ": alt-%s: (%d) init failure WARNING!\n",
-                                       ioc->alt_ioc->name, rc);
+                       printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
+                           ioc->alt_ioc->name, rc);
                }
        }
 
        if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
                if (ioc->upload_fw) {
                        ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                               "firmware upload required!\n", ioc->name));
+                           "firmware upload required!\n", ioc->name));
 
                        /* Controller is not operational, cannot do upload
                         */
@@ -2001,12 +2054,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                                 * mpt_diag_reset)
                                                 */
                                                ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                                       ": mpt_upload:  alt_%s has cached_fw=%p \n",
-                                                       ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
+                                                   "mpt_upload:  alt_%s has cached_fw=%p \n",
+                                                   ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
                                                ioc->alt_ioc->cached_fw = NULL;
                                        }
                                } else {
-                                       printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+                                       printk(MYIOC_s_WARN_FMT
+                                           "firmware upload failure!\n", ioc->name);
                                        ret = -5;
                                }
                        }
@@ -2021,8 +2075,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 
        if (reset_alt_ioc_active && ioc->alt_ioc) {
                /* (re)Enable alt-IOC! (reply interrupt) */
-               dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
-                               ioc->alt_ioc->name));
+               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
+                   ioc->alt_ioc->name));
                CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
                ioc->alt_ioc->active = 1;
        }
@@ -2075,10 +2129,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                (void) GetLanConfigPages(ioc);
                                a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
                                dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "LanAddr = %02X:%02X:%02X:"
-                                       "%02X:%02X:%02X\n",
-                                       ioc->name, a[5], a[4],
-                                       a[3], a[2], a[1], a[0] ));
+                                   "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                   ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
 
                        }
                } else {
@@ -2114,20 +2166,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
         */
        if (hard_reset_done) {
                rc = handlers = 0;
-               for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
-                       if ((ret == 0) && MptResetHandlers[ii]) {
+               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+                       if ((ret == 0) && MptResetHandlers[cb_idx]) {
                                dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "Calling IOC post_reset handler #%d\n",
-                                       ioc->name, ii));
-                               rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
+                                   "Calling IOC post_reset handler #%d\n",
+                                   ioc->name, cb_idx));
+                               rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
                                handlers++;
                        }
 
-                       if (alt_ioc_ready && MptResetHandlers[ii]) {
+                       if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
                                drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "Calling alt-%s post_reset handler #%d\n",
-                                       ioc->name, ioc->alt_ioc->name, ii));
-                               rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
+                                   "Calling IOC post_reset handler #%d\n",
+                                   ioc->alt_ioc->name, cb_idx));
+                               rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
                                handlers++;
                        }
                }
@@ -2166,8 +2218,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
 
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
            " searching for devfn match on %x or %x\n",
-               ioc->name, pci_name(pdev), pdev->bus->number,
-               pdev->devfn, func-1, func+1));
+           ioc->name, pci_name(pdev), pdev->bus->number,
+           pdev->devfn, func-1, func+1));
 
        peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
        if (!peer) {
@@ -2181,15 +2233,15 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
                if (_pcidev == peer) {
                        /* Paranoia checks */
                        if (ioc->alt_ioc != NULL) {
-                               printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+                               printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
                                        ioc->name, ioc->alt_ioc->name);
                                break;
                        } else if (ioc_srch->alt_ioc != NULL) {
-                               printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+                               printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
                                        ioc_srch->name, ioc_srch->alt_ioc->name);
                                break;
                        }
-                       dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+                       dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
                                ioc->name, ioc_srch->name));
                        ioc_srch->alt_ioc = ioc;
                        ioc->alt_ioc = ioc_srch;
@@ -2210,10 +2262,11 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
        int ret;
 
        if (ioc->cached_fw != NULL) {
-               ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
+               ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
+                   "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
                if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
-                       printk(KERN_WARNING MYNAM
-                               ": firmware downloadboot failure (%d)!\n", ret);
+                       printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
+                           ioc->name, ret);
                }
        }
 
@@ -2225,8 +2278,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
 
        if (ioc->alloc != NULL) {
                sz = ioc->alloc_sz;
-               dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free  @ %p, sz=%d bytes\n",
-                       ioc->name, ioc->alloc, ioc->alloc_sz));
+               dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free  @ %p, sz=%d bytes\n",
+                   ioc->name, ioc->alloc, ioc->alloc_sz));
                pci_free_consistent(ioc->pcidev, sz,
                                ioc->alloc, ioc->alloc_dma);
                ioc->reply_frames = NULL;
@@ -2286,15 +2339,14 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
        if (ioc->HostPageBuffer != NULL) {
                if((ret = mpt_host_page_access_control(ioc,
                    MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
-                       printk(KERN_ERR MYNAM
-                          ": %s: host page buffers free failed (%d)!\n",
-                           __FUNCTION__, ret);
+                       printk(MYIOC_s_ERR_FMT
+                          "host page buffers free failed (%d)!\n",
+                           ioc->name, ret);
                }
-               dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free  @ %p, sz=%d bytes\n",
+               dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free  @ %p, sz=%d bytes\n",
                        ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
                pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
-                               ioc->HostPageBuffer,
-                               ioc->HostPageBuffer_dma);
+                   ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
                ioc->HostPageBuffer = NULL;
                ioc->HostPageBuffer_sz = 0;
                ioc->alloc_total -= ioc->HostPageBuffer_sz;
@@ -2336,7 +2388,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
 #if defined(CONFIG_MTRR) && 0
        if (ioc->mtrr_reg > 0) {
                mtrr_del(ioc->mtrr_reg, 0, 0);
-               dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
+               dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
        }
 #endif
 
@@ -2344,8 +2396,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
        list_del(&ioc->list);
 
        sz_last = ioc->alloc_total;
-       dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
-                       ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+       dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
+           ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
 
        if (ioc->alt_ioc)
                ioc->alt_ioc->alt_ioc = NULL;
@@ -2424,7 +2476,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
 
        /* Get current [raw] IOC state  */
        ioc_state = mpt_GetIocState(ioc, 0);
-       dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
+       dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
 
        /*
         *      Check to see if IOC got left/stuck in doorbell handshake
@@ -2446,9 +2498,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
        if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
                statefault = 2;
                printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
-                               ioc->name);
-               printk(KERN_WARNING "           FAULT code = %04xh\n",
-                               ioc_state & MPI_DOORBELL_DATA_MASK);
+                   ioc->name);
+               printk(MYIOC_s_WARN_FMT "           FAULT code = %04xh\n",
+                   ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
        }
 
        /*
@@ -2464,9 +2516,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
                 * Else, fall through to KickStart case
                 */
                whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
-               dinitprintk(ioc, printk(KERN_INFO MYNAM
-                       "whoinit 0x%x statefault %d force %d\n",
-                       whoinit, statefault, force));
+               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                       "whoinit 0x%x statefault %d force %d\n",
+                       ioc->name, whoinit, statefault, force));
                if (whoinit == MPI_WHOINIT_PCI_PEER)
                        return -4;
                else {
@@ -2549,7 +2601,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
 
        /*  Get!  */
        s = CHIPREG_READ32(&ioc->chip->Doorbell);
-//     dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
        sc = s & MPI_IOC_STATE_MASK;
 
        /*  Save!  */
@@ -2581,9 +2632,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
 
        /* IOC *must* NOT be in RESET state! */
        if (ioc->last_state == MPI_IOC_STATE_RESET) {
-               printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
-                               ioc->name,
-                               ioc->last_state );
+               printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
+                   ioc->name, ioc->last_state );
                return -44;
        }
 
@@ -2703,8 +2753,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                }
                ioc->NBShiftFactor  = shiftFactor;
                dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                       "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
-                       ioc->name, vv, shiftFactor, r));
+                   "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
+                   ioc->name, vv, shiftFactor, r));
 
                if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
                        /*
@@ -2757,9 +2807,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 
        /* IOC *must* NOT be in RESET state! */
        if (ioc->last_state == MPI_IOC_STATE_RESET) {
-               printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
-                               ioc->name,
-                               ioc->last_state );
+               printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
+                   ioc->name, ioc->last_state );
                return -4;
        }
 
@@ -2934,7 +2983,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
                state = mpt_GetIocState(ioc, 1);
                count++;
        }
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
                        ioc->name, count));
 
        ioc->aen_event_read_flag=0;
@@ -3027,10 +3076,9 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
        int sz;
 
        sz = ioc->facts.FWImageSize;
-       dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-                ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
-       pci_free_consistent(ioc->pcidev, sz,
-                       ioc->cached_fw, ioc->cached_fw_dma);
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+           ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+       pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
        ioc->cached_fw = NULL;
 
        return;
@@ -3054,7 +3102,6 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
 static int
 mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
 {
-       u8                       request[ioc->req_sz];
        u8                       reply[sizeof(FWUploadReply_t)];
        FWUpload_t              *prequest;
        FWUploadReply_t         *preply;
@@ -3071,8 +3118,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
 
        mpt_alloc_fw_memory(ioc, sz);
 
-       dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-                ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+           ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
 
        if (ioc->cached_fw == NULL) {
                /* Major Failure.
@@ -3080,11 +3127,16 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
                return -ENOMEM;
        }
 
-       prequest = (FWUpload_t *)&request;
-       preply = (FWUploadReply_t *)&reply;
+       prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
+           kzalloc(ioc->req_sz, GFP_KERNEL);
+       if (!prequest) {
+               dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
+                   "while allocating memory \n", ioc->name));
+               mpt_free_fw_memory(ioc);
+               return -ENOMEM;
+       }
 
-       /*  Destination...  */
-       memset(prequest, 0, ioc->req_sz);
+       preply = (FWUploadReply_t *)&reply;
 
        reply_sz = sizeof(reply);
        memset(preply, 0, reply_sz);
@@ -3096,21 +3148,22 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
        ptcsge->DetailsLength = 12;
        ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
        ptcsge->ImageSize = cpu_to_le32(sz);
+       ptcsge++;
 
        sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
 
        flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
-       mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
+       mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
 
        sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
-       dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
-                       prequest, sgeoffset));
-       DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
+           ioc->name, prequest, sgeoffset));
+       DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
 
        ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
                                reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
 
-       dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
 
        cmdStatus = -EFAULT;
        if (ii == 0) {
@@ -3135,6 +3188,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
                        ioc->name));
                mpt_free_fw_memory(ioc);
        }
+       kfree(prequest);
 
        return cmdStatus;
 }
@@ -3381,7 +3435,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
        u32 ioc_state=0;
        int cnt,cntdn;
 
-       dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
        if (ioc->bus_type == SPI) {
                /* Always issue a Msg Unit Reset first. This will clear some
                 * SCSI bus hang conditions.
@@ -3400,7 +3454,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
                return hard_reset_done;
 
        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
-                       ioc->name));
+               ioc->name));
 
        cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2;     /* 2 seconds */
        for (cnt=0; cnt<cntdn; cnt++) {
@@ -3417,8 +3471,8 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
                }
        }
 
-       printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
-                       ioc->name, ioc_state);
+       dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
+               ioc->name, mpt_GetIocState(ioc, 0)));
        return -1;
 }
 
@@ -3560,20 +3614,20 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                 * MptResetHandlers[] registered yet.
                 */
                {
-                       int      ii;
+                       u8       cb_idx;
                        int      r = 0;
 
-                       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
-                               if (MptResetHandlers[ii]) {
+                       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+                               if (MptResetHandlers[cb_idx]) {
                                        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                                                "Calling IOC pre_reset handler #%d\n",
-                                               ioc->name, ii));
-                                       r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
+                                               ioc->name, cb_idx));
+                                       r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
                                        if (ioc->alt_ioc) {
                                                dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                                                        "Calling alt-%s pre_reset handler #%d\n",
-                                                       ioc->name, ioc->alt_ioc->name, ii));
-                                               r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
+                                                       ioc->name, ioc->alt_ioc->name, cb_idx));
+                                               r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
                                        }
                                }
                        }
@@ -3606,8 +3660,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                        }
                        if ((count = mpt_downloadboot(ioc,
                                (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
-                               printk(KERN_WARNING MYNAM
-                                       ": firmware downloadboot failure (%d)!\n", count);
+                               printk(MYIOC_s_WARN_FMT
+                                       "firmware downloadboot failure (%d)!\n", ioc->name, count);
                        }
 
                } else {
@@ -3750,8 +3804,8 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
                        if (sleepFlag != CAN_SLEEP)
                                count *= 10;
 
-                       printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
-                                       ioc->name, (int)((count+5)/HZ));
+                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+                           ioc->name, (int)((count+5)/HZ));
                        return -ETIME;
                }
 
@@ -4144,7 +4198,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
                }
 
                dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
-               DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
+               DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
 
                dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
                                ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
@@ -4349,7 +4403,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 #endif
 
        dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
-       DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
+       DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
 
        dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
                        ioc->name, t, u16cnt/2));
@@ -4824,8 +4878,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
 
                                if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
                                        ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
-                                       ddvprintk(ioc, printk(KERN_INFO MYNAM
-                                               " :%s noQas due to Capabilities=%x\n",
+                                       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                                               "noQas due to Capabilities=%x\n",
                                                ioc->name, pPP0->Capabilities));
                                }
                                ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
@@ -4888,6 +4942,38 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
                                /* Nvram data is left with INVALID mark
                                 */
                                rc = 1;
+                       } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
+
+                               /* This is an ATTO adapter, read Page2 accordingly
+                               */
+                               ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t  *) pbuf;
+                               ATTODeviceInfo_t *pdevice = NULL;
+                               u16 ATTOFlags;
+
+                               /* Save the Port Page 2 data
+                                * (reformat into a 32bit quantity)
+                                */
+                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                 pdevice = &pPP2->DeviceSettings[ii];
+                                 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
+                                 data = 0;
+
+                                 /* Translate ATTO device flags to LSI format
+                                  */
+                                 if (ATTOFlags & ATTOFLAG_DISC)
+                                   data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
+                                 if (ATTOFlags & ATTOFLAG_ID_ENB)
+                                   data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
+                                 if (ATTOFlags & ATTOFLAG_LUN_ENB)
+                                   data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
+                                 if (ATTOFlags & ATTOFLAG_TAGGED)
+                                   data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
+                                 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
+                                   data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
+
+                                 data = (data << 16) | (pdevice->Period << 8) | 10;
+                                 ioc->spi_data.nvram[ii] = data;
+                               }
                        } else {
                                SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t  *) pbuf;
                                MpiDeviceInfo_t *pdevice = NULL;
@@ -5701,10 +5787,10 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        CONFIGPARMS *pCfg;
        unsigned long flags;
 
-       dprintk(ioc, printk(KERN_DEBUG MYNAM
-                       ": IOC %s_reset routed to MPT base driver!\n",
-                       reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           ": IOC %s_reset routed to MPT base driver!\n",
+           ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+           reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
        if (reset_phase == MPT_IOC_SETUP_RESET) {
                ;
@@ -5843,7 +5929,7 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo
 static int
 procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
-       int      ii;
+       u8       cb_idx;
        int      scsi, fc, sas, lan, ctl, targ, dmp;
        char    *drvname;
        int      len;
@@ -5852,10 +5938,10 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo
        len += sprintf(buf+len, "  Fusion MPT base driver\n");
 
        scsi = fc = sas = lan = ctl = targ = dmp = 0;
-       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
                drvname = NULL;
-               if (MptCallbacks[ii]) {
-                       switch (MptDriverClass[ii]) {
+               if (MptCallbacks[cb_idx]) {
+                       switch (MptDriverClass[cb_idx]) {
                        case MPTSPI_DRIVER:
                                if (!scsi++) drvname = "SPI host";
                                break;
@@ -6099,26 +6185,25 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
         * For all other protocol drivers, this is a no-op.
         */
        {
-               int      ii;
+               u8       cb_idx;
                int      r = 0;
 
-               for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
-                       if (MptResetHandlers[ii]) {
+               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+                       if (MptResetHandlers[cb_idx]) {
                                dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
-                                               ioc->name, ii));
-                               r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
+                                               ioc->name, cb_idx));
+                               r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
                                if (ioc->alt_ioc) {
                                        dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
-                                                       ioc->name, ioc->alt_ioc->name, ii));
-                                       r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+                                                       ioc->name, ioc->alt_ioc->name, cb_idx));
+                                       r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
                                }
                        }
                }
        }
 
        if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
-               printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
-                       rc, ioc->name);
+               printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
        }
        ioc->reload_fw = 0;
        if (ioc->alt_ioc)
@@ -6515,6 +6600,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
        u32 evData0 = 0;
 //     u32 evCtx;
        int ii;
+       u8 cb_idx;
        int r = 0;
        int handlers = 0;
        char evStr[EVENT_DESCR_STR_SZ];
@@ -6537,12 +6623,12 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
                        evStr));
 
 #ifdef CONFIG_FUSION_LOGGING
-       devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
-           ": Event data:\n"));
+       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           ": Event data:\n", ioc->name));
        for (ii = 0; ii < evDataLen; ii++)
                devtverboseprintk(ioc, printk(" %08x",
                    le32_to_cpu(pEventReply->Data[ii])));
-       devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
+       devtverboseprintk(ioc, printk("\n"));
 #endif
 
        /*
@@ -6595,11 +6681,11 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
        /*
         *  Call each currently registered protocol event handler.
         */
-       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
-               if (MptEvHandlers[ii]) {
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptEvHandlers[cb_idx]) {
                        devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
-                                       ioc->name, ii));
-                       r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
+                                       ioc->name, cb_idx));
+                       r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
                        handlers++;
                }
        }
@@ -7034,8 +7120,8 @@ mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
        if (!desc)
                return;
 
-       printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
-           ioc->name, ioc_status, desc, extend_desc);
+       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
+           ioc->name, ioc_status, desc, extend_desc));
 }
 
 /**
@@ -7261,7 +7347,8 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
        if (!desc)
                return;
 
-       printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
+       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
+           ioc->name, status, desc));
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -7283,14 +7370,13 @@ EXPORT_SYMBOL(mpt_device_driver_register);
 EXPORT_SYMBOL(mpt_device_driver_deregister);
 EXPORT_SYMBOL(mpt_get_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame);
+EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
 EXPORT_SYMBOL(mpt_free_msg_frame);
 EXPORT_SYMBOL(mpt_add_sge);
 EXPORT_SYMBOL(mpt_send_handshake_request);
 EXPORT_SYMBOL(mpt_verify_adapter);
 EXPORT_SYMBOL(mpt_GetIocState);
 EXPORT_SYMBOL(mpt_print_ioc_summary);
-EXPORT_SYMBOL(mpt_lan_index);
-EXPORT_SYMBOL(mpt_stm_index);
 EXPORT_SYMBOL(mpt_HardResetHandler);
 EXPORT_SYMBOL(mpt_config);
 EXPORT_SYMBOL(mpt_findImVolumes);
@@ -7308,16 +7394,16 @@ EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
 static int __init
 fusion_init(void)
 {
-       int i;
+       u8 cb_idx;
 
        show_mptmod_ver(my_NAME, my_VERSION);
        printk(KERN_INFO COPYRIGHT "\n");
 
-       for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
-               MptCallbacks[i] = NULL;
-               MptDriverClass[i] = MPTUNKNOWN_DRIVER;
-               MptEvHandlers[i] = NULL;
-               MptResetHandlers[i] = NULL;
+       for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+               MptCallbacks[cb_idx] = NULL;
+               MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
+               MptEvHandlers[cb_idx] = NULL;
+               MptResetHandlers[cb_idx] = NULL;
        }
 
        /*  Register ourselves (mptbase) in order to facilitate
index 15ff22645844ace62cfe016d93b6efef0cf242d2..d7682e083f590c8ca39a49a346797300cff02f7e 100644 (file)
@@ -3,9 +3,9 @@
  *      High performance SCSI + LAN / Fibre Channel device drivers.
  *      For use with PCI chip/adapter(s):
  *          LSIFC9xx/LSI409xx Fibre Channel
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #ifndef MODULEAUTHOR
-#define MODULEAUTHOR   "LSI Logic Corporation"
+#define MODULEAUTHOR   "LSI Corporation"
 #endif
 
 #ifndef COPYRIGHT
 #define COPYRIGHT      "Copyright (c) 1999-2007 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.04.05"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.05"
+#define MPT_LINUX_VERSION_COMMON       "3.04.06"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.06"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
  * MPT drivers.  NOTE: Users of these macro defs must
  * themselves define their own MYNAM.
  */
+#define MYIOC_s_FMT                    MYNAM ": %s: "
 #define MYIOC_s_DEBUG_FMT              KERN_DEBUG MYNAM ": %s: "
 #define MYIOC_s_INFO_FMT               KERN_INFO MYNAM ": %s: "
 #define MYIOC_s_NOTE_FMT               KERN_NOTICE MYNAM ": %s: "
 #define MYIOC_s_WARN_FMT               KERN_WARNING MYNAM ": %s: WARNING - "
 #define MYIOC_s_ERR_FMT                        KERN_ERR MYNAM ": %s: ERROR - "
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  ATTO UL4D associated structures and defines
+ */
+#define ATTOFLAG_DISC     0x0001
+#define ATTOFLAG_TAGGED   0x0002
+#define ATTOFLAG_WIDE_ENB 0x0008
+#define ATTOFLAG_ID_ENB   0x0010
+#define ATTOFLAG_LUN_ENB  0x0060
+
+typedef struct _ATTO_DEVICE_INFO
+{
+       u8      Offset;                                 /* 00h */
+       u8      Period;                                 /* 01h */
+       u16     ATTOFlags;                              /* 02h */
+} ATTO_DEVICE_INFO, MPI_POINTER PTR_ATTO_DEVICE_INFO,
+  ATTODeviceInfo_t, MPI_POINTER pATTODeviceInfo_t;
+
+typedef struct _ATTO_CONFIG_PAGE_SCSI_PORT_2
+{
+       CONFIG_PAGE_HEADER      Header;                 /* 00h */
+       u16                     PortFlags;              /* 04h */
+       u16                     Unused1;                /* 06h */
+       u32                     Unused2;                /* 08h */
+       ATTO_DEVICE_INFO        DeviceSettings[16];     /* 0Ch */
+} fATTO_CONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_ATTO_CONFIG_PAGE_SCSI_PORT_2,
+  ATTO_SCSIPortPage2_t, MPI_POINTER pATTO_SCSIPortPage2_t;
+
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  MPT protocol driver defs...
@@ -307,7 +337,8 @@ typedef struct _SYSIF_REGS
        u32     Reserved2[2];   /* 38-3F  reserved for future use    */
        u32     RequestFifo;    /* 40     Request Post/Free FIFO     */
        u32     ReplyFifo;      /* 44     Reply   Post/Free FIFO     */
-       u32     Reserved3[2];   /* 48-4F  reserved for future use    */
+       u32     RequestHiPriFifo; /* 48   Hi Priority Request FIFO   */
+       u32     Reserved3;      /* 4C-4F  reserved for future use    */
        u32     HostIndex;      /* 50     Host Index register        */
        u32     Reserved4[15];  /* 54-8F                             */
        u32     Fubar;          /* 90     For Fubar usage            */
@@ -649,9 +680,9 @@ typedef struct _MPT_ADAPTER
        u8                       reload_fw;     /* Force a FW Reload on next reset */
        u8                       NBShiftFactor;  /* NB Shift Factor based on Block Size (Facts)  */
        u8                       pad1[4];
-       int                      DoneCtx;
-       int                      TaskCtx;
-       int                      InternalCtx;
+       u8                       DoneCtx;
+       u8                       TaskCtx;
+       u8                       InternalCtx;
        spinlock_t               initializing_hba_lock;
        int                      initializing_hba_lock_flag;
        struct list_head         list;
@@ -668,10 +699,14 @@ typedef struct _MPT_ADAPTER
 
        struct work_struct       fc_setup_reset_work;
        struct list_head         fc_rports;
+       struct work_struct       fc_lsc_work;
+       u8                       fc_link_speed[2];
        spinlock_t               fc_rescan_work_lock;
        struct work_struct       fc_rescan_work;
        char                     fc_rescan_work_q_name[KOBJ_NAME_LEN];
        struct workqueue_struct *fc_rescan_work_q;
+       struct scsi_cmnd        **ScsiLookup;
+       spinlock_t                scsi_lookup_lock;
 } MPT_ADAPTER;
 
 /*
@@ -785,7 +820,6 @@ typedef struct _MPT_SCSI_HOST {
        MPT_ADAPTER              *ioc;
        int                       port;
        u32                       pad0;
-       struct scsi_cmnd        **ScsiLookup;
        MPT_LOCAL_REPLY          *pLocal;               /* used for internal commands */
        struct timer_list         timer;
                /* Pool of memory for holding SCpnts before doing
@@ -853,20 +887,21 @@ extern void        mpt_detach(struct pci_dev *pdev);
 extern int      mpt_suspend(struct pci_dev *pdev, pm_message_t state);
 extern int      mpt_resume(struct pci_dev *pdev);
 #endif
-extern int      mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
-extern void     mpt_deregister(int cb_idx);
-extern int      mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
-extern void     mpt_event_deregister(int cb_idx);
-extern int      mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func);
-extern void     mpt_reset_deregister(int cb_idx);
-extern int      mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx);
-extern void     mpt_device_driver_deregister(int cb_idx);
-extern MPT_FRAME_HDR   *mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc);
+extern u8       mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern void     mpt_deregister(u8 cb_idx);
+extern int      mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc);
+extern void     mpt_event_deregister(u8 cb_idx);
+extern int      mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func);
+extern void     mpt_reset_deregister(u8 cb_idx);
+extern int      mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx);
+extern void     mpt_device_driver_deregister(u8 cb_idx);
+extern MPT_FRAME_HDR   *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc);
 extern void     mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
-extern void     mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+extern void     mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+extern void     mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
 extern void     mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
 
-extern int      mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
+extern int      mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
 extern int      mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
 extern u32      mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 extern void     mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
@@ -884,9 +919,6 @@ extern int   mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhys
 extern struct list_head          ioc_list;
 extern struct proc_dir_entry   *mpt_proc_root_dir;
 
-extern int               mpt_lan_index;        /* needed by mptlan.c */
-extern int               mpt_stm_index;        /* needed by mptstm.c */
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif         /* } __KERNEL__ */
 
index 89695e705bdc936b72df4dca3a98b3364ee58f3b..6029509702d35e02b92f76fc1546007c39ee5299 100644 (file)
@@ -1,10 +1,10 @@
 /*
  *  linux/drivers/message/fusion/mptctl.c
  *      mpt Ioctl driver.
- *      For use with LSI Logic PCI chip/adapters
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI PCI chip/adapters
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -66,8 +66,8 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 
-#define COPYRIGHT      "Copyright (c) 1999-2007 LSI Logic Corporation"
-#define MODULEAUTHOR   "LSI Logic Corporation"
+#define COPYRIGHT      "Copyright (c) 1999-2007 LSI Corporation"
+#define MODULEAUTHOR   "LSI Corporation"
 #include "mptbase.h"
 #include "mptctl.h"
 
@@ -83,7 +83,7 @@ MODULE_VERSION(my_VERSION);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-static int mptctl_id = -1;
+static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
 
 static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
 
@@ -181,7 +181,6 @@ static inline int
 mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
 {
        int rc = 0;
-//     dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
 
        if (nonblock) {
                if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
@@ -190,7 +189,6 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
                if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
                        rc = -ERESTARTSYS;
        }
-//     dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down return %d\n", rc));
        return rc;
 }
 
@@ -342,7 +340,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
        SCSITaskMgmt_t  *pScsiTm;
        MPT_SCSI_HOST   *hd;
        int              ii;
-       int              retval;
+       int              retval=0;
 
 
        ioctl->reset &= ~MPTCTL_RESET_OK;
@@ -350,7 +348,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
        if (ioctl->ioc->sh == NULL)
                return -EPERM;
 
-       hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;
+       hd = shost_priv(ioctl->ioc->sh);
        if (hd == NULL)
                return -EPERM;
 
@@ -395,12 +393,19 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
        DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
 
        ioctl->wait_done=0;
-       if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
-            sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
-               dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
-                       " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
-                       hd->ioc, mf));
-               goto mptctl_bus_reset_done;
+
+       if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+           (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+               mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
+       else {
+               retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
+                       sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+               if (retval != 0) {
+                       dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+                               " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
+                               hd->ioc, mf));
+                       goto mptctl_bus_reset_done;
+               }
        }
 
        /* Now wait for the command to complete */
@@ -444,7 +449,7 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
        MPT_SCSI_HOST * hd;
        unsigned long flags;
 
-       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+       hd = shost_priv(ioc->sh);
        if (hd == NULL)
                return;
 
@@ -468,7 +473,7 @@ static int
 mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
        MPT_IOCTL *ioctl = ioc->ioctl;
-       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": IOC %s_reset routed to IOCTL driver!\n",ioc->name,
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
                reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
                reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
@@ -574,7 +579,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        MPT_ADAPTER *iocp = NULL;
 
        if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
-               printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
+               printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
                                "Unable to copy mpt_ioctl_header data @ %p\n",
                                __FILE__, __LINE__, uhdr);
                return -EFAULT;
@@ -587,13 +592,13 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        iocnumX = khdr.iocnum & 0xFF;
        if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
            (iocp == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnumX);
                return -ENODEV;
        }
 
        if (!iocp->active) {
-               printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
                                __FILE__, __LINE__);
                return -EFAULT;
        }
@@ -660,14 +665,14 @@ static int mptctl_do_reset(unsigned long arg)
        MPT_ADAPTER             *iocp;
 
        if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
-               printk(KERN_ERR "%s@%d::mptctl_do_reset - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - "
                                "Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
                                __FILE__, __LINE__, urinfo);
                return -EFAULT;
        }
 
        if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
-               printk(KERN_DEBUG "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
                                __FILE__, __LINE__, krinfo.hdr.iocnum);
                return -ENODEV; /* (-6) No such device or address */
        }
@@ -676,8 +681,8 @@ static int mptctl_do_reset(unsigned long arg)
            iocp->name));
 
        if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
-               printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
-                       __FILE__, __LINE__);
+               printk (MYIOC_s_ERR_FMT "%s@%d::mptctl_do_reset - reset failed.\n",
+                       iocp->name, __FILE__, __LINE__);
                return -1;
        }
 
@@ -708,7 +713,7 @@ mptctl_fw_download(unsigned long arg)
        struct mpt_fw_xfer       kfwdl;
 
        if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
-               printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+               printk(KERN_ERR MYNAM "%s@%d::_ioctl_fwdl - "
                                "Unable to copy mpt_fw_xfer struct @ %p\n",
                                __FILE__, __LINE__, ufwdl);
                return -EFAULT;
@@ -756,7 +761,8 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
        pFWDownloadReply_t       ReplyMsg = NULL;
 
        if (mpt_verify_adapter(ioc, &iocp) < 0) {
-               printk(KERN_DEBUG "ioctl_fwdl - ioc%d not found!\n",                             ioc);
+               printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
+                                ioc);
                return -ENODEV; /* (-6) No such device or address */
        } else {
 
@@ -868,9 +874,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
                        mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
                        n++;
                        if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
-                               printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
-                                               "Unable to copy f/w buffer hunk#%d @ %p\n",
-                                               __FILE__, __LINE__, n, ufwbuf);
+                               printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
+                                       "Unable to copy f/w buffer hunk#%d @ %p\n",
+                                       iocp->name, __FILE__, __LINE__, n, ufwbuf);
                                goto fwdl_out;
                        }
                        fw_bytes_copied += bl->len;
@@ -906,21 +912,22 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
        ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
        iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
        if (iocstat == MPI_IOCSTATUS_SUCCESS) {
-               printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
+               printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
                return 0;
        } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
-               printk(KERN_WARNING MYNAM ": ?Hmmm...  %s says it doesn't support F/W download!?!\n",
-                               iocp->name);
-               printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
+               printk(MYIOC_s_WARN_FMT "Hmmm...  F/W download not supported!?!\n",
+                       iocp->name);
+               printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
+                       iocp->name);
                return -EBADRQC;
        } else if (iocstat == MPI_IOCSTATUS_BUSY) {
-               printk(KERN_WARNING MYNAM ": Warning!  %s says: IOC_BUSY!\n", iocp->name);
-               printk(KERN_WARNING MYNAM ": (try again later?)\n");
+               printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
+               printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
                return -EBUSY;
        } else {
-               printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR!  %s returned [bad] status = %04xh\n",
-                                   iocp->name, iocstat);
-               printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
+               printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
+                       iocp->name, iocstat);
+               printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
                return -ENOMSG;
        }
        return 0;
@@ -970,10 +977,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
         * structures for the SG elements.
         */
        i = MAX_SGL_BYTES / 8;
-       buflist = kmalloc(i, GFP_USER);
-       if (buflist == NULL)
+       buflist = kzalloc(i, GFP_USER);
+       if (!buflist)
                return NULL;
-       memset(buflist, 0, i);
        buflist_ent = 0;
 
        /* Allocate a single block of memory to store the sg elements and
@@ -1008,10 +1014,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
                if (buflist[buflist_ent].kptr == NULL) {
                        alloc_sz = alloc_sz / 2;
                        if (alloc_sz == 0) {
-                               printk(KERN_WARNING MYNAM "-SG: No can do - "
-                                                   "not enough memory!   :-(\n");
-                               printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
-                                                   numfrags);
+                               printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+                                   "not enough memory!   :-(\n", ioc->name);
+                               printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+                                       ioc->name, numfrags);
                                goto free_and_fail;
                        }
                        continue;
@@ -1034,18 +1040,19 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
 
                /* Need to chain? */
                if (fragcnt == sg_spill) {
-                       printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required!   :-(\n");
-                       printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags);
+                       printk(MYIOC_s_WARN_FMT
+                           "-SG: No can do - " "Chain required!   :-(\n", ioc->name);
+                       printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
                        goto free_and_fail;
                }
 
                /* overflow check... */
                if (numfrags*8 > MAX_SGL_BYTES){
                        /* GRRRRR... */
-                       printk(KERN_WARNING MYNAM "-SG: No can do - "
-                                           "too many SG frags!   :-(\n");
-                       printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
-                                           numfrags);
+                       printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+                               "too many SG frags!   :-(\n", ioc->name);
+                       printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+                               ioc->name, numfrags);
                        goto free_and_fail;
                }
        }
@@ -1066,8 +1073,6 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
 
 free_and_fail:
        if (sglbuf != NULL) {
-               int i;
-
                for (i = 0; i < numfrags; i++) {
                        dma_addr_t dma_addr;
                        u8 *kptr;
@@ -1170,7 +1175,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        int                     cim_rev;
        u8                      revision;
        struct scsi_device      *sdev;
-       VirtDevice              *vdev;
+       VirtDevice              *vdevice;
 
        /* Add of PCI INFO results in unaligned access for
         * IA64 and Sparc. Reset long to int. Return no PCI
@@ -1189,13 +1194,13 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 
        karg = kmalloc(data_size, GFP_KERNEL);
        if (karg == NULL) {
-               printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
+               printk(KERN_ERR MYNAM "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
                                __FILE__, __LINE__);
                return -ENOMEM;
        }
 
        if (copy_from_user(karg, uarg, data_size)) {
-               printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_getiocinfo - "
                        "Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                kfree(karg);
@@ -1204,7 +1209,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 
        if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                kfree(karg);
                return -ENODEV;
@@ -1212,9 +1217,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 
        /* Verify the data transfer size is correct. */
        if (karg->hdr.maxDataSize != data_size) {
-               printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
                        "Structure size mismatch. Command not completed.\n",
-                               __FILE__, __LINE__);
+                       ioc->name, __FILE__, __LINE__);
                kfree(karg);
                return -EFAULT;
        }
@@ -1265,8 +1270,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        karg->numDevices = 0;
        if (ioc->sh) {
                shost_for_each_device(sdev, ioc->sh) {
-                       vdev = sdev->hostdata;
-                       if (vdev->vtarget->tflags &
+                       vdevice = sdev->hostdata;
+                       if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
                        karg->numDevices++;
@@ -1290,9 +1295,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        /* Copy the data from kernel memory to user memory
         */
        if (copy_to_user((char __user *)arg, karg, data_size)) {
-               printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
                        "Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
-                               __FILE__, __LINE__, uarg);
+                       ioc->name, __FILE__, __LINE__, uarg);
                kfree(karg);
                return -EFAULT;
        }
@@ -1317,7 +1322,7 @@ mptctl_gettargetinfo (unsigned long arg)
        struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
        struct mpt_ioctl_targetinfo karg;
        MPT_ADAPTER             *ioc;
-       VirtDevice              *vdev;
+       VirtDevice              *vdevice;
        char                    *pmem;
        int                     *pdata;
        int                     iocnum;
@@ -1329,7 +1334,7 @@ mptctl_gettargetinfo (unsigned long arg)
        struct scsi_device      *sdev;
 
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
-               printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - "
                        "Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -1337,7 +1342,7 @@ mptctl_gettargetinfo (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -1353,8 +1358,8 @@ mptctl_gettargetinfo (unsigned long arg)
        port = karg.hdr.port;
 
        if (maxWordsLeft <= 0) {
-               printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
-                               __FILE__, __LINE__);
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+                       ioc->name, __FILE__, __LINE__);
                return -ENOMEM;
        }
 
@@ -1372,13 +1377,12 @@ mptctl_gettargetinfo (unsigned long arg)
         *      15- 8: Bus Number
         *       7- 0: Target ID
         */
-       pmem = kmalloc(numBytes, GFP_KERNEL);
-       if (pmem == NULL) {
-               printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
-                               __FILE__, __LINE__);
+       pmem = kzalloc(numBytes, GFP_KERNEL);
+       if (!pmem) {
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+                       ioc->name, __FILE__, __LINE__);
                return -ENOMEM;
        }
-       memset(pmem, 0, numBytes);
        pdata =  (int *) pmem;
 
        /* Get number of devices
@@ -1387,13 +1391,13 @@ mptctl_gettargetinfo (unsigned long arg)
                shost_for_each_device(sdev, ioc->sh) {
                        if (!maxWordsLeft)
                                continue;
-                       vdev = sdev->hostdata;
-                       if (vdev->vtarget->tflags &
+                       vdevice = sdev->hostdata;
+                       if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
-                       lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun;
-                       *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) +
-                           (vdev->vtarget->id ));
+                       lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun;
+                       *pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) +
+                           (vdevice->vtarget->id ));
                        pdata++;
                        numDevices++;
                        --maxWordsLeft;
@@ -1405,9 +1409,9 @@ mptctl_gettargetinfo (unsigned long arg)
         */
        if (copy_to_user((char __user *)arg, &karg,
                                sizeof(struct mpt_ioctl_targetinfo))) {
-               printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
                        "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
-                               __FILE__, __LINE__, uarg);
+                       ioc->name, __FILE__, __LINE__, uarg);
                kfree(pmem);
                return -EFAULT;
        }
@@ -1415,9 +1419,9 @@ mptctl_gettargetinfo (unsigned long arg)
        /* Copy the remaining data from kernel memory to user memory
         */
        if (copy_to_user(uarg->targetInfo, pmem, numBytes)) {
-               printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
                        "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
-                               __FILE__, __LINE__, pdata);
+                       ioc->name, __FILE__, __LINE__, pdata);
                kfree(pmem);
                return -EFAULT;
        }
@@ -1444,7 +1448,7 @@ mptctl_readtest (unsigned long arg)
        int iocnum;
 
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
-               printk(KERN_ERR "%s@%d::mptctl_readtest - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
                        "Unable to read in mpt_ioctl_test struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -1452,7 +1456,7 @@ mptctl_readtest (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -1476,9 +1480,9 @@ mptctl_readtest (unsigned long arg)
        /* Copy the data from kernel memory to user memory
         */
        if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
-               printk(KERN_ERR "%s@%d::mptctl_readtest - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - "
                        "Unable to write out mpt_ioctl_test struct @ %p\n",
-                               __FILE__, __LINE__, uarg);
+                       ioc->name, __FILE__, __LINE__, uarg);
                return -EFAULT;
        }
 
@@ -1505,7 +1509,7 @@ mptctl_eventquery (unsigned long arg)
        int iocnum;
 
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
-               printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
                        "Unable to read in mpt_ioctl_eventquery struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -1513,7 +1517,7 @@ mptctl_eventquery (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -1526,9 +1530,9 @@ mptctl_eventquery (unsigned long arg)
        /* Copy the data from kernel memory to user memory
         */
        if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
-               printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - "
                        "Unable to write out mpt_ioctl_eventquery struct @ %p\n",
-                               __FILE__, __LINE__, uarg);
+                       ioc->name, __FILE__, __LINE__, uarg);
                return -EFAULT;
        }
        return 0;
@@ -1544,7 +1548,7 @@ mptctl_eventenable (unsigned long arg)
        int iocnum;
 
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
-               printk(KERN_ERR "%s@%d::mptctl_eventenable - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
                        "Unable to read in mpt_ioctl_eventenable struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -1552,7 +1556,7 @@ mptctl_eventenable (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -1563,12 +1567,13 @@ mptctl_eventenable (unsigned long arg)
                /* Have not yet allocated memory - do so now.
                 */
                int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
-               ioc->events = kmalloc(sz, GFP_KERNEL);
-               if (ioc->events == NULL) {
-                       printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+               ioc->events = kzalloc(sz, GFP_KERNEL);
+               if (!ioc->events) {
+                       printk(MYIOC_s_ERR_FMT
+                           ": ERROR - Insufficient memory to add adapter!\n",
+                           ioc->name);
                        return -ENOMEM;
                }
-               memset(ioc->events, 0, sz);
                ioc->alloc_total += sz;
 
                ioc->eventContext = 0;
@@ -1592,7 +1597,7 @@ mptctl_eventreport (unsigned long arg)
        int                      numBytes, maxEvents, max;
 
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
-               printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - "
                        "Unable to read in mpt_ioctl_eventreport struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -1600,7 +1605,7 @@ mptctl_eventreport (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -1626,9 +1631,9 @@ mptctl_eventreport (unsigned long arg)
         */
        numBytes = max * sizeof(MPT_IOCTL_EVENTS);
        if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
-               printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - "
                        "Unable to write out mpt_ioctl_eventreport struct @ %p\n",
-                               __FILE__, __LINE__, ioc->events);
+                       ioc->name, __FILE__, __LINE__, ioc->events);
                return -EFAULT;
        }
 
@@ -1646,7 +1651,7 @@ mptctl_replace_fw (unsigned long arg)
        int                      newFwSize;
 
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
-               printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - "
                        "Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -1654,7 +1659,7 @@ mptctl_replace_fw (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -1684,9 +1689,9 @@ mptctl_replace_fw (unsigned long arg)
        /* Copy the data from user memory to kernel space
         */
        if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
-               printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
                                "Unable to read in mpt_ioctl_replace_fw image "
-                               "@ %p\n", __FILE__, __LINE__, uarg);
+                               "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
                mpt_free_fw_memory(ioc);
                return -EFAULT;
        }
@@ -1720,7 +1725,7 @@ mptctl_mpt_command (unsigned long arg)
 
 
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
-               printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - "
                        "Unable to read in mpt_ioctl_command struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -1728,7 +1733,7 @@ mptctl_mpt_command (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -1769,21 +1774,24 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        ulong           timeout;
        struct scsi_device *sdev;
 
+       /* bufIn and bufOut are used for user to kernel space transfers
+        */
        bufIn.kptr = bufOut.kptr = NULL;
+       bufIn.len = bufOut.len = 0;
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
        if (!ioc->ioctl) {
-               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
                        "No memory available during driver init.\n",
                                __FILE__, __LINE__);
                return -ENOMEM;
        } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
-               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
                        "Busy with IOC Reset \n", __FILE__, __LINE__);
                return -EBUSY;
        }
@@ -1797,9 +1805,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                sz += sizeof(dma_addr_t) + sizeof(u32);
 
        if (sz > ioc->req_sz) {
-               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                        "Request frame too large (%d) maximum (%d)\n",
-                               __FILE__, __LINE__, sz, ioc->req_sz);
+                       ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);
                return -EFAULT;
        }
 
@@ -1817,9 +1825,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
         * Request frame in user space
         */
        if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
-               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                        "Unable to read MF from mpt_ioctl_command struct @ %p\n",
-                       __FILE__, __LINE__, mfPtr);
+                       ioc->name, __FILE__, __LINE__, mfPtr);
                rc = -EFAULT;
                goto done_free_mem;
        }
@@ -1870,17 +1878,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
                        id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
                        if (pScsiReq->TargetID > id) {
-                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                        "Target ID out of bounds. \n",
-                                       __FILE__, __LINE__);
+                                       ioc->name, __FILE__, __LINE__);
                                rc = -ENODEV;
                                goto done_free_mem;
                        }
 
                        if (pScsiReq->Bus >= ioc->number_of_buses) {
-                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                        "Target Bus out of bounds. \n",
-                                       __FILE__, __LINE__);
+                                       ioc->name, __FILE__, __LINE__);
                                rc = -ENODEV;
                                goto done_free_mem;
                        }
@@ -1932,9 +1940,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        ioc->ioctl->id = pScsiReq->TargetID;
 
                } else {
-                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "SCSI driver is not loaded. \n",
-                                       __FILE__, __LINE__);
+                               ioc->name, __FILE__, __LINE__);
                        rc = -EFAULT;
                        goto done_free_mem;
                }
@@ -1951,9 +1959,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
        case MPI_FUNCTION_SATA_PASSTHROUGH:
                if (!ioc->sh) {
-                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "SCSI driver is not loaded. \n",
-                                       __FILE__, __LINE__);
+                               ioc->name, __FILE__, __LINE__);
                        rc = -EFAULT;
                        goto done_free_mem;
                }
@@ -2010,9 +2018,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        ioc->ioctl->reset = MPTCTL_RESET_OK;
                        ioc->ioctl->id = pScsiReq->TargetID;
                } else {
-                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "SCSI driver is not loaded. \n",
-                                       __FILE__, __LINE__);
+                               ioc->name, __FILE__, __LINE__);
                        rc = -EFAULT;
                        goto done_free_mem;
                }
@@ -2021,10 +2029,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        case MPI_FUNCTION_SCSI_TASK_MGMT:
                {
                        MPT_SCSI_HOST *hd = NULL;
-                       if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) {
-                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
+                               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                        "SCSI driver not loaded or SCSI host not found. \n",
-                                       __FILE__, __LINE__);
+                                       ioc->name, __FILE__, __LINE__);
                                rc = -EFAULT;
                                goto done_free_mem;
                        } else if (mptctl_set_tm_flags(hd) != 0) {
@@ -2055,9 +2063,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
                                (pInit->HostMfaHighAddr != high_addr) ||
                                (pInit->SenseBufferHighAddr != sense_high)) {
-                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                        "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
-                                       __FILE__, __LINE__);
+                                       ioc->name, __FILE__, __LINE__);
                                rc = -EFAULT;
                                goto done_free_mem;
                        }
@@ -2088,9 +2096,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        MPI_FUNCTION_LAN_RESET
                */
 
-               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                        "Illegal request (function 0x%x) \n",
-                       __FILE__, __LINE__, hdr->Function);
+                       ioc->name, __FILE__, __LINE__, hdr->Function);
                rc = -EFAULT;
                goto done_free_mem;
        }
@@ -2103,11 +2111,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        psge = (char *) (((int *) mf) + karg.dataSgeOffset);
        flagsLength = 0;
 
-       /* bufIn and bufOut are used for user to kernel space transfers
-        */
-       bufIn.kptr = bufOut.kptr = NULL;
-       bufIn.len = bufOut.len = 0;
-
        if (karg.dataOutSize > 0)
                sgSize ++;
 
@@ -2147,11 +2150,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                if (copy_from_user(bufOut.kptr,
                                                karg.dataOutBufPtr,
                                                bufOut.len)) {
-                                       printk(KERN_ERR
+                                       printk(MYIOC_s_ERR_FMT
                                                "%s@%d::mptctl_do_mpt_command - Unable "
                                                "to read user data "
                                                "struct @ %p\n",
-                                               __FILE__, __LINE__,karg.dataOutBufPtr);
+                                               ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr);
                                        rc =  -EFAULT;
                                        goto done_free_mem;
                                }
@@ -2187,15 +2190,20 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
                DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
-               if (mpt_send_handshake_request(mptctl_id, ioc,
-                       sizeof(SCSITaskMgmt_t), (u32*)mf,
-                       CAN_SLEEP) != 0) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
-                               " (ioc %p, mf %p) \n", ioc->name,
-                               ioc, mf));
-                       mptctl_free_tm_flags(ioc);
-                       rc = -ENODATA;
-                       goto done_free_mem;
+               if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+                   (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+                       mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
+               else {
+                       rc =mpt_send_handshake_request(mptctl_id, ioc,
+                               sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
+                       if (rc != 0) {
+                               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                                   "_send_handshake FAILED! (ioc %p, mf %p)\n",
+                                   ioc->name, ioc, mf));
+                               mptctl_free_tm_flags(ioc);
+                               rc = -ENODATA;
+                               goto done_free_mem;
+                       }
                }
 
        } else
@@ -2233,10 +2241,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                if (sz > 0) {
                        if (copy_to_user(karg.replyFrameBufPtr,
                                 &ioc->ioctl->ReplyFrame, sz)){
-                                printk(KERN_ERR
+                                printk(MYIOC_s_ERR_FMT
                                     "%s@%d::mptctl_do_mpt_command - "
                                 "Unable to write out reply frame %p\n",
-                                __FILE__, __LINE__, karg.replyFrameBufPtr);
+                                ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr);
                                 rc =  -ENODATA;
                                 goto done_free_mem;
                        }
@@ -2249,9 +2257,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
                if (sz > 0) {
                        if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
-                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "Unable to write sense data to user %p\n",
-                               __FILE__, __LINE__,
+                               ioc->name, __FILE__, __LINE__,
                                karg.senseDataPtr);
                                rc =  -ENODATA;
                                goto done_free_mem;
@@ -2267,9 +2275,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
                if (copy_to_user(karg.dataInBufPtr,
                                 bufIn.kptr, karg.dataInSize)) {
-                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "Unable to write data to user %p\n",
-                               __FILE__, __LINE__,
+                               ioc->name, __FILE__, __LINE__,
                                karg.dataInBufPtr);
                        rc =  -ENODATA;
                }
@@ -2340,7 +2348,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
                return -EFAULT;
 
        if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
-               printk(KERN_ERR "%s@%d::mptctl_hp_host_info - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - "
                        "Unable to read in hp_host_info struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -2348,7 +2356,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
@@ -2456,7 +2464,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        karg.soft_resets = 0;
        karg.timeouts = 0;
        if (ioc->sh != NULL) {
-               MPT_SCSI_HOST *hd =  (MPT_SCSI_HOST *)ioc->sh->hostdata;
+               MPT_SCSI_HOST *hd =  shost_priv(ioc->sh);
 
                if (hd && (cim_rev == 1)) {
                        karg.hard_resets = hd->hard_resets;
@@ -2529,9 +2537,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        /* Copy the data from kernel memory to user memory
         */
        if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
-               printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - "
                        "Unable to write out hp_host_info @ %p\n",
-                               __FILE__, __LINE__, uarg);
+                       ioc->name, __FILE__, __LINE__, uarg);
                return -EFAULT;
        }
 
@@ -2567,7 +2575,7 @@ mptctl_hp_targetinfo(unsigned long arg)
        int                     tmp, np, rc = 0;
 
        if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
-               printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
+               printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - "
                        "Unable to read in hp_host_targetinfo struct @ %p\n",
                                __FILE__, __LINE__, uarg);
                return -EFAULT;
@@ -2575,11 +2583,11 @@ mptctl_hp_targetinfo(unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
                (ioc == NULL)) {
-               printk(KERN_DEBUG "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+               printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
-       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
            ioc->name));
 
        /*  There is nothing to do for FCP parts.
@@ -2673,16 +2681,16 @@ mptctl_hp_targetinfo(unsigned long arg)
                        pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
                }
        }
-       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+       hd = shost_priv(ioc->sh);
        if (hd != NULL)
                karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
 
        /* Copy the data from kernel memory to user memory
         */
        if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
-               printk(KERN_ERR "%s@%d::mptctl_hp_target_info - "
+               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - "
                        "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
-                               __FILE__, __LINE__, uarg);
+                       ioc->name, __FILE__, __LINE__, uarg);
                return -EFAULT;
        }
 
@@ -2732,7 +2740,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
        if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
            (iocp == NULL)) {
                printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
-                               __LINE__, iocnumX);
+                       __LINE__, iocnumX);
                return -ENODEV;
        }
 
@@ -2772,7 +2780,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
        if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
            (iocp == NULL)) {
                printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
-                               __LINE__, iocnumX);
+                       __LINE__, iocnumX);
                return -ENODEV;
        }
 
@@ -2853,31 +2861,22 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a
 static int
 mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       int err;
-       int sz;
-       u8 *mem;
+       MPT_IOCTL *mem;
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 
        /*
         * Allocate and inite a MPT_IOCTL structure
        */
-       sz = sizeof (MPT_IOCTL);
-       mem = kmalloc(sz, GFP_KERNEL);
-       if (mem == NULL) {
-               err = -ENOMEM;
-               goto out_fail;
+       mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
+       if (!mem) {
+               mptctl_remove(pdev);
+               return -ENOMEM;
        }
 
-       memset(mem, 0, sz);
-       ioc->ioctl = (MPT_IOCTL *) mem;
+       ioc->ioctl = mem;
        ioc->ioctl->ioc = ioc;
        mutex_init(&ioc->ioctl->ioctl_mutex);
        return 0;
-
-out_fail:
-
-       mptctl_remove(pdev);
-       return err;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2924,7 +2923,8 @@ static int __init mptctl_init(void)
         *  Install our handler
         */
        ++where;
-       if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
+       mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
+       if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
                printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
                misc_deregister(&mptctl_miscdev);
                err = -EBUSY;
index 180b3c156247fc158a8b2b80b466239dbdf2e77a..2c1890127e155d18e2053a414ab26926c6e71d44 100644 (file)
@@ -3,9 +3,9 @@
  *      Fusion MPT misc device (ioctl) driver.
  *      For use with PCI chip/adapter(s):
  *          LSIFC9xx/LSI409xx Fibre Channel
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
index 8422c25e4a3e7f71f8ecc26e95a16b416a5c15ac..3cdd4e9621150bcfae62c741deadb179040561ff 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *  linux/drivers/message/fusion/mptfc.c
- *      For use with LSI Logic PCI chip/adapter(s)
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI PCI chip/adapter(s)
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -90,9 +90,9 @@ static int max_lun = MPTFC_MAX_LUN;
 module_param(max_lun, int, 0);
 MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
 
-static int     mptfcDoneCtx = -1;
-static int     mptfcTaskCtx = -1;
-static int     mptfcInternalCtx = -1; /* Used only for internal commands */
+static u8      mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8      mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8      mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;
 
 static int mptfc_target_alloc(struct scsi_target *starget);
 static int mptfc_slave_alloc(struct scsi_device *sdev);
@@ -194,37 +194,36 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
        struct fc_rport         *rport = starget_to_rport(scsi_target(sdev));
        unsigned long           flags;
        int                     ready;
+       MPT_ADAPTER             *ioc;
 
-       hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+       hd = shost_priv(SCpnt->device->host);
+       ioc = hd->ioc;
        spin_lock_irqsave(shost->host_lock, flags);
        while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
                spin_unlock_irqrestore(shost->host_lock, flags);
-               dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+               dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
                        "mptfc_block_error_handler.%d: %d:%d, port status is "
                        "DID_IMM_RETRY, deferring %s recovery.\n",
-                       ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
-                       ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
-                       SCpnt->device->id,SCpnt->device->lun,caller));
+                       ioc->name, ioc->sh->host_no,
+                       SCpnt->device->id, SCpnt->device->lun, caller));
                msleep(1000);
                spin_lock_irqsave(shost->host_lock, flags);
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
 
        if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
-               dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+               dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
                        "%s.%d: %d:%d, failing recovery, "
-                       "port state %d, vdev %p.\n", caller,
-                       ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
-                       ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
-                       SCpnt->device->id,SCpnt->device->lun,ready,
+                       "port state %d, vdevice %p.\n", caller,
+                       ioc->name, ioc->sh->host_no,
+                       SCpnt->device->id, SCpnt->device->lun, ready,
                        SCpnt->device->hostdata));
                return FAILED;
        }
-       dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+       dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
                "%s.%d: %d:%d, executing recovery.\n", caller,
-               ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
-               ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
-               SCpnt->device->id,SCpnt->device->lun));
+               ioc->name, ioc->sh->host_no,
+               SCpnt->device->id, SCpnt->device->lun));
        return (*func)(SCpnt);
 }
 
@@ -470,7 +469,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
                        /*
                         * if already mapped, remap here.  If not mapped,
                         * target_alloc will allocate vtarget and map,
-                        * slave_alloc will fill in vdev from vtarget.
+                        * slave_alloc will fill in vdevice from vtarget.
                         */
                        if (ri->starget) {
                                vtarget = ri->starget->hostdata;
@@ -602,10 +601,10 @@ mptfc_slave_alloc(struct scsi_device *sdev)
 {
        MPT_SCSI_HOST           *hd;
        VirtTarget              *vtarget;
-       VirtDevice              *vdev;
+       VirtDevice              *vdevice;
        struct scsi_target      *starget;
        struct fc_rport         *rport;
-
+       MPT_ADAPTER             *ioc;
 
        starget = scsi_target(sdev);
        rport = starget_to_rport(starget);
@@ -613,31 +612,32 @@ mptfc_slave_alloc(struct scsi_device *sdev)
        if (!rport || fc_remote_port_chkready(rport))
                return -ENXIO;
 
-       hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+       hd = shost_priv(sdev->host);
+       ioc = hd->ioc;
 
-       vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
-       if (!vdev) {
+       vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+       if (!vdevice) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
-                               hd->ioc->name, sizeof(VirtDevice));
+                               ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
 
 
-       sdev->hostdata = vdev;
+       sdev->hostdata = vdevice;
        vtarget = starget->hostdata;
 
        if (vtarget->num_luns == 0) {
-               vtarget->ioc_id = hd->ioc->id;
+               vtarget->ioc_id = ioc->id;
                vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
        }
 
-       vdev->vtarget = vtarget;
-       vdev->lun = sdev->lun;
+       vdevice->vtarget = vtarget;
+       vdevice->lun = sdev->lun;
 
        vtarget->num_luns++;
 
 
-       mptfc_dump_lun_info(hd->ioc, rport, sdev, vtarget);
+       mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
 
        return 0;
 }
@@ -648,9 +648,9 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        struct mptfc_rport_info *ri;
        struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
        int             err;
-       VirtDevice      *vdev = SCpnt->device->hostdata;
+       VirtDevice      *vdevice = SCpnt->device->hostdata;
 
-       if (!vdev || !vdev->vtarget) {
+       if (!vdevice || !vdevice->vtarget) {
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
                return 0;
@@ -674,6 +674,50 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        return mptscsih_qcmd(SCpnt,done);
 }
 
+/*
+ *     mptfc_display_port_link_speed - displaying link speed
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @portnum: IOC Port number
+ *     @pp0dest: port page0 data payload
+ *
+ */
+static void
+mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest)
+{
+       u8      old_speed, new_speed, state;
+       char    *old, *new;
+
+       if (portnum >= 2)
+               return;
+
+       old_speed = ioc->fc_link_speed[portnum];
+       new_speed = pp0dest->CurrentSpeed;
+       state = pp0dest->PortState;
+
+       if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE &&
+           new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) {
+
+               old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
+                      old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
+                       old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
+                        "Unknown";
+               new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
+                      new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
+                       new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
+                        "Unknown";
+               if (old_speed == 0)
+                       printk(MYIOC_s_NOTE_FMT
+                               "FC Link Established, Speed = %s\n",
+                               ioc->name, new);
+               else if (old_speed != new_speed)
+                       printk(MYIOC_s_WARN_FMT
+                               "FC Link Speed Change, Old Speed = %s, New Speed = %s\n",
+                               ioc->name, old, new);
+
+               ioc->fc_link_speed[portnum] = new_speed;
+       }
+}
+
 /*
  *     mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -773,6 +817,7 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
                                                        " complete.\n",
                                                ioc->name);
                        }
+                       mptfc_display_port_link_speed(ioc, portnum, pp0dest);
                }
 
                pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -1022,6 +1067,18 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
 
 }
 
+static void
+mptfc_link_status_change(struct work_struct *work)
+{
+       MPT_ADAPTER             *ioc =
+               container_of(work, MPT_ADAPTER, fc_rescan_work);
+       int ii;
+
+       for (ii=0; ii < ioc->facts.NumberOfPorts; ii++)
+               (void) mptfc_GetFcPortPage0(ioc, ii);
+
+}
+
 static void
 mptfc_setup_reset(struct work_struct *work)
 {
@@ -1163,6 +1220,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        spin_lock_init(&ioc->fc_rescan_work_lock);
        INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
        INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
+       INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);
 
        spin_lock_irqsave(&ioc->FreeQlock, flags);
 
@@ -1218,20 +1276,21 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
-       hd = (MPT_SCSI_HOST *) sh->hostdata;
+       hd = shost_priv(sh);
        hd->ioc = ioc;
 
        /* SCSI needs scsi_cmnd lookup table!
         * (with size equal to req_depth*PtrSz!)
         */
-       hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
-       if (!hd->ScsiLookup) {
+       ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+       if (!ioc->ScsiLookup) {
                error = -ENOMEM;
                goto out_mptfc_probe;
        }
+       spin_lock_init(&ioc->scsi_lookup_lock);
 
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
-                ioc->name, hd->ScsiLookup));
+                ioc->name, ioc->ScsiLookup));
 
        /* Clear the TM flags
         */
@@ -1262,8 +1321,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        sh->transportt = mptfc_transport_template;
        error = scsi_add_host (sh, &ioc->pcidev->dev);
        if(error) {
-               dprintk(ioc, printk(KERN_ERR MYNAM
-                 "scsi_add_host failed\n"));
+               dprintk(ioc, printk(MYIOC_s_ERR_FMT
+                 "scsi_add_host failed\n", ioc->name));
                goto out_mptfc_probe;
        }
 
@@ -1325,7 +1384,7 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                        ioc->name, event));
 
        if (ioc->sh == NULL ||
-               ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
+               ((hd = shost_priv(ioc->sh)) == NULL))
                return 1;
 
        switch (event) {
@@ -1337,6 +1396,14 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                }
                spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
                break;
+       case MPI_EVENT_LINK_STATUS_CHANGE:
+               spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+               if (ioc->fc_rescan_work_q) {
+                       queue_work(ioc->fc_rescan_work_q,
+                                  &ioc->fc_lsc_work);
+               }
+               spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+               break;
        default:
                rc = mptscsih_event_process(ioc,pEvReply);
                break;
index 3da4c37846ecc91f5bbc0f7b709e272fe014c7c6..7950fc678ed17c281e826529b290c76efa8cca11 100644 (file)
@@ -1,10 +1,10 @@
 /*
  *  linux/drivers/message/fusion/mptlan.c
  *      IP Over Fibre Channel device driver.
- *      For use with LSI Logic Fibre Channel PCI chip/adapters
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI Fibre Channel PCI chip/adapters
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 2000-2007 LSI Logic Corporation
+ *  Copyright (c) 2000-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -154,7 +154,7 @@ static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
 /*
  *  Fusion MPT LAN private data
  */
-static int LanCtx = -1;
+static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
 
 static u32 max_buckets_out = 127;
 static u32 tx_max_out_p = 127 - 16;
@@ -164,12 +164,6 @@ static struct NAA_Hosed *mpt_bad_naa = NULL;
 DEFINE_RWLOCK(bad_naa_lock);
 #endif
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Fusion MPT LAN external data
- */
-extern int mpt_lan_index;
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     lan_reply - Handle all data sent from the hardware.
@@ -1230,6 +1224,8 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
                }
                pRecvReq = (LANReceivePostRequest_t *) mf;
 
+               i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+               mpt_dev->RequestNB[i] = 0;
                count = buckets;
                if (count > max)
                        count = max;
@@ -1351,10 +1347,11 @@ mpt_lan_post_receive_buckets_work(struct work_struct *work)
 static struct net_device *
 mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
 {
-       struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
-       struct mpt_lan_priv *priv = NULL;
+       struct net_device *dev;
+       struct mpt_lan_priv *priv;
        u8 HWaddr[FC_ALEN], *a;
 
+       dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
        if (!dev)
                return NULL;
 
@@ -1366,7 +1363,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        priv->mpt_dev = mpt_dev;
        priv->pnum = pnum;
 
-       memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task));
        INIT_DELAYED_WORK(&priv->post_buckets_task,
                          mpt_lan_post_receive_buckets_work);
        priv->post_buckets_active = 0;
@@ -1391,8 +1387,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        spin_lock_init(&priv->txfidx_lock);
        spin_lock_init(&priv->rxfidx_lock);
 
-       memset(&priv->stats, 0, sizeof(priv->stats));
-
        /*  Grab pre-fetched LANPage1 stuff. :-) */
        a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
 
@@ -1508,9 +1502,6 @@ static int __init mpt_lan_init (void)
                return -EBUSY;
        }
 
-       /* Set the callback index to be used by driver core for turbo replies */
-       mpt_lan_index = LanCtx;
-
        dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
 
        if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) {
@@ -1531,10 +1522,9 @@ static void __exit mpt_lan_exit(void)
        mpt_device_driver_deregister(MPTLAN_DRIVER);
        mpt_reset_deregister(LanCtx);
 
-       if (LanCtx >= 0) {
+       if (LanCtx) {
                mpt_deregister(LanCtx);
-               LanCtx = -1;
-               mpt_lan_index = 0;
+               LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
        }
 }
 
index 8d08c2bed24a49c228611af7d866767e45f92016..bafb67fc81813d4ccfbceaa8ca70fb06234995a2 100644 (file)
@@ -1,10 +1,10 @@
 /*
  *  linux/drivers/message/fusion/mptlan.h
  *      IP Over Fibre Channel device driver.
- *      For use with LSI Logic Fibre Channel PCI chip/adapters
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI Fibre Channel PCI chip/adapters
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 2000-2007 LSI Logic Corporation
+ *  Copyright (c) 2000-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -75,7 +75,7 @@
 #include <asm/io.h>
 
     /* Override mptbase.h by pre-defining these! */
-#define MODULEAUTHOR   "LSI Logic Corporation"
+#define MODULEAUTHOR   "LSI Corporation"
 
 #include "mptbase.h"
 
index b9c69bff218caed8ac8dd2057157d7c72aa31818..e4c94f93de16a98462518419c923bb24f24d9414 100644 (file)
@@ -1,11 +1,10 @@
 /*
  *  linux/drivers/message/fusion/mptsas.c
- *      For use with LSI Logic PCI chip/adapter(s)
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI PCI chip/adapter(s)
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
- *  Copyright (c) 2005-2007 Dell
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -61,6 +60,7 @@
 
 #include "mptbase.h"
 #include "mptscsih.h"
+#include "mptsas.h"
 
 
 #define my_NAME                "Fusion MPT SAS Host driver"
@@ -89,134 +89,35 @@ static int max_lun = MPTSAS_MAX_LUN;
 module_param(max_lun, int, 0);
 MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
 
-static int     mptsasDoneCtx = -1;
-static int     mptsasTaskCtx = -1;
-static int     mptsasInternalCtx = -1; /* Used only for internal commands */
-static int     mptsasMgmtCtx = -1;
+static u8      mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8      mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8      mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
+static u8      mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
 
 static void mptsas_hotplug_work(struct work_struct *work);
 
-struct mptsas_target_reset_event {
-       struct list_head        list;
-       EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
-       u8      target_reset_issued;
-};
-
-enum mptsas_hotplug_action {
-       MPTSAS_ADD_DEVICE,
-       MPTSAS_DEL_DEVICE,
-       MPTSAS_ADD_RAID,
-       MPTSAS_DEL_RAID,
-       MPTSAS_ADD_INACTIVE_VOLUME,
-       MPTSAS_IGNORE_EVENT,
-};
-
-struct mptsas_hotplug_event {
-       struct work_struct      work;
-       MPT_ADAPTER             *ioc;
-       enum mptsas_hotplug_action event_type;
-       u64                     sas_address;
-       u8                      channel;
-       u8                      id;
-       u32                     device_info;
-       u16                     handle;
-       u16                     parent_handle;
-       u8                      phy_id;
-       u8                      phys_disk_num_valid;    /* hrc (hidden raid component) */
-       u8                      phys_disk_num;          /* hrc - unique index*/
-       u8                      hidden_raid_component;  /* hrc - don't expose*/
-};
-
-struct mptsas_discovery_event {
-       struct work_struct      work;
-       MPT_ADAPTER             *ioc;
-};
-
-/*
- * SAS topology structures
- *
- * The MPT Fusion firmware interface spreads information about the
- * SAS topology over many manufacture pages, thus we need some data
- * structure to collect it and process it for the SAS transport class.
- */
-
-struct mptsas_devinfo {
-       u16     handle;         /* unique id to address this device */
-       u16     handle_parent;  /* unique id to address parent device */
-       u16     handle_enclosure; /* enclosure identifier of the enclosure */
-       u16     slot;           /* physical slot in enclosure */
-       u8      phy_id;         /* phy number of parent device */
-       u8      port_id;        /* sas physical port this device
-                                  is assoc'd with */
-       u8      id;             /* logical target id of this device */
-       u32     phys_disk_num;  /* phys disk id, for csmi-ioctls */
-       u8      channel;        /* logical bus number of this device */
-       u64     sas_address;    /* WWN of this device,
-                                  SATA is assigned by HBA,expander */
-       u32     device_info;    /* bitfield detailed info about this device */
-};
-
-/*
- * Specific details on ports, wide/narrow
- */
-struct mptsas_portinfo_details{
-       u16     num_phys;       /* number of phys belong to this port */
-       u64     phy_bitmask;    /* TODO, extend support for 255 phys */
-       struct sas_rphy *rphy;  /* transport layer rphy object */
-       struct sas_port *port;  /* transport layer port object */
-       struct scsi_target *starget;
-       struct mptsas_portinfo *port_info;
-};
-
-struct mptsas_phyinfo {
-       u16     handle;                 /* unique id to address this */
-       u8      phy_id;                 /* phy index */
-       u8      port_id;                /* firmware port identifier */
-       u8      negotiated_link_rate;   /* nego'd link rate for this phy */
-       u8      hw_link_rate;           /* hardware max/min phys link rate */
-       u8      programmed_link_rate;   /* programmed max/min phy link rate */
-       u8      sas_port_add_phy;       /* flag to request sas_port_add_phy*/
-       struct mptsas_devinfo identify; /* point to phy device info */
-       struct mptsas_devinfo attached; /* point to attached device info */
-       struct sas_phy *phy;            /* transport layer phy object */
-       struct mptsas_portinfo *portinfo;
-       struct mptsas_portinfo_details * port_details;
-};
-
-struct mptsas_portinfo {
-       struct list_head list;
-       u16             num_phys;       /* number of phys */
-       struct mptsas_phyinfo *phy_info;
-};
-
-struct mptsas_enclosure {
-       u64     enclosure_logical_id;   /* The WWN for the enclosure */
-       u16     enclosure_handle;       /* unique id to address this */
-       u16     flags;                  /* details enclosure management */
-       u16     num_slot;               /* num slots */
-       u16     start_slot;             /* first slot */
-       u8      start_id;               /* starting logical target id */
-       u8      start_channel;          /* starting logical channel id */
-       u8      sep_id;                 /* SEP device logical target id */
-       u8      sep_channel;            /* SEP channel logical channel id */
-};
-
 static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
                                        MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
 {
-       dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
-       dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
-               le16_to_cpu(phy_data->AttachedDeviceHandle)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
-               le16_to_cpu(phy_data->ControllerDevHandle)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port));
-       dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags));
-       dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags));
-       dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate));
-       dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
-               le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
-       dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n",
-               le32_to_cpu(phy_data->DiscoveryStatus)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "---- IO UNIT PAGE 0 ------------\n", ioc->name));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
+           ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
+           ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
+           ioc->name, phy_data->Port));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
+           ioc->name, phy_data->PortFlags));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
+           ioc->name, phy_data->PhyFlags));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
+           ioc->name, phy_data->NegotiatedLinkRate));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Controller PHY Device Info=0x%X\n", ioc->name,
+           le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
+           ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
 }
 
 static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
@@ -225,27 +126,41 @@ static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
 
        memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
 
-       dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
-       dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n",
-                       le16_to_cpu(pg0->AttachedDevHandle)));
-       dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
-                       (unsigned long long)le64_to_cpu(sas_address)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier));
-       dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
-                       le32_to_cpu(pg0->AttachedDeviceInfo)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate));
-       dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount));
-       dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "---- SAS PHY PAGE 0 ------------\n", ioc->name));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Attached Device Handle=0x%X\n", ioc->name,
+           le16_to_cpu(pg0->AttachedDevHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
+           ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Attached PHY Identifier=0x%X\n", ioc->name,
+           pg0->AttachedPhyIdentifier));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
+           ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
+           ioc->name,  pg0->ProgrammedLinkRate));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
+           ioc->name, pg0->ChangeCount));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
+           ioc->name, le32_to_cpu(pg0->PhyInfo)));
 }
 
 static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
 {
-       dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
-       dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount));
-       dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
-                       pg1->RunningDisparityErrorCount));
-       dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount));
-       dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "---- SAS PHY PAGE 1 ------------\n", ioc->name));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
+           ioc->name,  pg1->InvalidDwordCount));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Running Disparity Error Count=0x%x\n", ioc->name,
+           pg1->RunningDisparityErrorCount));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Loss Dword Synch Count=0x%x\n", ioc->name,
+           pg1->LossDwordSynchCount));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "PHY Reset Problem Count=0x%x\n\n", ioc->name,
+           pg1->PhyResetProblemCount));
 }
 
 static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
@@ -254,37 +169,53 @@ static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
 
        memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
 
-       dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n"));
-       dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot)));
-       dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long)
-           le64_to_cpu(sas_address)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID));
-       dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus));
-       /* The PhyNum field specifies the PHY number of the parent
-        * device this device is linked to
-        */
-       dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum));
-       dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
+           ioc->name, le16_to_cpu(pg0->DevHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
+           ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
+           ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
+           ioc->name, le16_to_cpu(pg0->Slot)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
+           ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
+           ioc->name, pg0->TargetID));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
+           ioc->name, pg0->Bus));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
+           ioc->name, pg0->PhyNum));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
+           ioc->name, le16_to_cpu(pg0->AccessStatus)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
+           ioc->name, le32_to_cpu(pg0->DeviceInfo)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
+           ioc->name, le16_to_cpu(pg0->Flags)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
+           ioc->name, pg0->PhysicalPort));
 }
 
 static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
 {
-       dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n"));
-       dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort));
-       dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier));
-       dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate));
-       dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate));
-       dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate));
-       dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n",
-                       le16_to_cpu(pg1->OwnerDevHandle)));
-       dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n",
-                       le16_to_cpu(pg1->AttachedDevHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
+           ioc->name, pg1->PhysicalPort));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
+           ioc->name, pg1->PhyIdentifier));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
+           ioc->name, pg1->NegotiatedLinkRate));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
+           ioc->name, pg1->ProgrammedLinkRate));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
+           ioc->name, pg1->HwLinkRate));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
+           ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
+       dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Attached Device Handle=0x%X\n\n", ioc->name,
+           le16_to_cpu(pg1->AttachedDevHandle)));
 }
 
 static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
@@ -354,8 +285,8 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
        port_info = port_details->port_info;
        phy_info = port_info->phy_info;
 
-       dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d "
-           "bitmask=0x%016llX\n", __FUNCTION__, port_details,
+       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
+           "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
            port_details->num_phys, (unsigned long long)
            port_details->phy_bitmask));
 
@@ -382,14 +313,15 @@ mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rp
 {
        if (phy_info->port_details) {
                phy_info->port_details->rphy = rphy;
-               dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
+                   ioc->name, rphy));
        }
 
        if (rphy) {
                dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
-                   &rphy->dev, "add:"));
-               dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n",
-                       rphy, rphy->dev.release));
+                   &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
+                   ioc->name, rphy, rphy->dev.release));
        }
 }
 
@@ -410,9 +342,9 @@ mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_po
 
        if (port) {
                dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
-                   &port->dev, "add:"));
-               dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n",
-                       port, port->dev.release));
+                   &port->dev, MYIOC_s_FMT "add:", ioc->name));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
+                   ioc->name, port, port->dev.release));
        }
 }
 
@@ -463,9 +395,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                 * Removing a phy from a port, letting the last
                 * phy be removed by firmware events.
                 */
-               dsaswideprintk(ioc, printk(KERN_DEBUG
-                       "%s: [%p]: deleting phy = %d\n",
-                       __FUNCTION__, port_details, i));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: [%p]: deleting phy = %d\n",
+                   ioc->name, __FUNCTION__, port_details, i));
                port_details->num_phys--;
                port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
                memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
@@ -479,8 +411,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
        phy_info = port_info->phy_info;
        for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
                sas_address = phy_info->attached.sas_address;
-               dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
-                   i, (unsigned long long)sas_address));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
+                   ioc->name, i, (unsigned long long)sas_address));
                if (!sas_address)
                        continue;
                port_details = phy_info->port_details;
@@ -498,9 +430,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                                port_details->phy_bitmask |=
                                    (1 << phy_info->phy_id);
                        phy_info->sas_port_add_phy=1;
-                       dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t"
+                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
                            "phy_id=%d sas_address=0x%018llX\n",
-                           i, (unsigned long long)sas_address));
+                           ioc->name, i, (unsigned long long)sas_address));
                        phy_info->port_details = port_details;
                }
 
@@ -515,9 +447,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                                continue;
                        if (phy_info_cmp->port_details == port_details )
                                continue;
-                       dsaswideprintk(ioc, printk(KERN_DEBUG
+                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                            "\t\tphy_id=%d sas_address=0x%018llX\n",
-                           j, (unsigned long long)
+                           ioc->name, j, (unsigned long long)
                            phy_info_cmp->attached.sas_address));
                        if (phy_info_cmp->port_details) {
                                port_details->rphy =
@@ -549,15 +481,15 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                port_details = port_info->phy_info[i].port_details;
                if (!port_details)
                        continue;
-               dsaswideprintk(ioc, printk(KERN_DEBUG
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                    "%s: [%p]: phy_id=%02d num_phys=%02d "
-                   "bitmask=0x%016llX\n", __FUNCTION__,
+                   "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
                    port_details, i, port_details->num_phys,
                    (unsigned long long)port_details->phy_bitmask));
-               dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n",
-                       port_details->port, port_details->rphy));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
+                   ioc->name, port_details->port, port_details->rphy));
        }
-       dsaswideprintk(ioc, printk(KERN_DEBUG"\n"));
+       dsaswideprintk(ioc, printk("\n"));
        mutex_unlock(&ioc->sas_topology_mutex);
 }
 
@@ -573,15 +505,15 @@ static VirtTarget *
 mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct scsi_device              *sdev;
-       VirtDevice                      *vdev;
+       VirtDevice                      *vdevice;
        VirtTarget                      *vtarget = NULL;
 
        shost_for_each_device(sdev, ioc->sh) {
-               if ((vdev = sdev->hostdata) == NULL)
+               if ((vdevice = sdev->hostdata) == NULL)
                        continue;
-               if (vdev->vtarget->id == id &&
-                   vdev->vtarget->channel == channel)
-                       vtarget = vdev->vtarget;
+               if (vdevice->vtarget->id == id &&
+                   vdevice->vtarget->channel == channel)
+                       vtarget = vdevice->vtarget;
        }
        return vtarget;
 }
@@ -623,13 +555,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
 
        DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
-       if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
-           sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
-               mpt_free_msg_frame(ioc, mf);
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
-                   ioc->name,__FUNCTION__, __LINE__));
-               return 0;
-       }
+       mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
 
        return 1;
 }
@@ -649,7 +575,7 @@ static void
 mptsas_target_reset_queue(MPT_ADAPTER *ioc,
     EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
 {
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(ioc->sh);
        VirtTarget *vtarget = NULL;
        struct mptsas_target_reset_event *target_reset_list;
        u8              id, channel;
@@ -696,7 +622,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
 static void
 mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
 {
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(ioc->sh);
         struct list_head *head = &hd->target_reset_list;
        struct mptsas_target_reset_event *target_reset_list;
        struct mptsas_hotplug_event *ev;
@@ -813,7 +739,7 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 
        if (!ioc->sh || !ioc->sh->hostdata)
                goto out;
-       hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+       hd = shost_priv(ioc->sh);
        if (!hd->ioc)
                goto out;
 
@@ -913,19 +839,20 @@ static int
 mptsas_target_alloc(struct scsi_target *starget)
 {
        struct Scsi_Host *host = dev_to_shost(&starget->dev);
-       MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST           *hd = shost_priv(host);
        VirtTarget              *vtarget;
        u8                      id, channel;
        struct sas_rphy         *rphy;
        struct mptsas_portinfo  *p;
        int                      i;
+       MPT_ADAPTER             *ioc = hd->ioc;
 
        vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
        if (!vtarget)
                return -ENOMEM;
 
        vtarget->starget = starget;
-       vtarget->ioc_id = hd->ioc->id;
+       vtarget->ioc_id = ioc->id;
        vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
        id = starget->id;
        channel = 0;
@@ -934,15 +861,15 @@ mptsas_target_alloc(struct scsi_target *starget)
         * RAID volumes placed beyond the last expected port.
         */
        if (starget->channel == MPTSAS_RAID_CHANNEL) {
-               for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
-                       if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
-                               channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+               for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+                       if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
+                               channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
                goto out;
        }
 
        rphy = dev_to_rphy(starget->dev.parent);
-       mutex_lock(&hd->ioc->sas_topology_mutex);
-       list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(p, &ioc->sas_topology, list) {
                for (i = 0; i < p->num_phys; i++) {
                        if (p->phy_info[i].attached.sas_address !=
                                        rphy->identify.sas_address)
@@ -954,18 +881,18 @@ mptsas_target_alloc(struct scsi_target *starget)
                        /*
                         * Exposing hidden raid components
                         */
-                       if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
-                               id = mptscsih_raid_id_to_num(hd->ioc,
+                       if (mptscsih_is_phys_disk(ioc, channel, id)) {
+                               id = mptscsih_raid_id_to_num(ioc,
                                                channel, id);
                                vtarget->tflags |=
                                    MPT_TARGET_FLAGS_RAID_COMPONENT;
                                p->phy_info[i].attached.phys_disk_num = id;
                        }
-                       mutex_unlock(&hd->ioc->sas_topology_mutex);
+                       mutex_unlock(&ioc->sas_topology_mutex);
                        goto out;
                }
        }
-       mutex_unlock(&hd->ioc->sas_topology_mutex);
+       mutex_unlock(&ioc->sas_topology_mutex);
 
        kfree(vtarget);
        return -ENXIO;
@@ -981,10 +908,11 @@ static void
 mptsas_target_destroy(struct scsi_target *starget)
 {
        struct Scsi_Host *host = dev_to_shost(&starget->dev);
-       MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST           *hd = shost_priv(host);
        struct sas_rphy         *rphy;
        struct mptsas_portinfo  *p;
        int                      i;
+       MPT_ADAPTER *ioc = hd->ioc;
 
        if (!starget->hostdata)
                return;
@@ -993,7 +921,7 @@ mptsas_target_destroy(struct scsi_target *starget)
                goto out;
 
        rphy = dev_to_rphy(starget->dev.parent);
-       list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+       list_for_each_entry(p, &ioc->sas_topology, list) {
                for (i = 0; i < p->num_phys; i++) {
                        if (p->phy_info[i].attached.sas_address !=
                                        rphy->identify.sas_address)
@@ -1013,61 +941,62 @@ static int
 mptsas_slave_alloc(struct scsi_device *sdev)
 {
        struct Scsi_Host        *host = sdev->host;
-       MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST           *hd = shost_priv(host);
        struct sas_rphy         *rphy;
        struct mptsas_portinfo  *p;
-       VirtDevice              *vdev;
+       VirtDevice              *vdevice;
        struct scsi_target      *starget;
        int                     i;
+       MPT_ADAPTER *ioc = hd->ioc;
 
-       vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
-       if (!vdev) {
+       vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+       if (!vdevice) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
-                               hd->ioc->name, sizeof(VirtDevice));
+                               ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
        starget = scsi_target(sdev);
-       vdev->vtarget = starget->hostdata;
+       vdevice->vtarget = starget->hostdata;
 
        if (sdev->channel == MPTSAS_RAID_CHANNEL)
                goto out;
 
        rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
-       mutex_lock(&hd->ioc->sas_topology_mutex);
-       list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(p, &ioc->sas_topology, list) {
                for (i = 0; i < p->num_phys; i++) {
                        if (p->phy_info[i].attached.sas_address !=
                                        rphy->identify.sas_address)
                                continue;
-                       vdev->lun = sdev->lun;
+                       vdevice->lun = sdev->lun;
                        /*
                         * Exposing hidden raid components
                         */
-                       if (mptscsih_is_phys_disk(hd->ioc,
+                       if (mptscsih_is_phys_disk(ioc,
                            p->phy_info[i].attached.channel,
                            p->phy_info[i].attached.id))
                                sdev->no_uld_attach = 1;
-                       mutex_unlock(&hd->ioc->sas_topology_mutex);
+                       mutex_unlock(&ioc->sas_topology_mutex);
                        goto out;
                }
        }
-       mutex_unlock(&hd->ioc->sas_topology_mutex);
+       mutex_unlock(&ioc->sas_topology_mutex);
 
-       kfree(vdev);
+       kfree(vdevice);
        return -ENXIO;
 
  out:
-       vdev->vtarget->num_luns++;
-       sdev->hostdata = vdev;
+       vdevice->vtarget->num_luns++;
+       sdev->hostdata = vdevice;
        return 0;
 }
 
 static int
 mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
-       VirtDevice      *vdev = SCpnt->device->hostdata;
+       VirtDevice      *vdevice = SCpnt->device->hostdata;
 
-       if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
+       if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
                return 0;
@@ -1239,10 +1168,8 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
        /* process the completed Reply Message Frame */
        reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
        if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
-               printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-                   __FUNCTION__,
-                   reply->IOCStatus,
-                   reply->IOCLogInfo);
+               printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+                   ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
                error = -ENXIO;
                goto out_unlock;
        }
@@ -1328,16 +1255,16 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        u64 sas_address = 0;
 
        if (!rsp) {
-               printk(KERN_ERR "%s: the smp response space is missing\n",
-                      __FUNCTION__);
+               printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
+                   ioc->name, __FUNCTION__);
                return -EINVAL;
        }
 
        /* do we need to support multiple segments? */
        if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
-               printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
-                      __FUNCTION__, req->bio->bi_vcnt, req->data_len,
-                      rsp->bio->bi_vcnt, rsp->data_len);
+               printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
+                   ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+                   rsp->bio->bi_vcnt, rsp->data_len);
                return -EINVAL;
        }
 
@@ -1402,7 +1329,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
        timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
        if (!timeleft) {
-               printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
+               printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
                /* On timeout reset the board */
                mpt_HardResetHandler(ioc, CAN_SLEEP);
                ret = -ETIMEDOUT;
@@ -1417,8 +1344,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                memcpy(req->sense, smprep, sizeof(*smprep));
                req->sense_len = sizeof(*smprep);
        } else {
-               printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
-                      __FUNCTION__);
+               printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
+                   ioc->name, __FUNCTION__);
                ret = -ENXIO;
        }
 unmap:
@@ -2062,12 +1989,12 @@ static int mptsas_probe_one_phy(struct device *dev,
                                goto out;
                        }
                        mptsas_set_port(ioc, phy_info, port);
-                       dsaswideprintk(ioc, printk(KERN_DEBUG
+                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                            "sas_port_alloc: port=%p dev=%p port_id=%d\n",
-                           port, dev, port->port_identifier));
+                           ioc->name, port, dev, port->port_identifier));
                }
-               dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
-                   phy_info->phy_id));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
+                   ioc->name, phy_info->phy_id));
                sas_port_add_phy(port, phy_info->phy);
                phy_info->sas_port_add_phy = 0;
        }
@@ -2369,8 +2296,9 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
                                        expander_sas_address)
                                        continue;
                                dsaswideprintk(ioc,
-                                       dev_printk(KERN_DEBUG, &port->dev,
-                                       "delete port (%d)\n", port->port_identifier));
+                                   dev_printk(KERN_DEBUG, &port->dev,
+                                   MYIOC_s_FMT "delete port (%d)\n", ioc->name,
+                                   port->port_identifier));
                                sas_port_delete(port);
                                mptsas_port_delete(ioc, phy_info->port_details);
                        }
@@ -2613,7 +2541,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
 
                ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
                if (!ev) {
-                       printk(KERN_WARNING "mptsas: lost hotplug event\n");
+                       printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
                        goto out;
                }
 
@@ -2754,8 +2682,8 @@ mptsas_hotplug_work(struct work_struct *work)
                printk(MYIOC_s_INFO_FMT
                       "removing %s device, channel %d, id %d, phy %d\n",
                       ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-               dev_printk(KERN_DEBUG, &port->dev,
-                   "delete port (%d)\n", port->port_identifier);
+               dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
+                   "delete port (%d)\n", ioc->name, port->port_identifier);
                sas_port_delete(port);
                mptsas_port_delete(ioc, phy_info->port_details);
                break;
@@ -2796,8 +2724,8 @@ mptsas_hotplug_work(struct work_struct *work)
 
                        if (!vtarget) {
                                dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                       "%s: exit at line=%d\n", ioc->name,
-                                       __FUNCTION__, __LINE__));
+                                   "%s: exit at line=%d\n", ioc->name,
+                                   __FUNCTION__, __LINE__));
                                break;
                        }
                        /*
@@ -2930,7 +2858,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
        case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
                ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
                if (!ev) {
-                       printk(KERN_WARNING "mptsas: lost hotplug event\n");
+                       printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
                        break;
                }
 
@@ -2989,7 +2917,7 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
 
        ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
        if (!ev) {
-               printk(KERN_WARNING "mptsas: lost hotplug event\n");
+               printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
                return;
        }
 
@@ -3288,20 +3216,22 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                sh->sg_tablesize = numSGE;
        }
 
-       hd = (MPT_SCSI_HOST *) sh->hostdata;
+       hd = shost_priv(sh);
        hd->ioc = ioc;
 
        /* SCSI needs scsi_cmnd lookup table!
         * (with size equal to req_depth*PtrSz!)
         */
-       hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
-       if (!hd->ScsiLookup) {
+       ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+       if (!ioc->ScsiLookup) {
                error = -ENOMEM;
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
                goto out_mptsas_probe;
        }
+       spin_lock_init(&ioc->scsi_lookup_lock);
 
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
-                ioc->name, hd->ScsiLookup));
+                ioc->name, ioc->ScsiLookup));
 
        /* Clear the TM flags
         */
@@ -3340,8 +3270,8 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        error = scsi_add_host(sh, &ioc->pcidev->dev);
        if (error) {
-               dprintk(ioc, printk(KERN_ERR MYNAM
-                 "scsi_add_host failed\n"));
+               dprintk(ioc, printk(MYIOC_s_ERR_FMT
+                 "scsi_add_host failed\n", ioc->name));
                goto out_mptsas_probe;
        }
 
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h
new file mode 100644 (file)
index 0000000..7c150f5
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *  linux/drivers/message/fusion/mptsas.h
+ *      High performance SCSI + LAN / Fibre Channel device drivers.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI MPT (Message Passing Technology) firmware.
+ *
+ *  Copyright (c) 1999-2007 LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    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.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef MPTSAS_H_INCLUDED
+#define MPTSAS_H_INCLUDED
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+struct mptsas_target_reset_event {
+       struct list_head        list;
+       EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
+       u8      target_reset_issued;
+};
+
+enum mptsas_hotplug_action {
+       MPTSAS_ADD_DEVICE,
+       MPTSAS_DEL_DEVICE,
+       MPTSAS_ADD_RAID,
+       MPTSAS_DEL_RAID,
+       MPTSAS_ADD_INACTIVE_VOLUME,
+       MPTSAS_IGNORE_EVENT,
+};
+
+struct mptsas_hotplug_event {
+       struct work_struct      work;
+       MPT_ADAPTER             *ioc;
+       enum mptsas_hotplug_action event_type;
+       u64                     sas_address;
+       u8                      channel;
+       u8                      id;
+       u32                     device_info;
+       u16                     handle;
+       u16                     parent_handle;
+       u8                      phy_id;
+       u8                      phys_disk_num_valid;    /* hrc (hidden raid component) */
+       u8                      phys_disk_num;          /* hrc - unique index*/
+       u8                      hidden_raid_component;  /* hrc - don't expose*/
+};
+
+struct mptsas_discovery_event {
+       struct work_struct      work;
+       MPT_ADAPTER             *ioc;
+};
+
+/*
+ * SAS topology structures
+ *
+ * The MPT Fusion firmware interface spreads information about the
+ * SAS topology over many manufacture pages, thus we need some data
+ * structure to collect it and process it for the SAS transport class.
+ */
+
+struct mptsas_devinfo {
+       u16     handle;         /* unique id to address this device */
+       u16     handle_parent;  /* unique id to address parent device */
+       u16     handle_enclosure; /* enclosure identifier of the enclosure */
+       u16     slot;           /* physical slot in enclosure */
+       u8      phy_id;         /* phy number of parent device */
+       u8      port_id;        /* sas physical port this device
+                                  is assoc'd with */
+       u8      id;             /* logical target id of this device */
+       u32     phys_disk_num;  /* phys disk id, for csmi-ioctls */
+       u8      channel;        /* logical bus number of this device */
+       u64     sas_address;    /* WWN of this device,
+                                  SATA is assigned by HBA,expander */
+       u32     device_info;    /* bitfield detailed info about this device */
+};
+
+/*
+ * Specific details on ports, wide/narrow
+ */
+struct mptsas_portinfo_details{
+       u16     num_phys;       /* number of phys belong to this port */
+       u64     phy_bitmask;    /* TODO, extend support for 255 phys */
+       struct sas_rphy *rphy;  /* transport layer rphy object */
+       struct sas_port *port;  /* transport layer port object */
+       struct scsi_target *starget;
+       struct mptsas_portinfo *port_info;
+};
+
+struct mptsas_phyinfo {
+       u16     handle;                 /* unique id to address this */
+       u8      phy_id;                 /* phy index */
+       u8      port_id;                /* firmware port identifier */
+       u8      negotiated_link_rate;   /* nego'd link rate for this phy */
+       u8      hw_link_rate;           /* hardware max/min phys link rate */
+       u8      programmed_link_rate;   /* programmed max/min phy link rate */
+       u8      sas_port_add_phy;       /* flag to request sas_port_add_phy*/
+       struct mptsas_devinfo identify; /* point to phy device info */
+       struct mptsas_devinfo attached; /* point to attached device info */
+       struct sas_phy *phy;            /* transport layer phy object */
+       struct mptsas_portinfo *portinfo;
+       struct mptsas_portinfo_details * port_details;
+};
+
+struct mptsas_portinfo {
+       struct list_head list;
+       u16             num_phys;       /* number of phys */
+       struct mptsas_phyinfo *phy_info;
+};
+
+struct mptsas_enclosure {
+       u64     enclosure_logical_id;   /* The WWN for the enclosure */
+       u16     enclosure_handle;       /* unique id to address this */
+       u16     flags;                  /* details enclosure management */
+       u16     num_slot;               /* num slots */
+       u16     start_slot;             /* first slot */
+       u8      start_id;               /* starting logical target id */
+       u8      start_channel;          /* starting logical channel id */
+       u8      sep_id;                 /* SEP device logical target id */
+       u8      sep_channel;            /* SEP channel logical channel id */
+};
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
index 5431529741ad28380442e3b5618d799b988bdecd..bdff950a54a19103195e893ada00b76f187f251e 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *  linux/drivers/message/fusion/mptscsih.c
- *      For use with LSI Logic PCI chip/adapter(s)
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI PCI chip/adapter(s)
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -80,6 +80,10 @@ MODULE_VERSION(my_VERSION);
 /*
  *  Other private/forward protos...
  */
+static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
+static void    mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
+static int     SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
 int            mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static void    mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
 int            mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
@@ -90,7 +94,6 @@ static void   mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
 static void    mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
 static int     mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
 static int     mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-static int     SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
 
 static int     mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
 
@@ -192,7 +195,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
        int chain_idx;
 
        dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
-                       ioc->name));
+           ioc->name));
        spin_lock_irqsave(&ioc->FreeQlock, flags);
        if (!list_empty(&ioc->FreeChainQ)) {
                int offset;
@@ -203,13 +206,14 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
                offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
                chain_idx = offset / ioc->req_sz;
                rc = SUCCESS;
-               dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
-                       ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
+               dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+                   ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
        } else {
                rc = FAILED;
                chain_idx = MPT_HOST_NO_CHAIN;
-               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer failed\n",
-                       ioc->name));
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
+                   ioc->name));
        }
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
@@ -419,8 +423,8 @@ nextSGEset:
                 *   out the Address and Flags fields.
                 */
                chainSge = (char *) psge;
-               dsgprintk(ioc, printk(KERN_DEBUG "  Current buff @ %p (index 0x%x)",
-                               psge, req_idx));
+               dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Current buff @ %p (index 0x%x)",
+                   ioc->name, psge, req_idx));
 
                /* Start the SGE for the next buffer
                 */
@@ -428,8 +432,8 @@ nextSGEset:
                sgeOffset = 0;
                sg_done = 0;
 
-               dsgprintk(ioc, printk(KERN_DEBUG "  Chain buff @ %p (index 0x%x)\n",
-                               psge, chain_idx));
+               dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Chain buff @ %p (index 0x%x)\n",
+                   ioc->name, psge, chain_idx));
 
                /* Start the SGE for the next buffer
                 */
@@ -588,18 +592,17 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
        }
 
        scsi_print_command(sc);
-       printk(KERN_DEBUG "\tfw_channel = %d, fw_id = %d\n",
-           pScsiReply->Bus, pScsiReply->TargetID);
-       printk(KERN_DEBUG "\trequest_len = %d, underflow = %d, resid = %d\n",
-           scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc));
-       printk(KERN_DEBUG "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
-           le16_to_cpu(pScsiReply->TaskTag),
+       printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
+           ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
+       printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
+           "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
+           scsi_get_resid(sc));
+       printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
+           "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
            le32_to_cpu(pScsiReply->TransferCount), sc->result);
-
-       printk(KERN_DEBUG "\tiocstatus = %s (0x%04x), "
+       printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
            "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
-           desc, ioc_status,
-           desc1, pScsiReply->SCSIStatus,
+           ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
            pScsiReply->SCSIState);
 
        if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
@@ -607,9 +610,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
                asc = sc->sense_buffer[12];
                ascq = sc->sense_buffer[13];
 
-               printk(KERN_DEBUG "\t[sense_key,asc,ascq]: "
-                   "[0x%02x,0x%02x,0x%02x]\n",
-                   skey, asc, ascq);
+               printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
+                   "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
        }
 
        /*
@@ -617,8 +619,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
         */
        if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
            pScsiReply->ResponseInfo)
-               printk(KERN_DEBUG "response_info = %08xh\n",
-                   le32_to_cpu(pScsiReply->ResponseInfo));
+               printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
+                   ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
 }
 #endif
 
@@ -645,11 +647,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        SCSIIORequest_t *pScsiReq;
        SCSIIOReply_t   *pScsiReply;
        u16              req_idx, req_idx_MR;
-       VirtDevice       *vdev;
+       VirtDevice       *vdevice;
        VirtTarget       *vtarget;
 
-       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
-
+       hd = shost_priv(ioc->sh);
        req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
        req_idx_MR = (mr != NULL) ?
            le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
@@ -660,12 +661,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                printk (MYIOC_s_ERR_FMT
                    "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
                    ioc->name, req_idx, req_idx_MR, mf, mr,
-                   hd->ScsiLookup[req_idx_MR]);
+                   mptscsih_get_scsi_lookup(ioc, req_idx_MR));
                return 0;
        }
 
-       sc = hd->ScsiLookup[req_idx];
-       hd->ScsiLookup[req_idx] = NULL;
+       sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
        if (sc == NULL) {
                MPIHeader_t *hdr = (MPIHeader_t *)mf;
 
@@ -738,8 +738,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                 */
                if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
                    pScsiReply->ResponseInfo) {
-                       printk(KERN_NOTICE "[%d:%d:%d:%d] "
-                       "FCP_ResponseInfo=%08xh\n",
+                       printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
+                       "FCP_ResponseInfo=%08xh\n", ioc->name,
                        sc->device->host->host_no, sc->device->channel,
                        sc->device->id, sc->device->lun,
                        le32_to_cpu(pScsiReply->ResponseInfo));
@@ -771,10 +771,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                        if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
                                hd->sel_timeout[pScsiReq->TargetID]++;
 
-                       vdev = sc->device->hostdata;
-                       if (!vdev)
+                       vdevice = sc->device->hostdata;
+                       if (!vdevice)
                                break;
-                       vtarget = vdev->vtarget;
+                       vtarget = vdevice->vtarget;
                        if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
                                mptscsih_issue_sep_command(ioc, vtarget,
                                    MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
@@ -824,9 +824,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                sc->result=DID_SOFT_ERROR << 16;
                        else /* Sufficient data transfer occurred */
                                sc->result = (DID_OK << 16) | scsi_status;
-                       dreplyprintk(ioc, printk(KERN_DEBUG
+                       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                            "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
-                           sc->result, sc->device->channel, sc->device->id));
+                           ioc->name, sc->result, sc->device->channel, sc->device->id));
                        break;
 
                case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
@@ -858,9 +858,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                        }
 
 
-                       dreplyprintk(ioc, printk(KERN_DEBUG "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
-                                       sc->underflow));
-                       dreplyprintk(ioc, printk(KERN_DEBUG "  ActBytesXferd=%02xh\n", xfer_cnt));
+                       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                           "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+                           ioc->name, sc->underflow));
+                       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                           "  ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
 
                        /* Report Queue Full
                         */
@@ -969,48 +971,32 @@ static void
 mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 {
        MPT_ADAPTER *ioc = hd->ioc;
-       struct scsi_cmnd        *SCpnt;
-       MPT_FRAME_HDR   *mf;
+       struct scsi_cmnd *sc;
+       SCSIIORequest_t *mf = NULL;
        int              ii;
-       int              max = ioc->req_depth;
-
-       dprintk(ioc, printk(KERN_DEBUG MYNAM ": flush_ScsiLookup called\n"));
-       for (ii= 0; ii < max; ii++) {
-               if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
-
-                       /* Command found.
-                        */
-
-                       /* Null ScsiLookup index
-                        */
-                       hd->ScsiLookup[ii] = NULL;
-
-                       mf = MPT_INDEX_2_MFPTR(ioc, ii);
-                       dmfprintk(ioc, printk(KERN_DEBUG MYNAM ": flush: ScsiDone (mf=%p,sc=%p)\n",
-                                       mf, SCpnt));
-
-                       /* Free Chain buffers */
-                       mptscsih_freeChainBuffers(ioc, ii);
-
-                       /* Free Message frames */
-                       mpt_free_msg_frame(ioc, mf);
-
-                       if ((unsigned char *)mf != SCpnt->host_scribble)
-                               continue;
-
-                       /* Set status, free OS resources (SG DMA buffers)
-                        * Do OS callback
-                        */
-                       scsi_dma_unmap(SCpnt);
-
-                       SCpnt->result = DID_RESET << 16;
-                       SCpnt->host_scribble = NULL;
+       int              channel, id;
 
-                       SCpnt->scsi_done(SCpnt);        /* Issue the command callback */
-               }
+       for (ii= 0; ii < ioc->req_depth; ii++) {
+               sc = mptscsih_getclear_scsi_lookup(ioc, ii);
+               if (!sc)
+                       continue;
+               mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
+               if (!mf)
+                       continue;
+               channel = mf->Bus;
+               id = mf->TargetID;
+               mptscsih_freeChainBuffers(ioc, ii);
+               mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
+               if ((unsigned char *)mf != sc->host_scribble)
+                       continue;
+               scsi_dma_unmap(sc);
+               sc->result = DID_RESET << 16;
+               sc->host_scribble = NULL;
+               sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+                   "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
+                   " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
+               sc->scsi_done(sc);
        }
-
-       return;
 }
 
 /*
@@ -1032,17 +1018,16 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
 {
        SCSIIORequest_t *mf = NULL;
        int              ii;
-       int              max = hd->ioc->req_depth;
        struct scsi_cmnd *sc;
        struct scsi_lun  lun;
+       MPT_ADAPTER *ioc = hd->ioc;
+       unsigned long   flags;
 
-       dsprintk(hd->ioc, printk(KERN_DEBUG MYNAM ": search_running channel %d id %d lun %d max %d\n",
-           vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
-
-       for (ii=0; ii < max; ii++) {
-               if ((sc = hd->ScsiLookup[ii]) != NULL) {
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       for (ii = 0; ii < ioc->req_depth; ii++) {
+               if ((sc = ioc->ScsiLookup[ii]) != NULL) {
 
-                       mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
+                       mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
                        if (mf == NULL)
                                continue;
                        /* If the device is a hidden raid component, then its
@@ -1059,22 +1044,23 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
                            memcmp(lun.scsi_lun, mf->LUN, 8))
                                continue;
 
-                       /* Cleanup
-                        */
-                       hd->ScsiLookup[ii] = NULL;
-                       mptscsih_freeChainBuffers(hd->ioc, ii);
-                       mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
                        if ((unsigned char *)mf != sc->host_scribble)
                                continue;
+                       ioc->ScsiLookup[ii] = NULL;
+                       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+                       mptscsih_freeChainBuffers(ioc, ii);
+                       mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
                        scsi_dma_unmap(sc);
                        sc->host_scribble = NULL;
                        sc->result = DID_NO_CONNECT << 16;
-                       sdev_printk(KERN_INFO, sc->device, "completing cmds: fw_channel %d,"
-                          "fw_id %d, sc=%p, mf = %p, idx=%x\n", vdevice->vtarget->channel,
+                       sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
+                          "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
                           vdevice->vtarget->id, sc, mf, ii);
                        sc->scsi_done(sc);
+                       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
                }
        }
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
        return;
 }
 
@@ -1097,17 +1083,18 @@ mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSI
 {
        long time = jiffies;
        MPT_SCSI_HOST           *hd;
+       MPT_ADAPTER     *ioc;
 
        if (sc->device == NULL)
                return;
        if (sc->device->host == NULL)
                return;
-       if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
+       if ((hd = shost_priv(sc->device->host)) == NULL)
                return;
-
+       ioc = hd->ioc;
        if (time - hd->last_queue_full > 10 * HZ) {
-               dprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
-                               hd->ioc->name, 0, sc->device->id, sc->device->lun));
+               dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+                               ioc->name, 0, sc->device->id, sc->device->lun));
                hd->last_queue_full = time;
        }
 }
@@ -1134,28 +1121,28 @@ mptscsih_remove(struct pci_dev *pdev)
 
        scsi_remove_host(host);
 
-       if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
+       if((hd = shost_priv(host)) == NULL)
                return;
 
        mptscsih_shutdown(pdev);
 
        sz1=0;
 
-       if (hd->ScsiLookup != NULL) {
-               sz1 = hd->ioc->req_depth * sizeof(void *);
-               kfree(hd->ScsiLookup);
-               hd->ScsiLookup = NULL;
+       if (ioc->ScsiLookup != NULL) {
+               sz1 = ioc->req_depth * sizeof(void *);
+               kfree(ioc->ScsiLookup);
+               ioc->ScsiLookup = NULL;
        }
 
-       dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
            "Free'd ScsiLookup (%d) memory\n",
-           hd->ioc->name, sz1));
+           ioc->name, sz1));
 
        kfree(hd->info_kbuf);
 
        /* NULL the Scsi_Host pointer
         */
-       hd->ioc->sh = NULL;
+       ioc->sh = NULL;
 
        scsi_host_put(host);
 
@@ -1171,15 +1158,6 @@ mptscsih_remove(struct pci_dev *pdev)
 void
 mptscsih_shutdown(struct pci_dev *pdev)
 {
-       MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
-       struct Scsi_Host        *host = ioc->sh;
-       MPT_SCSI_HOST           *hd;
-
-       if(!host)
-               return;
-
-       hd = (MPT_SCSI_HOST *)host->hostdata;
-
 }
 
 #ifdef CONFIG_PM
@@ -1225,7 +1203,7 @@ mptscsih_info(struct Scsi_Host *SChost)
        MPT_SCSI_HOST *h;
        int size = 0;
 
-       h = (MPT_SCSI_HOST *)SChost->hostdata;
+       h = shost_priv(SChost);
 
        if (h) {
                if (h->info_kbuf == NULL)
@@ -1319,7 +1297,7 @@ int
 mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
                        int length, int func)
 {
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER     *ioc = hd->ioc;
        int size = 0;
 
@@ -1358,7 +1336,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        MPT_SCSI_HOST           *hd;
        MPT_FRAME_HDR           *mf;
        SCSIIORequest_t         *pScsiReq;
-       VirtDevice              *vdev = SCpnt->device->hostdata;
+       VirtDevice              *vdevice = SCpnt->device->hostdata;
        int      lun;
        u32      datalen;
        u32      scsictl;
@@ -1368,7 +1346,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        int      ii;
        MPT_ADAPTER *ioc;
 
-       hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+       hd = shost_priv(SCpnt->device->host);
        ioc = hd->ioc;
        lun = SCpnt->device->lun;
        SCpnt->scsi_done = done;
@@ -1385,7 +1363,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        /*
         *  Put together a MPT SCSI request...
         */
-       if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
+       if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
                dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
                                ioc->name));
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -1415,8 +1393,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        /* Default to untagged. Once a target structure has been allocated,
         * use the Inquiry data to determine if device supports tagged.
         */
-       if (vdev
-           && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+       if (vdevice
+           && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
            && (SCpnt->device->tagged_supported)) {
                scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
        } else {
@@ -1425,10 +1403,10 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 
        /* Use the above information to set up the message frame
         */
-       pScsiReq->TargetID = (u8) vdev->vtarget->id;
-       pScsiReq->Bus = vdev->vtarget->channel;
+       pScsiReq->TargetID = (u8) vdevice->vtarget->id;
+       pScsiReq->Bus = vdevice->vtarget->channel;
        pScsiReq->ChainOffset = 0;
-       if (vdev->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)
+       if (vdevice->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)
                pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
        else
                pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
@@ -1453,7 +1431,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        pScsiReq->DataLength = cpu_to_le32(datalen);
 
        /* SenseBuffer low address */
-       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
                                           + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
        /* Now add the SG list
@@ -1465,23 +1443,22 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
                        (dma_addr_t) -1);
        } else {
                /* Add a 32 or 64 bit SGE */
-               if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
+               if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
                        goto fail;
        }
 
        SCpnt->host_scribble = (unsigned char *)mf;
-       hd->ScsiLookup[my_idx] = SCpnt;
+       mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
 
-       mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
+       mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
        dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
                        ioc->name, SCpnt, mf, my_idx));
-       DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf)
+       DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
        return 0;
 
  fail:
-       hd->ScsiLookup[my_idx] = NULL;
-       mptscsih_freeChainBuffers(hd->ioc, my_idx);
-       mpt_free_msg_frame(hd->ioc, mf);
+       mptscsih_freeChainBuffers(ioc, my_idx);
+       mpt_free_msg_frame(ioc, mf);
        return SCSI_MLQUEUE_HOST_BUSY;
 }
 
@@ -1590,38 +1567,38 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c
         */
        if (mptscsih_tm_pending_wait(hd) == FAILED) {
                if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-                       dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler abort: "
+                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
                           "Timed out waiting for last TM (%d) to complete! \n",
                           ioc->name, hd->tmPending));
                        return FAILED;
                } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
-                       dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler target "
+                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
                                "reset: Timed out waiting for last TM (%d) "
                                "to complete! \n", ioc->name,
                                hd->tmPending));
                        return FAILED;
                } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
-                       dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler bus reset: "
+                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
                           "Timed out waiting for last TM (%d) to complete! \n",
                          ioc->name, hd->tmPending));
                        return FAILED;
                }
        } else {
-               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
                hd->tmPending |=  (1 << type);
-               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
        }
 
-       ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
+       ioc_raw_state = mpt_GetIocState(ioc, 0);
 
        if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
                printk(MYIOC_s_WARN_FMT
                        "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
                        ioc->name, type, ioc_raw_state);
-               printk(KERN_WARNING " Issuing HardReset!!\n");
+               printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
                if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
-                       printk((KERN_WARNING "TMHandler: HardReset "
-                               "FAILED!!\n"));
+                       printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
+                           "FAILED!!\n", ioc->name);
                return FAILED;
        }
 
@@ -1680,16 +1657,17 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
        SCSITaskMgmt_t  *pScsiTm;
        int              ii;
        int              retval;
+       MPT_ADAPTER     *ioc = hd->ioc;
 
        /* Return Fail to calling function if no message frames available.
         */
-       if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
-               dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
-                               hd->ioc->name));
+       if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
+                               ioc->name));
                return FAILED;
        }
-       dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
-                       hd->ioc->name, mf));
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
+                       ioc->name, mf));
 
        /* Format the Request
         */
@@ -1712,28 +1690,34 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
 
        pScsiTm->TaskMsgContext = ctx2abort;
 
-       dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
-               "type=%d\n", hd->ioc->name, ctx2abort, type));
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
+               "type=%d\n", ioc->name, ctx2abort, type));
 
        DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
 
-       if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
-               sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
-               dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
-                       " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
-                       hd->ioc, mf, retval));
-               goto fail_out;
+       if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+           (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+               mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+       else {
+               retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
+                       sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+               if (retval) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
+                       " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
+                       ioc, mf, retval));
+                       goto fail_out;
+               }
        }
 
        if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
-               dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
-                       " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
-                       hd->ioc, mf));
-               dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-                        hd->ioc->name));
-               retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
-               dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
-                        hd->ioc->name, retval));
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
+                       " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
+                       ioc, mf));
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+                        ioc->name));
+               retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
+                        ioc->name, retval));
                goto fail_out;
        }
 
@@ -1754,7 +1738,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
        /*
         * Free task managment mf, and corresponding tm flags
         */
-       mpt_free_msg_frame(hd->ioc, mf);
+       mpt_free_msg_frame(ioc, mf);
        hd->tmPending = 0;
        hd->tmState = TM_STATE_NONE;
        return FAILED;
@@ -1797,11 +1781,11 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 
        /* If we can't locate our host adapter structure, return FAILED status.
         */
-       if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
+       if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
                SCpnt->result = DID_RESET << 16;
                SCpnt->scsi_done(SCpnt);
-               printk(KERN_DEBUG MYNAM ": mptscsih_abort: Can't locate "
-                   "host! (sc=%p)\n", SCpnt);
+               printk(KERN_ERR MYNAM ": task abort: "
+                   "can't locate host! (sc=%p)\n", SCpnt);
                return FAILED;
        }
 
@@ -1812,8 +1796,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 
        vdevice = SCpnt->device->hostdata;
        if (!vdevice || !vdevice->vtarget) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been "
-                   "deleted (sc=%p)\n", ioc->name, SCpnt));
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: device has been deleted (sc=%p)\n",
+                   ioc->name, SCpnt));
                SCpnt->result = DID_NO_CONNECT << 16;
                SCpnt->scsi_done(SCpnt);
                retval = 0;
@@ -1823,8 +1808,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
        /* Task aborts are not supported for hidden raid components.
         */
        if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: hidden raid "
-                   "component (sc=%p)\n", ioc->name, SCpnt));
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: hidden raid component (sc=%p)\n",
+                   ioc->name, SCpnt));
                SCpnt->result = DID_RESET << 16;
                retval = FAILED;
                goto out;
@@ -1832,12 +1818,12 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 
        /* Find this command
         */
-       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
                /* Cmd not found in ScsiLookup.
                 * Do OS callback.
                 */
                SCpnt->result = DID_RESET << 16;
-               dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: mptscsih_abort: "
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
                   "Command not in the active list! (sc=%p)\n", ioc->name,
                   SCpnt));
                retval = 0;
@@ -1859,7 +1845,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
         *       swap it here either.  It is an opaque cookie to
         *       the controller, so it does not matter. -DaveM
         */
-       mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+       mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
        ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
 
        hd->abortSCpnt = SCpnt;
@@ -1868,7 +1854,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
            vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
            ctx2abort, mptscsih_get_tm_timeout(ioc));
 
-       if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
+       if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
            SCpnt->serial_number == sn)
                retval = FAILED;
 
@@ -1901,9 +1887,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
 
        /* If we can't locate our host adapter structure, return FAILED status.
         */
-       if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
-               printk(KERN_DEBUG MYNAM ": mptscsih_dev_reset: Can't "
-                   "locate host! (sc=%p)\n", SCpnt);
+       if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+               printk(KERN_ERR MYNAM ": target reset: "
+                  "Can't locate host! (sc=%p)\n", SCpnt);
                return FAILED;
        }
 
@@ -1959,14 +1945,14 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
 {
        MPT_SCSI_HOST   *hd;
        int              retval;
-       VirtDevice       *vdev;
+       VirtDevice       *vdevice;
        MPT_ADAPTER     *ioc;
 
        /* If we can't locate our host adapter structure, return FAILED status.
         */
-       if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
-               printk(KERN_DEBUG MYNAM ": mptscsih_bus_reset: Can't "
-                   "locate host! (sc=%p)\n", SCpnt );
+       if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+               printk(KERN_ERR MYNAM ": bus reset: "
+                  "Can't locate host! (sc=%p)\n", SCpnt);
                return FAILED;
        }
 
@@ -1978,9 +1964,9 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
        if (hd->timeouts < -1)
                hd->timeouts++;
 
-       vdev = SCpnt->device->hostdata;
+       vdevice = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-           vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
+           vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
 
        printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
            ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
@@ -2008,9 +1994,9 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
        MPT_ADAPTER     *ioc;
 
        /*  If we can't locate the host to reset, then we failed. */
-       if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
-               printk( KERN_DEBUG MYNAM ": mptscsih_host_reset: Can't "
-                   "locate host! (sc=%p)\n", SCpnt);
+       if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+               printk(KERN_ERR MYNAM ": host reset: "
+                   "Can't locate host! (sc=%p)\n", SCpnt);
                return FAILED;
        }
 
@@ -2021,7 +2007,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
        /*  If our attempts to reset the host failed, then return a failed
         *  status.  The host will be taken off line by the SCSI mid-layer.
         */
-       if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
+       if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
                retval = FAILED;
        } else {
                /*  Make sure TM pending is cleared and TM state is set to
@@ -2051,17 +2037,18 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
        unsigned long  flags;
        int            loop_count = 4 * 10;  /* Wait 10 seconds */
        int            status = FAILED;
+       MPT_ADAPTER     *ioc = hd->ioc;
 
        do {
-               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
                if (hd->tmState == TM_STATE_NONE) {
                        hd->tmState = TM_STATE_IN_PROGRESS;
                        hd->tmPending = 1;
-                       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
                        status = SUCCESS;
                        break;
                }
-               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
                msleep(250);
        } while (--loop_count);
 
@@ -2082,15 +2069,16 @@ mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
        unsigned long  flags;
        int            loop_count = 4 * timeout;
        int            status = FAILED;
+       MPT_ADAPTER     *ioc = hd->ioc;
 
        do {
-               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
                if(hd->tmPending == 0) {
                        status = SUCCESS;
-                       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
                        break;
                }
-               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
                msleep(250);
        } while (--loop_count);
 
@@ -2172,7 +2160,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
                return 1;
        }
 
-       hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+       hd = shost_priv(ioc->sh);
        pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
        pScsiTmReq = (SCSITaskMgmt_t*)mf;
        tmType = pScsiTmReq->TaskType;
@@ -2223,7 +2211,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
                if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
                    hd->cmdPtr)
                        if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
-                               printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+                               printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
                break;
 
        case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
@@ -2366,7 +2354,7 @@ void
 mptscsih_slave_destroy(struct scsi_device *sdev)
 {
        struct Scsi_Host        *host = sdev->host;
-       MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST           *hd = shost_priv(host);
        VirtTarget              *vtarget;
        VirtDevice              *vdevice;
        struct scsi_target      *starget;
@@ -2393,16 +2381,17 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
 int
 mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
 {
-       MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+       MPT_SCSI_HOST           *hd = shost_priv(sdev->host);
        VirtTarget              *vtarget;
        struct scsi_target      *starget;
        int                     max_depth;
        int                     tagged;
+       MPT_ADAPTER             *ioc = hd->ioc;
 
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
 
-       if (hd->ioc->bus_type == SPI) {
+       if (ioc->bus_type == SPI) {
                if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
                        max_depth = 1;
                else if (sdev->type == TYPE_DISK &&
@@ -2437,19 +2426,20 @@ mptscsih_slave_configure(struct scsi_device *sdev)
        VirtTarget              *vtarget;
        VirtDevice              *vdevice;
        struct scsi_target      *starget;
-       MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)sh->hostdata;
+       MPT_SCSI_HOST           *hd = shost_priv(sh);
+       MPT_ADAPTER             *ioc = hd->ioc;
 
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
        vdevice = sdev->hostdata;
 
-       dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+       dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "device @ %p, channel=%d, id=%d, lun=%d\n",
-               hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
-       if (hd->ioc->bus_type == SPI)
-               dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+               ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
+       if (ioc->bus_type == SPI)
+               dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                    "sdtr %d wdtr %d ppr %d inq length=%d\n",
-                   hd->ioc->name, sdev->sdtr, sdev->wdtr,
+                   ioc->name, sdev->sdtr, sdev->wdtr,
                    sdev->ppr, sdev->inquiry_len));
 
        if (sdev->id > sh->max_id) {
@@ -2461,21 +2451,21 @@ mptscsih_slave_configure(struct scsi_device *sdev)
        vdevice->configured_lun = 1;
        mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
 
-       dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+       dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "Queue depth=%d, tflags=%x\n",
-               hd->ioc->name, sdev->queue_depth, vtarget->tflags));
+               ioc->name, sdev->queue_depth, vtarget->tflags));
 
-       if (hd->ioc->bus_type == SPI)
-               dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+       if (ioc->bus_type == SPI)
+               dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                    "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
-                   hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
+                   ioc->name, vtarget->negoFlags, vtarget->maxOffset,
                    vtarget->minSyncFactor));
 
 slave_configure_exit:
 
-       dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+       dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "tagged %d, simple %d, ordered %d\n",
-               hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
+               ioc->name,sdev->tagged_supported, sdev->simple_tags,
                sdev->ordered_tags));
 
        return 0;
@@ -2494,14 +2484,15 @@ slave_configure_exit:
 static void
 mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
 {
-       VirtDevice      *vdev;
+       VirtDevice      *vdevice;
        SCSIIORequest_t *pReq;
        u32              sense_count = le32_to_cpu(pScsiReply->SenseCount);
+       MPT_ADAPTER     *ioc = hd->ioc;
 
        /* Get target structure
         */
        pReq = (SCSIIORequest_t *) mf;
-       vdev = sc->device->hostdata;
+       vdevice = sc->device->hostdata;
 
        if (sense_count) {
                u8 *sense_data;
@@ -2509,15 +2500,14 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
 
                /* Copy the sense received into the scsi command block. */
                req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-               sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
+               sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
                memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
 
                /* Log SMART data (asc = 0x5D, non-IM case only) if required.
                 */
-               if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
-                       if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
+               if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
+                       if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
                                int idx;
-                               MPT_ADAPTER *ioc = hd->ioc;
 
                                idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
                                ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
@@ -2530,36 +2520,116 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
                                ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
 
                                ioc->eventContext++;
-                               if (hd->ioc->pcidev->vendor ==
+                               if (ioc->pcidev->vendor ==
                                    PCI_VENDOR_ID_IBM) {
-                                       mptscsih_issue_sep_command(hd->ioc,
-                                           vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
-                                       vdev->vtarget->tflags |=
+                                       mptscsih_issue_sep_command(ioc,
+                                           vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+                                       vdevice->vtarget->tflags |=
                                            MPT_TARGET_FLAGS_LED_ON;
                                }
                        }
                }
        } else {
-               dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
-                               hd->ioc->name));
+               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
+                               ioc->name));
        }
 }
 
-static int
-SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
+/**
+ * mptscsih_get_scsi_lookup
+ *
+ * retrieves scmd entry from ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ *
+ * Returns the scsi_cmd pointer
+ *
+ **/
+static struct scsi_cmnd *
+mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
 {
-       MPT_SCSI_HOST *hd;
-       int i;
+       unsigned long   flags;
+       struct scsi_cmnd *scmd;
 
-       hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       scmd = ioc->ScsiLookup[i];
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       return scmd;
+}
+
+/**
+ * mptscsih_getclear_scsi_lookup
+ *
+ * retrieves and clears scmd entry from ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ *
+ * Returns the scsi_cmd pointer
+ *
+ **/
+static struct scsi_cmnd *
+mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
+{
+       unsigned long   flags;
+       struct scsi_cmnd *scmd;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       scmd = ioc->ScsiLookup[i];
+       ioc->ScsiLookup[i] = NULL;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       return scmd;
+}
 
-       for (i = 0; i < hd->ioc->req_depth; i++) {
-               if (hd->ScsiLookup[i] == sc) {
-                       return i;
+/**
+ * mptscsih_set_scsi_lookup
+ *
+ * writes a scmd entry into the ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ * @scmd: scsi_cmnd pointer
+ *
+ **/
+static void
+mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
+{
+       unsigned long   flags;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->ScsiLookup[i] = scmd;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+}
+
+/**
+ * SCPNT_TO_LOOKUP_IDX
+ *
+ * search's for a given scmd in the ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @scmd: scsi_cmnd pointer
+ *
+ **/
+static int
+SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
+{
+       unsigned long   flags;
+       int i, index=-1;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       for (i = 0; i < ioc->req_depth; i++) {
+               if (ioc->ScsiLookup[i] == sc) {
+                       index = i;
+                       goto out;
                }
        }
 
-       return -1;
+ out:
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return index;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2568,21 +2638,20 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
        MPT_SCSI_HOST   *hd;
        unsigned long    flags;
-       int             ii;
 
-       dtmprintk(ioc, printk(KERN_DEBUG MYNAM
-                       ": IOC %s_reset routed to SCSI host driver!\n",
-                       reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           ": IOC %s_reset routed to SCSI host driver!\n",
+           ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+           reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
        /* If a FW reload request arrives after base installed but
         * before all scsi hosts have been attached, then an alt_ioc
         * may have a NULL sh pointer.
         */
-       if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+       if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
                return 0;
        else
-               hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+               hd = shost_priv(ioc->sh);
 
        if (reset_phase == MPT_IOC_SETUP_RESET) {
                dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
@@ -2624,11 +2693,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
                 * Init all control structures.
                 */
 
-               /* ScsiLookup initialization
-                */
-               for (ii=0; ii < hd->ioc->req_depth; ii++)
-                       hd->ScsiLookup[ii] = NULL;
-
                /* 2. Chain Buffer initialization
                 */
 
@@ -2675,7 +2739,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                        ioc->name, event));
 
        if (ioc->sh == NULL ||
-               ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
+               ((hd = shost_priv(ioc->sh)) == NULL))
                return 1;
 
        switch (event) {
@@ -2713,7 +2777,8 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
        case MPI_EVENT_STATE_CHANGE:                    /* 02 */
        case MPI_EVENT_EVENT_CHANGE:                    /* 0A */
        default:
-               dprintk(ioc, printk(KERN_DEBUG MYNAM ": Ignoring event (=%02Xh)\n", event));
+               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
+                   ioc->name, event));
                break;
        }
 
@@ -2753,7 +2818,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        int              completionCode;
        u16              req_idx;
 
-       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+       hd = shost_priv(ioc->sh);
 
        if ((mf == NULL) ||
            (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
@@ -2765,17 +2830,17 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 
        del_timer(&hd->timer);
        req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-       hd->ScsiLookup[req_idx] = NULL;
+       mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
        pReq = (SCSIIORequest_t *) mf;
 
        if (mf != hd->cmdPtr) {
                printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
-                               hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
+                               ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
        }
        hd->cmdPtr = NULL;
 
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
-                       hd->ioc->name, mf, mr, req_idx));
+                       ioc->name, mf, mr, req_idx));
 
        hd->pLocal = &hd->localReply;
        hd->pLocal->scsiStatus = 0;
@@ -2839,15 +2904,15 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                 */
                                completionCode = MPT_SCANDV_SENSE;
                                hd->pLocal->scsiStatus = scsi_status;
-                               sense_data = ((u8 *)hd->ioc->sense_buf_pool +
+                               sense_data = ((u8 *)ioc->sense_buf_pool +
                                        (req_idx * MPT_SENSE_BUFFER_ALLOC));
 
                                sz = min_t(int, pReq->SenseBufferLength,
                                                        SCSI_STD_SENSE_BYTES);
                                memcpy(hd->pLocal->sense, sense_data, sz);
 
-                               ddvprintk(ioc, printk(KERN_DEBUG "  Check Condition, sense ptr %p\n",
-                                               sense_data));
+                               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Check Condition, sense ptr %p\n",
+                                   ioc->name, sense_data));
                        } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
                                if (pReq->CDB[0] == INQUIRY)
                                        completionCode = MPT_SCANDV_ISSUE_SENSE;
@@ -2906,8 +2971,9 @@ void
 mptscsih_timer_expired(unsigned long data)
 {
        MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+       MPT_ADAPTER     *ioc = hd->ioc;
 
-       ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
 
        if (hd->cmdPtr) {
                MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
@@ -2921,13 +2987,13 @@ mptscsih_timer_expired(unsigned long data)
                         */
                } else {
                        /* Perform a FW reload */
-                       if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
-                               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
+                       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
+                               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
                        }
                }
        } else {
                /* This should NEVER happen */
-               printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
+               printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
        }
 
        /* No more processing.
@@ -2935,7 +3001,7 @@ mptscsih_timer_expired(unsigned long data)
         * The FW will reply to all outstanding commands, callback will finish cleanup.
         * Hard reset clean-up will free all resources.
         */
-       ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name));
+       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
 
        return;
 }
@@ -2973,11 +3039,12 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
        char             cmdLen;
        char             CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        char             cmd = io->cmd;
+       MPT_ADAPTER     *ioc = hd->ioc;
 
        in_isr = in_interrupt();
        if (in_isr) {
-               dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
-                                       hd->ioc->name));
+               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+                                       ioc->name));
                return -EPERM;
        }
 
@@ -3078,9 +3145,9 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 
        /* Get and Populate a free Frame
         */
-       if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
-               ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "No msg frames!\n",
-                                       hd->ioc->name));
+       if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
+                   ioc->name));
                return -EBUSY;
        }
 
@@ -3119,19 +3186,19 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 
        if (cmd == REQUEST_SENSE) {
                pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
-               ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
-                       hd->ioc->name, cmd));
+               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
+                       ioc->name, cmd));
        }
 
        for (ii=0; ii < 16; ii++)
                pScsiReq->CDB[ii] = CDB[ii];
 
        pScsiReq->DataLength = cpu_to_le32(io->size);
-       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
                                           + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-       ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
-                       hd->ioc->name, cmd, io->channel, io->id, io->lun));
+       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+                       ioc->name, cmd, io->channel, io->id, io->lun));
 
        if (dir == MPI_SCSIIO_CONTROL_READ) {
                mpt_add_sge((char *) &pScsiReq->SGL,
@@ -3166,7 +3233,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
        hd->cmdPtr = mf;
 
        add_timer(&hd->timer);
-       mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
+       mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
        wait_event(hd->scandv_waitq, hd->scandv_wait_done);
 
        if (hd->pLocal) {
@@ -3182,8 +3249,8 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
        } else {
                rc = -EFAULT;
                /* This should never happen. */
-               ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
-                               hd->ioc->name));
+               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
+                               ioc->name));
        }
 
        return rc;
@@ -3235,7 +3302,7 @@ static ssize_t
 mptscsih_version_fw_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
@@ -3250,7 +3317,7 @@ static ssize_t
 mptscsih_version_bios_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
@@ -3265,7 +3332,7 @@ static ssize_t
 mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
@@ -3276,7 +3343,7 @@ static ssize_t
 mptscsih_version_product_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
@@ -3288,7 +3355,7 @@ static ssize_t
 mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02xh\n",
@@ -3301,7 +3368,7 @@ static ssize_t
 mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
@@ -3313,7 +3380,7 @@ static ssize_t
 mptscsih_board_name_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
@@ -3324,7 +3391,7 @@ static ssize_t
 mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
@@ -3336,7 +3403,7 @@ static ssize_t
 mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
@@ -3348,7 +3415,7 @@ static ssize_t
 mptscsih_io_delay_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
@@ -3360,7 +3427,7 @@ static ssize_t
 mptscsih_device_delay_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
@@ -3372,7 +3439,7 @@ static ssize_t
 mptscsih_debug_level_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
@@ -3382,7 +3449,7 @@ mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
                                                                size_t count)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)host->hostdata;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER *ioc = hd->ioc;
        int val = 0;
 
index 67b088db2f109c2831afe3356108f23c4323f6b4..d289e97cfe8b2b781734454fee76ee8426ac3050 100644 (file)
@@ -3,9 +3,9 @@
  *      High performance SCSI / Fibre Channel SCSI Host device driver.
  *      For use with PCI chip/adapter(s):
  *          LSIFC9xx/LSI409xx Fibre Channel
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
index 8c98420640a5eccaccaecfc3bff15f219a4e8707..25bcfcf36f2e365bbdebf0afc06b261ab2be8a36 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *  linux/drivers/message/fusion/mptspi.c
- *      For use with LSI Logic PCI chip/adapter(s)
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI PCI chip/adapter(s)
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
@@ -90,9 +90,9 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *,
 
 static struct scsi_transport_template *mptspi_transport_template = NULL;
 
-static int     mptspiDoneCtx = -1;
-static int     mptspiTaskCtx = -1;
-static int     mptspiInternalCtx = -1; /* Used only for internal commands */
+static u8      mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8      mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8      mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
 
 /**
  *     mptspi_setTargetNegoParms  - Update the target negotiation parameters
@@ -107,7 +107,8 @@ static void
 mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
                            struct scsi_device *sdev)
 {
-       SpiCfgData *pspi_data = &hd->ioc->spi_data;
+       MPT_ADAPTER *ioc = hd->ioc;
+       SpiCfgData *pspi_data = &ioc->spi_data;
        int  id = (int) target->id;
        int  nvram;
        u8 width = MPT_NARROW;
@@ -138,9 +139,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
                                else {
                                        factor = MPT_ULTRA320;
                                        if (scsi_device_qas(sdev)) {
-                                               ddvprintk(hd->ioc,
-                                               printk(KERN_DEBUG "Enabling QAS due to "
-                                               "byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
+                                               ddvprintk(ioc,
+                                               printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to "
+                                               "byte56=%02x on id=%d!\n", ioc->name,
+                                               scsi_device_qas(sdev), id));
                                                noQas = 0;
                                        }
                                        if (sdev->type == TYPE_TAPE &&
@@ -227,8 +229,8 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
                /* Disable QAS in a mixed configuration case
                 */
 
-               ddvprintk(hd->ioc, printk(KERN_DEBUG
-                       "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
        }
 }
 
@@ -302,7 +304,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
 
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
-                       ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
+               ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
 
        mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
 
@@ -374,14 +376,15 @@ static int
 mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
 {
        int i, rc = 0;
+       MPT_ADAPTER *ioc = hd->ioc;
 
-       if (!hd->ioc->raid_data.pIocPg2)
+       if (!ioc->raid_data.pIocPg2)
                goto out;
 
-       if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes)
+       if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
                goto out;
-       for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
-               if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
+       for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+               if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
                        rc = 1;
                        goto out;
                }
@@ -394,17 +397,19 @@ mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
 static int mptspi_target_alloc(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
        VirtTarget              *vtarget;
+       MPT_ADAPTER *ioc;
 
        if (hd == NULL)
                return -ENODEV;
 
+       ioc = hd->ioc;
        vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
        if (!vtarget)
                return -ENOMEM;
 
-       vtarget->ioc_id = hd->ioc->id;
+       vtarget->ioc_id = ioc->id;
        vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
        vtarget->id = (u8)starget->id;
        vtarget->channel = (u8)starget->channel;
@@ -412,34 +417,34 @@ static int mptspi_target_alloc(struct scsi_target *starget)
        starget->hostdata = vtarget;
 
        if (starget->channel == 1) {
-               if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0)
+               if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0)
                        return 0;
                vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
                /* The real channel for this device is zero */
                vtarget->channel = 0;
                /* The actual physdisknum (for RAID passthrough) */
-               vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0,
+               vtarget->id = mptscsih_raid_id_to_num(ioc, 0,
                    starget->id);
        }
 
        if (starget->channel == 0 &&
            mptspi_is_raid(hd, starget->id)) {
                vtarget->raidVolume = 1;
-               ddvprintk(hd->ioc, printk(KERN_DEBUG
-                   "RAID Volume @ channel=%d id=%d\n", starget->channel,
+               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel,
                    starget->id));
        }
 
-       if (hd->ioc->spi_data.nvram &&
-           hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
-               u32 nvram = hd->ioc->spi_data.nvram[starget->id];
+       if (ioc->spi_data.nvram &&
+           ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
+               u32 nvram = ioc->spi_data.nvram[starget->id];
                spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
                spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
        } else {
-               spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor;
-               spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth;
+               spi_min_period(starget) = ioc->spi_data.minSyncFactor;
+               spi_max_width(starget) = ioc->spi_data.maxBusWidth;
        }
-       spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset;
+       spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
 
        spi_offset(starget) = 0;
        mptspi_write_width(starget, 0);
@@ -509,10 +514,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
                             struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
        struct _MPT_ADAPTER *ioc = hd->ioc;
-       struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0;
-       dma_addr_t pg0_dma;
+       struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
+       dma_addr_t spi_dev_pg0_dma;
        int size;
        struct _x_config_parms cfg;
        struct _CONFIG_PAGE_HEADER hdr;
@@ -530,9 +535,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
        size += 2048;
        */
 
-       pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL);
-       if (pg0 == NULL) {
-               starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
+       spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL);
+       if (spi_dev_pg0 == NULL) {
+               starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+                   "dma_alloc_coherent for parameters failed\n", ioc->name);
                return -EINVAL;
        }
 
@@ -546,22 +552,22 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
        memset(&cfg, 0, sizeof(cfg));
 
        cfg.cfghdr.hdr = &hdr;
-       cfg.physAddr = pg0_dma;
+       cfg.physAddr = spi_dev_pg0_dma;
        cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
        cfg.dir = 0;
        cfg.pageAddr = starget->id;
 
        if (mpt_config(ioc, &cfg)) {
-               starget_printk(KERN_ERR, starget, "mpt_config failed\n");
+               starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
                goto out_free;
        }
        err = 0;
-       memcpy(pass_pg0, pg0, size);
+       memcpy(pass_pg0, spi_dev_pg0, size);
 
-       mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters));
+       mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters));
 
  out_free:
-       dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma);
+       dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma);
        return err;
 }
 
@@ -588,11 +594,11 @@ static u32 mptspi_getRP(struct scsi_target *starget)
 static void mptspi_read_parameters(struct scsi_target *starget)
 {
        int nego;
-       struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0;
+       struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0;
 
-       mptspi_read_spi_device_pg0(starget, &pg0);
+       mptspi_read_spi_device_pg0(starget, &spi_dev_pg0);
 
-       nego = le32_to_cpu(pg0.NegotiatedParameters);
+       nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters);
 
        spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0;
        spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0;
@@ -612,12 +618,13 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
 {
        MpiRaidActionRequest_t  *pReq;
        MPT_FRAME_HDR           *mf;
+       MPT_ADAPTER *ioc = hd->ioc;
 
        /* Get and Populate a free Frame
         */
-       if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
-               ddvprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
-                                       hd->ioc->name));
+       if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+               ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+                                       ioc->name));
                return -EAGAIN;
        }
        pReq = (MpiRaidActionRequest_t *)mf;
@@ -638,8 +645,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
        mpt_add_sge((char *)&pReq->ActionDataSGE,
                MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
-       ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
-                       hd->ioc->name, pReq->Action, channel, id));
+       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
+                       ioc->name, pReq->Action, channel, id));
 
        hd->pLocal = NULL;
        hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
@@ -651,7 +658,7 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
        hd->cmdPtr = mf;
 
        add_timer(&hd->timer);
-       mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
+       mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
        wait_event(hd->scandv_waitq, hd->scandv_wait_done);
 
        if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
@@ -664,6 +671,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
                             struct scsi_device *sdev)
 {
        VirtTarget *vtarget = scsi_target(sdev)->hostdata;
+       MPT_ADAPTER *ioc = hd->ioc;
 
        /* no DV on RAID devices */
        if (sdev->channel == 0 &&
@@ -673,8 +681,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
        /* If this is a piece of a RAID, then quiesce first */
        if (sdev->channel == 1 &&
            mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
-               starget_printk(KERN_ERR, scsi_target(sdev),
-                              "Integrated RAID quiesce failed\n");
+               starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+                   "Integrated RAID quiesce failed\n", ioc->name);
                return;
        }
 
@@ -684,8 +692,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
 
        if (sdev->channel == 1 &&
            mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
-               starget_printk(KERN_ERR, scsi_target(sdev),
-                              "Integrated RAID resume failed\n");
+               starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+                   "Integrated RAID resume failed\n", ioc->name);
 
        mptspi_read_parameters(sdev->sdev_target);
        spi_display_xfer_agreement(sdev->sdev_target);
@@ -694,28 +702,29 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
 
 static int mptspi_slave_alloc(struct scsi_device *sdev)
 {
-       MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+       MPT_SCSI_HOST *hd = shost_priv(sdev->host);
        VirtTarget              *vtarget;
-       VirtDevice              *vdev;
+       VirtDevice              *vdevice;
        struct scsi_target      *starget;
+       MPT_ADAPTER *ioc = hd->ioc;
 
        if (sdev->channel == 1 &&
-               mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0)
+               mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0)
                        return -ENXIO;
 
-       vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
-       if (!vdev) {
+       vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+       if (!vdevice) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
-                               hd->ioc->name, sizeof(VirtDevice));
+                               ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
 
-       vdev->lun = sdev->lun;
-       sdev->hostdata = vdev;
+       vdevice->lun = sdev->lun;
+       sdev->hostdata = vdevice;
 
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
-       vdev->vtarget = vtarget;
+       vdevice->vtarget = vtarget;
        vtarget->num_luns++;
 
        if (sdev->channel == 1)
@@ -726,8 +735,7 @@ static int mptspi_slave_alloc(struct scsi_device *sdev)
 
 static int mptspi_slave_configure(struct scsi_device *sdev)
 {
-       struct _MPT_SCSI_HOST *hd =
-               (struct _MPT_SCSI_HOST *)sdev->host->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
        VirtTarget *vtarget = scsi_target(sdev)->hostdata;
        int ret;
 
@@ -755,24 +763,25 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
 static int
 mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
-       struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
-       VirtDevice      *vdev = SCpnt->device->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
+       VirtDevice      *vdevice = SCpnt->device->hostdata;
+       MPT_ADAPTER *ioc = hd->ioc;
 
-       if (!vdev || !vdev->vtarget) {
+       if (!vdevice || !vdevice->vtarget) {
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
                return 0;
        }
 
        if (SCpnt->device->channel == 1 &&
-               mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) {
+               mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) {
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
                return 0;
        }
 
        if (spi_dv_pending(scsi_target(SCpnt->device)))
-               ddvprintk(hd->ioc, scsi_print_command(SCpnt));
+               ddvprintk(ioc, scsi_print_command(SCpnt));
 
        return mptscsih_qcmd(SCpnt,done);
 }
@@ -829,7 +838,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
                               struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
        struct _MPT_ADAPTER *ioc = hd->ioc;
        struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
        dma_addr_t pg1_dma;
@@ -847,7 +856,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
 
        pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
        if (pg1 == NULL) {
-               starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
+               starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+                   "dma_alloc_coherent for parameters failed\n", ioc->name);
                return -EINVAL;
        }
 
@@ -876,7 +886,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
        mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
 
        if (mpt_config(ioc, &cfg)) {
-               starget_printk(KERN_ERR, starget, "mpt_config failed\n");
+               starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+                   "mpt_config failed\n", ioc->name);
                goto out_free;
        }
        err = 0;
@@ -1015,7 +1026,7 @@ static void mptspi_write_qas(struct scsi_target *starget, int qas)
 {
        struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
        VirtTarget *vtarget = starget->hostdata;
        u32 nego;
 
@@ -1067,15 +1078,16 @@ static void mpt_work_wrapper(struct work_struct *work)
        struct work_queue_wrapper *wqw =
                container_of(work, struct work_queue_wrapper, work);
        struct _MPT_SCSI_HOST *hd = wqw->hd;
-       struct Scsi_Host *shost = hd->ioc->sh;
+       MPT_ADAPTER *ioc = hd->ioc;
+       struct Scsi_Host *shost = ioc->sh;
        struct scsi_device *sdev;
        int disk = wqw->disk;
        struct _CONFIG_PAGE_IOC_3 *pg3;
 
        kfree(wqw);
 
-       mpt_findImVolumes(hd->ioc);
-       pg3 = hd->ioc->raid_data.pIocPg3;
+       mpt_findImVolumes(ioc);
+       pg3 = ioc->raid_data.pIocPg3;
        if (!pg3)
                return;
 
@@ -1092,24 +1104,25 @@ static void mpt_work_wrapper(struct work_struct *work)
                if(vtarget->id != disk)
                        continue;
 
-               starget_printk(KERN_INFO, vtarget->starget,
-                              "Integrated RAID requests DV of new device\n");
+               starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
+                   "Integrated RAID requests DV of new device\n", ioc->name);
                mptspi_dv_device(hd, sdev);
        }
-       shost_printk(KERN_INFO, shost,
-                    "Integrated RAID detects new device %d\n", disk);
-       scsi_scan_target(&hd->ioc->sh->shost_gendev, 1, disk, 0, 1);
+       shost_printk(KERN_INFO, shost, MYIOC_s_FMT
+           "Integrated RAID detects new device %d\n", ioc->name, disk);
+       scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1);
 }
 
 
 static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
 {
        struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
+       MPT_ADAPTER *ioc = hd->ioc;
 
        if (!wqw) {
-               shost_printk(KERN_ERR, hd->ioc->sh,
-                            "Failed to act on RAID event for physical disk %d\n",
-                          disk);
+               shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
+                   "Failed to act on RAID event for physical disk %d\n",
+                   ioc->name, disk);
                return;
        }
        INIT_WORK(&wqw->work, mpt_work_wrapper);
@@ -1123,7 +1136,7 @@ static int
 mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
        u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
-       struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
 
        if (hd && event ==  MPI_EVENT_INTEGRATED_RAID) {
                int reason
@@ -1190,6 +1203,8 @@ static struct spi_function_template mptspi_transport_functions = {
 static struct pci_device_id mptspi_pci_table[] = {
        { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
                PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030,
+               PCI_ANY_ID, PCI_ANY_ID },
        { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
                PCI_ANY_ID, PCI_ANY_ID },
        {0}     /* Terminating entry */
@@ -1210,11 +1225,12 @@ mptspi_dv_renegotiate_work(struct work_struct *work)
        struct scsi_target *starget;
        struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
        u32 nego;
+       MPT_ADAPTER *ioc = hd->ioc;
 
        kfree(wqw);
 
        if (hd->spi_pending) {
-               shost_for_each_device(sdev, hd->ioc->sh) {
+               shost_for_each_device(sdev, ioc->sh) {
                        if  (hd->spi_pending & (1 << sdev->id))
                                continue;
                        starget = scsi_target(sdev);
@@ -1225,7 +1241,7 @@ mptspi_dv_renegotiate_work(struct work_struct *work)
                        mptspi_write_spi_device_pg1(starget, &pg1);
                }
        } else {
-               shost_for_each_device(sdev, hd->ioc->sh)
+               shost_for_each_device(sdev, ioc->sh)
                        mptspi_dv_device(hd, sdev);
        }
 }
@@ -1250,7 +1266,7 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
 static int
 mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-       struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
        int rc;
 
        rc = mptscsih_ioc_reset(ioc, reset_phase);
@@ -1269,7 +1285,7 @@ static int
 mptspi_resume(struct pci_dev *pdev)
 {
        MPT_ADAPTER     *ioc = pci_get_drvdata(pdev);
-       struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+       struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
        int rc;
 
        rc = mptscsih_resume(pdev);
@@ -1416,7 +1432,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        if (numSGE < sh->sg_tablesize) {
                /* Reset this value */
-               dprintk(ioc, printk(MYIOC_s_INFO_FMT
+               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                  "Resetting sg_tablesize to %d from %d\n",
                  ioc->name, numSGE, sh->sg_tablesize));
                sh->sg_tablesize = numSGE;
@@ -1424,20 +1440,21 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
-       hd = (MPT_SCSI_HOST *) sh->hostdata;
+       hd = shost_priv(sh);
        hd->ioc = ioc;
 
        /* SCSI needs scsi_cmnd lookup table!
         * (with size equal to req_depth*PtrSz!)
         */
-       hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
-       if (!hd->ScsiLookup) {
+       ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+       if (!ioc->ScsiLookup) {
                error = -ENOMEM;
                goto out_mptspi_probe;
        }
+       spin_lock_init(&ioc->scsi_lookup_lock);
 
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
-                ioc->name, hd->ScsiLookup));
+                ioc->name, ioc->ScsiLookup));
 
        /* Clear the TM flags
         */
@@ -1477,13 +1494,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Some versions of the firmware don't support page 0; without
         * that we can't get the parameters */
-       if (hd->ioc->spi_data.sdp0length != 0)
+       if (ioc->spi_data.sdp0length != 0)
                sh->transportt = mptspi_transport_template;
 
        error = scsi_add_host (sh, &ioc->pcidev->dev);
        if(error) {
-               dprintk(ioc, printk(KERN_ERR MYNAM
-                 "scsi_add_host failed\n"));
+               dprintk(ioc, printk(MYIOC_s_ERR_FMT
+                 "scsi_add_host failed\n", ioc->name));
                goto out_mptspi_probe;
        }
 
index 6c0b2f0a51ab5c606c22ca5aec1a9e41a7468d3a..216948dd71a55dd1b7f7f72b5c3f2cfa5588f8ab 100644 (file)
@@ -517,7 +517,7 @@ static char *next_cmd(char **cmds)
  ****************************************************************************/
 
 static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+static struct device *tpacpi_hwmon;
 static struct input_dev *tpacpi_inputdev;
 
 
index 082a1cbc16c0ec822be2954a7b1ea3be485a09fa..acd5835ec889b2181011a28a60206421a4f55e7e 100644 (file)
@@ -171,7 +171,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
 
 /* Device model */
 static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+static struct device *tpacpi_hwmon;
 static struct platform_driver tpacpi_pdriver;
 static struct input_dev *tpacpi_inputdev;
 static int tpacpi_create_driver_attributes(struct device_driver *drv);
index 0713a8c71e54b2980d88127644e14cd9ed87f748..233d0f9b3c4b507b0e10e46bc0b936abd6081188 100644 (file)
@@ -96,30 +96,23 @@ static int sdio_bus_match(struct device *dev, struct device_driver *drv)
 }
 
 static int
-sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
-               int buf_size)
+sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct sdio_func *func = dev_to_sdio_func(dev);
-       int i = 0, length = 0;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                       buf, buf_size, &length,
+       if (add_uevent_var(env,
                        "SDIO_CLASS=%02X", func->class))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                       buf, buf_size, &length,
+       if (add_uevent_var(env, 
                        "SDIO_ID=%04X:%04X", func->vendor, func->device))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                       buf, buf_size, &length,
+       if (add_uevent_var(env,
                        "MODALIAS=sdio:c%02Xv%04Xd%04X",
                        func->class, func->vendor, func->device))
                return -ENOMEM;
 
-       envp[i] = NULL;
-
        return 0;
 }
 
index f30327bba6f68232132c1684b5bbd53495e71d40..254b194e762544ebfb7dfe539cabd2eaa00a715c 100644 (file)
@@ -26,7 +26,7 @@
  */
 #include <linux/hrtimer.h>
 #include <linux/delay.h>
-#include <linux/blkdev.h>
+#include <linux/bio.h>
 #include <linux/dma-mapping.h>
 #include <linux/crc7.h>
 #include <linux/crc-itu-t.h>
index fbec8cd55e38e78e020826d9df8cb6ed7879d6d9..8848e8ac705d9f22a35dce96d3fe788984cc52ed 100644 (file)
@@ -278,6 +278,14 @@ config SSFDC
          This enables read only access to SmartMedia formatted NAND
          flash. You can mount it with FAT file system.
 
+config MTD_OOPS
+       tristate "Log panic/oops to an MTD buffer"
+       depends on MTD
+       help
+         This enables panic and oops messages to be logged to a circular
+         buffer in a flash partition where it can be read back at some
+         later point.
+
 source "drivers/mtd/chips/Kconfig"
 
 source "drivers/mtd/maps/Kconfig"
index 6d958a4566ffdf041397b9c685a76b88587493d4..7f0b04b4caa7b50e11cbbc8fe8b584f77c66ade4 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_NFTL)            += nftl.o
 obj-$(CONFIG_INFTL)            += inftl.o
 obj-$(CONFIG_RFD_FTL)          += rfd_ftl.o
 obj-$(CONFIG_SSFDC)            += ssfdc.o
+obj-$(CONFIG_MTD_OOPS)         += mtdoops.o
 
 nftl-objs              := nftlcore.o nftlmount.o
 inftl-objs             := inftlcore.o inftlmount.o
index 2f19fa78d24a67236d03fb4fce8651dd1ef7f05b..3aa3dca56ae6ea8dd16cef96d222905a14516a76 100644 (file)
@@ -526,7 +526,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
        struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 
        /*
-        * Probing of multi-partition flash ships.
+        * Probing of multi-partition flash chips.
         *
         * To support multiple partitions when available, we simply arrange
         * for each of them to have their own flchip structure even if they
@@ -653,7 +653,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
  resettime:
        timeo = jiffies + HZ;
  retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
+       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
                /*
                 * OK. We have possibility for contension on the write/erase
                 * operations which are global to the real chip and not per
@@ -798,6 +798,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                if (mode == FL_READY && chip->oldstate == FL_READY)
                        return 0;
 
+       case FL_SHUTDOWN:
+               /* The machine is rebooting now,so no one can get chip anymore */
+               return -EIO;
        default:
        sleep:
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1166,28 +1169,34 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       unsigned long ofs;
+       unsigned long ofs, last_end = 0;
        int chipnum;
        int ret = 0;
 
        if (!map->virt || (from + len > mtd->size))
                return -EINVAL;
 
-       *mtdbuf = (void *)map->virt + from;
-       *retlen = 0;
-
        /* Now lock the chip(s) to POINT state */
 
        /* ofs: offset within the first chip that the first read should start */
        chipnum = (from >> cfi->chipshift);
        ofs = from - (chipnum << cfi->chipshift);
 
+       *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+       *retlen = 0;
+
        while (len) {
                unsigned long thislen;
 
                if (chipnum >= cfi->numchips)
                        break;
 
+               /* We cannot point across chips that are virtually disjoint */
+               if (!last_end)
+                       last_end = cfi->chips[chipnum].start;
+               else if (cfi->chips[chipnum].start != last_end)
+                       break;
+
                if ((len + ofs -1) >> cfi->chipshift)
                        thislen = (1<<cfi->chipshift) - ofs;
                else
@@ -1201,6 +1210,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
                len -= thislen;
 
                ofs = 0;
+               last_end += 1 << cfi->chipshift;
                chipnum++;
        }
        return 0;
@@ -1780,7 +1790,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        return ret;
 }
 
-int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
 {
        unsigned long ofs, len;
        int ret;
@@ -1930,7 +1940,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
               __FUNCTION__, ofs, len);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-               ofs, len, 0);
+               ofs, len, NULL);
 #endif
 
        ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
@@ -1940,7 +1950,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-               ofs, len, 0);
+               ofs, len, NULL);
 #endif
 
        return ret;
@@ -1954,7 +1964,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
               __FUNCTION__, ofs, len);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-               ofs, len, 0);
+               ofs, len, NULL);
 #endif
 
        ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
@@ -1964,7 +1974,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-               ofs, len, 0);
+               ofs, len, NULL);
 #endif
 
        return ret;
@@ -2255,7 +2265,7 @@ static void cfi_intelext_save_locks(struct mtd_info *mtd)
                        adr = region->offset + block * len;
 
                        status = cfi_varsize_frob(mtd,
-                                       do_getlockstatus_oneblock, adr, len, 0);
+                                       do_getlockstatus_oneblock, adr, len, NULL);
                        if (status)
                                set_bit(block, region->lockmap);
                        else
@@ -2402,10 +2412,10 @@ static int cfi_intelext_reset(struct mtd_info *mtd)
                   and switch to array mode so any bootloader in
                   flash is accessible for soft reboot. */
                spin_lock(chip->mutex);
-               ret = get_chip(map, chip, chip->start, FL_SYNCING);
+               ret = get_chip(map, chip, chip->start, FL_SHUTDOWN);
                if (!ret) {
                        map_write(map, CMD(0xff), chip->start);
-                       chip->state = FL_READY;
+                       chip->state = FL_SHUTDOWN;
                }
                spin_unlock(chip->mutex);
        }
index 1f6445840461a844b51b869473001171105ba8d3..389acc600f5e9a214939f041a794e8382ff4c1d3 100644 (file)
@@ -1609,7 +1609,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 }
 
 
-int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
 {
        unsigned long ofs, len;
        int ret;
index 58e561e87699026de75ff94b9960128adb1490ac..a67b23b87fc044ecad43173e7c76bc9b025e0910 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/init.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -70,6 +69,7 @@
 
 /* Fujitsu */
 #define MBM29F040C     0x00A4
+#define MBM29F800BA    0x2258
 #define MBM29LV650UE   0x22D7
 #define MBM29LV320TE   0x22F6
 #define MBM29LV320BE   0x22F9
 #define LH28F640BF     0x00b0
 
 /* ST - www.st.com */
+#define M29F800AB      0x0058
 #define M29W800DT      0x00D7
 #define M29W800DB      0x005B
 #define M29W160DT      0x22C4
@@ -644,6 +645,23 @@ static const struct amd_flash_info jedec_table[] = {
                .regions        = {
                        ERASEINFO(0x10000,8)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_FUJITSU,
+               .dev_id         = MBM29F800BA,
+               .name           = "Fujitsu MBM29F800BA",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x10000,15),
+               }
        }, {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV650UE,
@@ -1510,6 +1528,23 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x1000,256)
                }
 
+       }, {
+               .mfr_id         = MANUFACTURER_ST,
+               .dev_id         = M29F800AB,
+               .name           = "ST M29F800AB",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x10000,15),
+               }
        }, {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W800DT,
index ff642f8fbee759c2d2c9bc4892a53b67de08a8e9..811d56fd890f6da79135d854ae52fc8d581d167f 100644 (file)
@@ -60,21 +60,22 @@ config MTD_DATAFLASH
          Sometimes DataFlash chips are packaged inside MMC-format
          cards; at this writing, the MMC stack won't handle those.
 
-config MTD_DATAFLASH26
-       tristate "AT91RM9200 DataFlash AT26xxx"
-       depends on MTD && ARCH_AT91RM9200 && AT91_SPI
-       help
-         This enables access to the DataFlash chip (AT26xxx) on an
-         AT91RM9200-based board.
-         If you have such a board and such a DataFlash, say 'Y'.
-
 config MTD_M25P80
-       tristate "Support for M25 SPI Flash"
+       tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
        depends on SPI_MASTER && EXPERIMENTAL
        help
-         This enables access to ST M25P80 and similar SPI flash chips,
-         used for program and data storage.  Set up your spi devices
-         with the right board-specific platform data.
+         This enables access to most modern SPI flash chips, used for
+         program and data storage.   Series supported include Atmel AT26DF,
+         Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X.  Other chips
+         are supported as well.  See the driver source for the current list,
+         or to add other chips.
+
+         Note that the original DataFlash chips (AT45 series, not AT26DF),
+         need an entirely different driver.
+
+         Set up your spi devices with the right board-specific platform data,
+         if you want to specify device partitioning or to use a device which
+         doesn't support the JEDEC ID instruction.
 
 config MTD_SLRAM
        tristate "Uncached system RAM"
index 8ab568b3f533f2accbab0ab4cb78721758eff4cb..0f788d5c4bf8307b9b609891338bc4469b755534 100644 (file)
@@ -16,5 +16,4 @@ obj-$(CONFIG_MTD_MTDRAM)      += mtdram.o
 obj-$(CONFIG_MTD_LART)         += lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)    += block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)    += mtd_dataflash.o
-obj-$(CONFIG_MTD_DATAFLASH26)  += at91_dataflash26.o
 obj-$(CONFIG_MTD_M25P80)       += m25p80.o
diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c
deleted file mode 100644 (file)
index 64ce37f..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
- * This is a largely modified version of at91_dataflash.c that
- * supports AT26xxx dataflash chips. The original driver supports
- * AT45xxx chips.
- *
- * Note: This driver was only tested with an AT26F004. It should be
- * easy to make it work with other AT26xxx dataflash devices, though.
- *
- * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
- * original Copyright (C) SAN People (Pty) Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/mtd/mtd.h>
-
-#include <asm/arch/at91_spi.h>
-
-#define DATAFLASH_MAX_DEVICES  4       /* max number of dataflash devices */
-
-#define MANUFACTURER_ID_ATMEL          0x1F
-
-/* command codes */
-
-#define AT26_OP_READ_STATUS            0x05
-#define AT26_OP_READ_DEV_ID            0x9F
-#define AT26_OP_ERASE_PAGE_4K          0x20
-#define AT26_OP_READ_ARRAY_FAST                0x0B
-#define AT26_OP_SEQUENTIAL_WRITE       0xAF
-#define AT26_OP_WRITE_ENABLE           0x06
-#define AT26_OP_WRITE_DISABLE          0x04
-#define AT26_OP_SECTOR_PROTECT         0x36
-#define AT26_OP_SECTOR_UNPROTECT       0x39
-
-/* status register bits */
-
-#define AT26_STATUS_BUSY               0x01
-#define AT26_STATUS_WRITE_ENABLE       0x02
-
-struct dataflash_local
-{
-       int spi;                        /* SPI chip-select number */
-       unsigned int page_size;         /* number of bytes per page */
-};
-
-
-/* Detected DataFlash devices */
-static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
-static int nr_devices = 0;
-
-/* Allocate a single SPI transfer descriptor.  We're assuming that if multiple
-   SPI transfers occur at the same time, spi_access_bus() will serialize them.
-   If this is not valid, then either (i) each dataflash 'priv' structure
-   needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
-   another mechanism.   */
-static struct spi_transfer_list* spi_transfer_desc;
-
-/*
- * Perform a SPI transfer to access the DataFlash device.
- */
-static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
-               char* txnext, int txnext_len, char* rxnext, int rxnext_len)
-{
-       struct spi_transfer_list* list = spi_transfer_desc;
-
-       list->tx[0] = tx;       list->txlen[0] = tx_len;
-       list->rx[0] = rx;       list->rxlen[0] = rx_len;
-
-       list->tx[1] = txnext;   list->txlen[1] = txnext_len;
-       list->rx[1] = rxnext;   list->rxlen[1] = rxnext_len;
-
-       list->nr_transfers = nr;
-       /* Note: spi_transfer() always returns 0, there are no error checks */
-       return spi_transfer(list);
-}
-
-/*
- * Return the status of the DataFlash device.
- */
-static unsigned char at91_dataflash26_status(void)
-{
-       unsigned char command[2];
-
-       command[0] = AT26_OP_READ_STATUS;
-       command[1] = 0;
-
-       do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
-
-       return command[1];
-}
-
-/*
- * Poll the DataFlash device until it is READY.
- */
-static unsigned char at91_dataflash26_waitready(void)
-{
-       unsigned char status;
-
-       while (1) {
-               status = at91_dataflash26_status();
-               if (!(status & AT26_STATUS_BUSY))
-                       return status;
-       }
-}
-
-/*
- * Enable/disable write access
- */
- static void at91_dataflash26_write_enable(int enable)
-{
-       unsigned char cmd[2];
-
-       DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable);
-
-       if (enable)
-               cmd[0] = AT26_OP_WRITE_ENABLE;
-       else
-               cmd[0] = AT26_OP_WRITE_DISABLE;
-       cmd[1] = 0;
-
-       do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
-}
-
-/*
- * Protect/unprotect sector
- */
- static void at91_dataflash26_sector_protect(loff_t addr, int protect)
-{
-       unsigned char cmd[4];
-
-       DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n",
-              addr, protect);
-
-       if (protect)
-               cmd[0] = AT26_OP_SECTOR_PROTECT;
-       else
-               cmd[0] = AT26_OP_SECTOR_UNPROTECT;
-       cmd[1] = (addr & 0x00FF0000) >> 16;
-       cmd[2] = (addr & 0x0000FF00) >> 8;
-       cmd[3] = (addr & 0x000000FF);
-
-       do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
-}
-
-/*
- * Erase blocks of flash.
- */
-static int at91_dataflash26_erase(struct mtd_info *mtd,
-                                 struct erase_info *instr)
-{
-       struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
-       unsigned char cmd[4];
-
-       DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n",
-              instr->addr, instr->len);
-
-       /* Sanity checks */
-       if (priv->page_size != 4096)
-               return -EINVAL; /* Can't handle other sizes at the moment */
-
-       if (   ((instr->len % mtd->erasesize) != 0)
-           || ((instr->len % priv->page_size) != 0)
-           || ((instr->addr % priv->page_size) != 0)
-           || ((instr->addr + instr->len) > mtd->size))
-               return -EINVAL;
-
-       spi_access_bus(priv->spi);
-
-       while (instr->len > 0) {
-               at91_dataflash26_write_enable(1);
-               at91_dataflash26_sector_protect(instr->addr, 0);
-               at91_dataflash26_write_enable(1);
-               cmd[0] = AT26_OP_ERASE_PAGE_4K;
-               cmd[1] = (instr->addr & 0x00FF0000) >> 16;
-               cmd[2] = (instr->addr & 0x0000FF00) >> 8;
-               cmd[3] = (instr->addr & 0x000000FF);
-
-               DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x"
-                                       "0x%02x\n",
-                       cmd[0], cmd[1], cmd[2], cmd[3]);
-
-               do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
-               at91_dataflash26_waitready();
-
-               instr->addr += priv->page_size;  /* next page */
-               instr->len -= priv->page_size;
-       }
-
-       at91_dataflash26_write_enable(0);
-       spi_release_bus(priv->spi);
-
-       /* Inform MTD subsystem that erase is complete */
-       instr->state = MTD_ERASE_DONE;
-       if (instr->callback)
-               instr->callback(instr);
-
-       return 0;
-}
-
-/*
- * Read from the DataFlash device.
- *   from   : Start offset in flash device
- *   len    : Number of bytes to read
- *   retlen : Number of bytes actually read
- *   buf    : Buffer that will receive data
- */
-static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len,
-                                size_t *retlen, u_char *buf)
-{
-       struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
-       unsigned char cmd[5];
-
-       DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n",
-             from, from+len);
-
-       *retlen = 0;
-
-       /* Sanity checks */
-       if (!len)
-               return 0;
-       if (from + len > mtd->size)
-               return -EINVAL;
-
-       cmd[0] = AT26_OP_READ_ARRAY_FAST;
-       cmd[1] = (from & 0x00FF0000) >> 16;
-       cmd[2] = (from & 0x0000FF00) >> 8;
-       cmd[3] = (from & 0x000000FF);
-       /* cmd[4] is a "Don't care" byte  */
-
-       DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n",
-              cmd[0], cmd[1], cmd[2], cmd[3]);
-
-       spi_access_bus(priv->spi);
-       do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len);
-       spi_release_bus(priv->spi);
-
-       *retlen = len;
-       return 0;
-}
-
-/*
- * Write to the DataFlash device.
- *   to     : Start offset in flash device
- *   len    : Number of bytes to write
- *   retlen : Number of bytes actually written
- *   buf    : Buffer containing the data
- */
-static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len,
-                                 size_t *retlen, const u_char *buf)
-{
-       struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
-       unsigned int addr, buf_index = 0;
-       int ret = -EIO, sector, last_sector;
-       unsigned char status, cmd[5];
-
-       DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len);
-
-       *retlen = 0;
-
-       /* Sanity checks */
-       if (!len)
-               return 0;
-       if (to + len > mtd->size)
-               return -EINVAL;
-
-       spi_access_bus(priv->spi);
-
-       addr = to;
-       last_sector = -1;
-
-       while (buf_index < len) {
-               sector = addr / priv->page_size;
-               /* Write first byte if a new sector begins */
-               if (sector != last_sector) {
-                       at91_dataflash26_write_enable(1);
-                       at91_dataflash26_sector_protect(addr, 0);
-                       at91_dataflash26_write_enable(1);
-
-                       /* Program first byte of a new sector */
-                       cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
-                       cmd[1] = (addr & 0x00FF0000) >> 16;
-                       cmd[2] = (addr & 0x0000FF00) >> 8;
-                       cmd[3] = (addr & 0x000000FF);
-                       cmd[4] = buf[buf_index++];
-                       do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
-                       status = at91_dataflash26_waitready();
-                       addr++;
-                       /* On write errors, the chip resets the write enable
-                          flag. This also happens after the last byte of a
-                          sector is successfully programmed. */
-                       if (   ( !(status & AT26_STATUS_WRITE_ENABLE))
-                           && ((addr % priv->page_size) != 0) ) {
-                               DEBUG(MTD_DEBUG_LEVEL1,
-                                       "write error1: addr=0x%06x, "
-                                       "status=0x%02x\n", addr, status);
-                               goto write_err;
-                       }
-                       (*retlen)++;
-                       last_sector = sector;
-               }
-
-               /* Write subsequent bytes in the same sector */
-               cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
-               cmd[1] = buf[buf_index++];
-               do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
-               status = at91_dataflash26_waitready();
-               addr++;
-
-               if (   ( !(status & AT26_STATUS_WRITE_ENABLE))
-                   && ((addr % priv->page_size) != 0) ) {
-                       DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, "
-                               "status=0x%02x\n", addr, status);
-                       goto write_err;
-               }
-
-               (*retlen)++;
-       }
-
-       ret = 0;
-       at91_dataflash26_write_enable(0);
-write_err:
-       spi_release_bus(priv->spi);
-       return ret;
-}
-
-/*
- * Initialize and register DataFlash device with MTD subsystem.
- */
-static int __init add_dataflash(int channel, char *name, int nr_pages,
-                               int pagesize)
-{
-       struct mtd_info *device;
-       struct dataflash_local *priv;
-
-       if (nr_devices >= DATAFLASH_MAX_DEVICES) {
-               printk(KERN_ERR "at91_dataflash26: Too many devices "
-                               "detected\n");
-               return 0;
-       }
-
-       device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8,
-                        GFP_KERNEL);
-       if (!device)
-               return -ENOMEM;
-
-       device->name = (char *)&device[1];
-       sprintf(device->name, "%s.spi%d", name, channel);
-       device->size = nr_pages * pagesize;
-       device->erasesize = pagesize;
-       device->owner = THIS_MODULE;
-       device->type = MTD_DATAFLASH;
-       device->flags = MTD_CAP_NORFLASH;
-       device->erase = at91_dataflash26_erase;
-       device->read = at91_dataflash26_read;
-       device->write = at91_dataflash26_write;
-
-       priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local),
-               GFP_KERNEL);
-       if (!priv) {
-               kfree(device);
-               return -ENOMEM;
-       }
-
-       priv->spi = channel;
-       priv->page_size = pagesize;
-       device->priv = priv;
-
-       mtd_devices[nr_devices] = device;
-       nr_devices++;
-       printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n",
-              name, channel, device->size);
-
-       return add_mtd_device(device);
-}
-
-/*
- * Detect and initialize DataFlash device connected to specified SPI channel.
- *
- */
-
-struct dataflash26_types {
-       unsigned char id0;
-       unsigned char id1;
-       char *name;
-       int pagesize;
-       int nr_pages;
-};
-
-struct dataflash26_types df26_types[] = {
-       {
-               .id0 = 0x04,
-               .id1 = 0x00,
-               .name = "AT26F004",
-               .pagesize = 4096,
-               .nr_pages = 128,
-       },
-       {
-               .id0 = 0x45,
-               .id1 = 0x01,
-               .name = "AT26DF081A", /* Not tested ! */
-               .pagesize = 4096,
-               .nr_pages = 256,
-       },
-};
-
-static int __init at91_dataflash26_detect(int channel)
-{
-       unsigned char status, cmd[5];
-       int i;
-
-       spi_access_bus(channel);
-       status = at91_dataflash26_status();
-
-       if (status == 0 || status == 0xff) {
-               printk(KERN_ERR "at91_dataflash26_detect: status error %d\n",
-                       status);
-               spi_release_bus(channel);
-               return -ENODEV;
-       }
-
-       cmd[0] = AT26_OP_READ_DEV_ID;
-       do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
-       spi_release_bus(channel);
-
-       if (cmd[1] != MANUFACTURER_ID_ATMEL)
-               return -ENODEV;
-
-       for (i = 0; i < ARRAY_SIZE(df26_types); i++) {
-               if (   cmd[2] == df26_types[i].id0
-                   && cmd[3] == df26_types[i].id1)
-                       return add_dataflash(channel,
-                                               df26_types[i].name,
-                                               df26_types[i].nr_pages,
-                                               df26_types[i].pagesize);
-       }
-
-       printk(KERN_ERR "at91_dataflash26_detect: Unsupported device "
-                       "(0x%02x/0x%02x)\n", cmd[2], cmd[3]);
-       return -ENODEV;
-}
-
-static int __init at91_dataflash26_init(void)
-{
-       spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list),
-                                   GFP_KERNEL);
-       if (!spi_transfer_desc)
-               return -ENOMEM;
-
-       /* DataFlash (SPI chip select 0) */
-       at91_dataflash26_detect(0);
-
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-       /* DataFlash card (SPI chip select 3) */
-       at91_dataflash26_detect(3);
-#endif
-       return 0;
-}
-
-static void __exit at91_dataflash26_exit(void)
-{
-       int i;
-
-       for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
-               if (mtd_devices[i]) {
-                       del_mtd_device(mtd_devices[i]);
-                       kfree(mtd_devices[i]->priv);
-                       kfree(mtd_devices[i]);
-               }
-       }
-       nr_devices = 0;
-       kfree(spi_transfer_desc);
-}
-
-module_init(at91_dataflash26_init);
-module_exit(at91_dataflash26_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Hans J. Koch");
-MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200");
index 54aa7590764028c673a6b8e9dec1a06a5dbfbf8f..d8cc94ec4e504495421c5a3a558c02cdf8fff024 100644 (file)
@@ -81,9 +81,7 @@ static unsigned long __initdata doc_locations[] = {
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
 #elif defined(__PPC__)
        0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT_G)
-        0xff000000,
-##else
+#else
 #warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
        0xffffffff };
index 78c2511ae9e09e851ad74d8b33b5267e4cd4e826..98df5bcc02f3b42ea6f3aa5417e3437bd32e9d21 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * MTD SPI driver for ST M25Pxx flash chips
+ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips
  *
  * Author: Mike Lavender, mike@steroidmicros.com
  *
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
-#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 
-#include <asm/semaphore.h>
-
-
-/* NOTE: AT 25F and SST 25LF series are very similar,
- * but commands for sector erase and chip id differ...
- */
 
 #define FLASH_PAGESIZE         256
 
 /* Flash opcodes. */
-#define        OPCODE_WREN             6       /* Write enable */
-#define        OPCODE_RDSR             5       /* Read status register */
-#define        OPCODE_READ             3       /* Read data bytes */
-#define        OPCODE_PP               2       /* Page program */
-#define        OPCODE_SE               0xd8    /* Sector erase */
-#define        OPCODE_RES              0xab    /* Read Electronic Signature */
+#define        OPCODE_WREN             0x06    /* Write enable */
+#define        OPCODE_RDSR             0x05    /* Read status register */
+#define        OPCODE_READ             0x03    /* Read data bytes (low frequency) */
+#define        OPCODE_FAST_READ        0x0b    /* Read data bytes (high frequency) */
+#define        OPCODE_PP               0x02    /* Page program (up to 256 bytes) */
+#define        OPCODE_BE_4K            0x20    /* Erase 4KiB block */
+#define        OPCODE_BE_32K           0x52    /* Erase 32KiB block */
+#define        OPCODE_SE               0xd8    /* Sector erase (usually 64KiB) */
 #define        OPCODE_RDID             0x9f    /* Read JEDEC ID */
 
 /* Status Register bits. */
 #define        SR_WIP                  1       /* Write in progress */
 #define        SR_WEL                  2       /* Write enable latch */
+/* meaning of other SR_* bits may differ between vendors */
 #define        SR_BP0                  4       /* Block protect 0 */
 #define        SR_BP1                  8       /* Block protect 1 */
 #define        SR_BP2                  0x10    /* Block protect 2 */
 
 struct m25p {
        struct spi_device       *spi;
-       struct semaphore        lock;
+       struct mutex            lock;
        struct mtd_info         mtd;
-       unsigned                partitioned;
+       unsigned                partitioned:1;
+       u8                      erase_opcode;
        u8                      command[4];
 };
 
@@ -150,8 +150,9 @@ static int wait_till_ready(struct m25p *flash)
  */
 static int erase_sector(struct m25p *flash, u32 offset)
 {
-       DEBUG(MTD_DEBUG_LEVEL3, "%s: %s at 0x%08x\n", flash->spi->dev.bus_id,
-                       __FUNCTION__, offset);
+       DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n",
+                       flash->spi->dev.bus_id, __FUNCTION__,
+                       flash->mtd.erasesize / 1024, offset);
 
        /* Wait until finished previous write command. */
        if (wait_till_ready(flash))
@@ -161,7 +162,7 @@ static int erase_sector(struct m25p *flash, u32 offset)
        write_enable(flash);
 
        /* Set up command buffer. */
-       flash->command[0] = OPCODE_SE;
+       flash->command[0] = flash->erase_opcode;
        flash->command[1] = offset >> 16;
        flash->command[2] = offset >> 8;
        flash->command[3] = offset;
@@ -201,13 +202,17 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
        addr = instr->addr;
        len = instr->len;
 
-       down(&flash->lock);
+       mutex_lock(&flash->lock);
+
+       /* REVISIT in some cases we could speed up erasing large regions
+        * by using OPCODE_SE instead of OPCODE_BE_4K
+        */
 
        /* now erase those sectors */
        while (len) {
                if (erase_sector(flash, addr)) {
                        instr->state = MTD_ERASE_FAILED;
-                       up(&flash->lock);
+                       mutex_unlock(&flash->lock);
                        return -EIO;
                }
 
@@ -215,7 +220,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
                len -= mtd->erasesize;
        }
 
-       up(&flash->lock);
+       mutex_unlock(&flash->lock);
 
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
@@ -260,16 +265,19 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
        if (retlen)
                *retlen = 0;
 
-       down(&flash->lock);
+       mutex_lock(&flash->lock);
 
        /* Wait till previous write/erase is done. */
        if (wait_till_ready(flash)) {
                /* REVISIT status return?? */
-               up(&flash->lock);
+               mutex_unlock(&flash->lock);
                return 1;
        }
 
-       /* NOTE:  OPCODE_FAST_READ (if available) is faster... */
+       /* FIXME switch to OPCODE_FAST_READ.  It's required for higher
+        * clocks; and at this writing, every chip this driver handles
+        * supports that opcode.
+        */
 
        /* Set up the write data buffer. */
        flash->command[0] = OPCODE_READ;
@@ -281,7 +289,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 
        *retlen = m.actual_length - sizeof(flash->command);
 
-       up(&flash->lock);
+       mutex_unlock(&flash->lock);
 
        return 0;
 }
@@ -323,7 +331,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
        t[1].tx_buf = buf;
        spi_message_add_tail(&t[1], &m);
 
-       down(&flash->lock);
+       mutex_lock(&flash->lock);
 
        /* Wait until finished previous write command. */
        if (wait_till_ready(flash))
@@ -381,10 +389,10 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
                        if (retlen)
                                *retlen += m.actual_length
                                        - sizeof(flash->command);
-               }
-       }
+               }
+       }
 
-       up(&flash->lock);
+       mutex_unlock(&flash->lock);
 
        return 0;
 }
@@ -398,24 +406,118 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 struct flash_info {
        char            *name;
-       u8              id;
-       u16             jedec_id;
+
+       /* JEDEC id zero means "no ID" (most older chips); otherwise it has
+        * a high byte of zero plus three data bytes: the manufacturer id,
+        * then a two byte device id.
+        */
+       u32             jedec_id;
+
+       /* The size listed here is what works with OPCODE_SE, which isn't
+        * necessarily called a "sector" by the vendor.
+        */
        unsigned        sector_size;
-       unsigned        n_sectors;
+       u16             n_sectors;
+
+       u16             flags;
+#define        SECT_4K         0x01            /* OPCODE_BE_4K works uniformly */
 };
 
+
+/* NOTE: double check command sets and memory organization when you add
+ * more flash chips.  This current list focusses on newer chips, which
+ * have been converging on command sets which including JEDEC ID.
+ */
 static struct flash_info __devinitdata m25p_data [] = {
-       /* REVISIT: fill in JEDEC ids, for parts that have them */
-       { "m25p05", 0x05, 0x2010, 32 * 1024, 2 },
-       { "m25p10", 0x10, 0x2011, 32 * 1024, 4 },
-       { "m25p20", 0x11, 0x2012, 64 * 1024, 4 },
-       { "m25p40", 0x12, 0x2013, 64 * 1024, 8 },
-       { "m25p80", 0x13, 0x0000, 64 * 1024, 16 },
-       { "m25p16", 0x14, 0x2015, 64 * 1024, 32 },
-       { "m25p32", 0x15, 0x2016, 64 * 1024, 64 },
-       { "m25p64", 0x16, 0x2017, 64 * 1024, 128 },
+
+       /* Atmel -- some are (confusingly) marketed as "DataFlash" */
+       { "at25fs010",  0x1f6601, 32 * 1024, 4, SECT_4K, },
+       { "at25fs040",  0x1f6604, 64 * 1024, 8, SECT_4K, },
+
+       { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, },
+
+       { "at26f004",   0x1f0400, 64 * 1024, 8, SECT_4K, },
+       { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, },
+       { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, },
+       { "at26df321",  0x1f4701, 64 * 1024, 64, SECT_4K, },
+
+       /* Spansion -- single (large) sector size only, at least
+        * for the chips listed here (without boot sectors).
+        */
+       { "s25sl004a", 0x010212, 64 * 1024, 8, },
+       { "s25sl008a", 0x010213, 64 * 1024, 16, },
+       { "s25sl016a", 0x010214, 64 * 1024, 32, },
+       { "s25sl032a", 0x010215, 64 * 1024, 64, },
+       { "s25sl064a", 0x010216, 64 * 1024, 128, },
+
+       /* SST -- large erase sizes are "overlays", "sectors" are 4K */
+       { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, },
+       { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, },
+       { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, },
+       { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, },
+
+       /* ST Microelectronics -- newer production may have feature updates */
+       { "m25p05",  0x202010,  32 * 1024, 2, },
+       { "m25p10",  0x202011,  32 * 1024, 4, },
+       { "m25p20",  0x202012,  64 * 1024, 4, },
+       { "m25p40",  0x202013,  64 * 1024, 8, },
+       { "m25p80",         0,  64 * 1024, 16, },
+       { "m25p16",  0x202015,  64 * 1024, 32, },
+       { "m25p32",  0x202016,  64 * 1024, 64, },
+       { "m25p64",  0x202017,  64 * 1024, 128, },
+       { "m25p128", 0x202018, 256 * 1024, 64, },
+
+       { "m45pe80", 0x204014,  64 * 1024, 16, },
+       { "m45pe16", 0x204015,  64 * 1024, 32, },
+
+       { "m25pe80", 0x208014,  64 * 1024, 16, },
+       { "m25pe16", 0x208015,  64 * 1024, 32, SECT_4K, },
+
+       /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
+       { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, },
+       { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, },
+       { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, },
+       { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, },
+       { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, },
+       { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, },
+       { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, },
 };
 
+static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
+{
+       int                     tmp;
+       u8                      code = OPCODE_RDID;
+       u8                      id[3];
+       u32                     jedec;
+       struct flash_info       *info;
+
+       /* JEDEC also defines an optional "extended device information"
+        * string for after vendor-specific data, after the three bytes
+        * we use here.  Supporting some chips might require using it.
+        */
+       tmp = spi_write_then_read(spi, &code, 1, id, 3);
+       if (tmp < 0) {
+               DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n",
+                       spi->dev.bus_id, tmp);
+               return NULL;
+       }
+       jedec = id[0];
+       jedec = jedec << 8;
+       jedec |= id[1];
+       jedec = jedec << 8;
+       jedec |= id[2];
+
+       for (tmp = 0, info = m25p_data;
+                       tmp < ARRAY_SIZE(m25p_data);
+                       tmp++, info++) {
+               if (info->jedec_id == jedec)
+                       return info;
+       }
+       dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
+       return NULL;
+}
+
+
 /*
  * board specific setup should have ensured the SPI clock used here
  * matches what the READ command supports, at least until this driver
@@ -429,37 +531,51 @@ static int __devinit m25p_probe(struct spi_device *spi)
        unsigned                        i;
 
        /* Platform data helps sort out which chip type we have, as
-        * well as how this board partitions it.
+        * well as how this board partitions it.  If we don't have
+        * a chip ID, try the JEDEC id commands; they'll work for most
+        * newer chips, even if we don't recognize the particular chip.
         */
        data = spi->dev.platform_data;
-       if (!data || !data->type) {
-               /* FIXME some chips can identify themselves with RES
-                * or JEDEC get-id commands.  Try them ...
-                */
-               DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n",
-                               spi->dev.bus_id);
-               return -ENODEV;
-       }
+       if (data && data->type) {
+               for (i = 0, info = m25p_data;
+                               i < ARRAY_SIZE(m25p_data);
+                               i++, info++) {
+                       if (strcmp(data->type, info->name) == 0)
+                               break;
+               }
 
-       for (i = 0, info = m25p_data; i < ARRAY_SIZE(m25p_data); i++, info++) {
-               if (strcmp(data->type, info->name) == 0)
-                       break;
-       }
-       if (i == ARRAY_SIZE(m25p_data)) {
-               DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n",
-                               spi->dev.bus_id, data->type);
+               /* unrecognized chip? */
+               if (i == ARRAY_SIZE(m25p_data)) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
+                                       spi->dev.bus_id, data->type);
+                       info = NULL;
+
+               /* recognized; is that chip really what's there? */
+               } else if (info->jedec_id) {
+                       struct flash_info       *chip = jedec_probe(spi);
+
+                       if (!chip || chip != info) {
+                               dev_warn(&spi->dev, "found %s, expected %s\n",
+                                               chip ? chip->name : "UNKNOWN",
+                                               info->name);
+                               info = NULL;
+                       }
+               }
+       } else
+               info = jedec_probe(spi);
+
+       if (!info)
                return -ENODEV;
-       }
 
        flash = kzalloc(sizeof *flash, GFP_KERNEL);
        if (!flash)
                return -ENOMEM;
 
        flash->spi = spi;
-       init_MUTEX(&flash->lock);
+       mutex_init(&flash->lock);
        dev_set_drvdata(&spi->dev, flash);
 
-       if (data->name)
+       if (data && data->name)
                flash->mtd.name = data->name;
        else
                flash->mtd.name = spi->dev.bus_id;
@@ -468,17 +584,25 @@ static int __devinit m25p_probe(struct spi_device *spi)
        flash->mtd.writesize = 1;
        flash->mtd.flags = MTD_CAP_NORFLASH;
        flash->mtd.size = info->sector_size * info->n_sectors;
-       flash->mtd.erasesize = info->sector_size;
        flash->mtd.erase = m25p80_erase;
        flash->mtd.read = m25p80_read;
        flash->mtd.write = m25p80_write;
 
+       /* prefer "small sector" erase if possible */
+       if (info->flags & SECT_4K) {
+               flash->erase_opcode = OPCODE_BE_4K;
+               flash->mtd.erasesize = 4096;
+       } else {
+               flash->erase_opcode = OPCODE_SE;
+               flash->mtd.erasesize = info->sector_size;
+       }
+
        dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name,
                        flash->mtd.size / 1024);
 
        DEBUG(MTD_DEBUG_LEVEL2,
-               "mtd .name = %s, .size = 0x%.8x (%uM) "
-                       ".erasesize = 0x%.8x (%uK) .numeraseregions = %d\n",
+               "mtd .name = %s, .size = 0x%.8x (%uMiB) "
+                       ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
                flash->mtd.name,
                flash->mtd.size, flash->mtd.size / (1024*1024),
                flash->mtd.erasesize, flash->mtd.erasesize / 1024,
@@ -488,7 +612,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
                for (i = 0; i < flash->mtd.numeraseregions; i++)
                        DEBUG(MTD_DEBUG_LEVEL2,
                                "mtd.eraseregions[%d] = { .offset = 0x%.8x, "
-                               ".erasesize = 0x%.8x (%uK), "
+                               ".erasesize = 0x%.8x (%uKiB), "
                                ".numblocks = %d }\n",
                                i, flash->mtd.eraseregions[i].offset,
                                flash->mtd.eraseregions[i].erasesize,
@@ -516,14 +640,14 @@ static int __devinit m25p_probe(struct spi_device *spi)
                }
 
                if (nr_parts > 0) {
-                       for (i = 0; i < data->nr_parts; i++) {
+                       for (i = 0; i < nr_parts; i++) {
                                DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
                                        "{.name = %s, .offset = 0x%.8x, "
-                                               ".size = 0x%.8x (%uK) }\n",
-                                       i, data->parts[i].name,
-                                       data->parts[i].offset,
-                                       data->parts[i].size,
-                                       data->parts[i].size / 1024);
+                                               ".size = 0x%.8x (%uKiB) }\n",
+                                       i, parts[i].name,
+                                       parts[i].offset,
+                                       parts[i].size,
+                                       parts[i].size / 1024);
                        }
                        flash->partitioned = 1;
                        return add_mtd_partitions(&flash->mtd, parts, nr_parts);
@@ -560,6 +684,11 @@ static struct spi_driver m25p80_driver = {
        },
        .probe  = m25p_probe,
        .remove = __devexit_p(m25p_remove),
+
+       /* REVISIT: many of these chips have deep power-down modes, which
+        * should clearly be entered on suspend() to minimize power use.
+        * And also when they're otherwise idle...
+        */
 };
 
 
index a987e917f4e07e4c1bc534b574f66841d9c55cd3..a5ed6d232c357b16b7ffacfedd10d81a9915dad8 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 
@@ -89,7 +90,7 @@ struct dataflash {
        unsigned short          page_offset;    /* offset in flash address */
        unsigned int            page_size;      /* of bytes per page */
 
-       struct semaphore        lock;
+       struct mutex            lock;
        struct spi_device       *spi;
 
        struct mtd_info         mtd;
@@ -167,7 +168,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
        x.len = 4;
        spi_message_add_tail(&x, &msg);
 
-       down(&priv->lock);
+       mutex_lock(&priv->lock);
        while (instr->len > 0) {
                unsigned int    pageaddr;
                int             status;
@@ -210,7 +211,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
                        instr->len -= priv->page_size;
                }
        }
-       up(&priv->lock);
+       mutex_unlock(&priv->lock);
 
        /* Inform MTD subsystem that erase is complete */
        instr->state = MTD_ERASE_DONE;
@@ -266,7 +267,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
        x[1].len = len;
        spi_message_add_tail(&x[1], &msg);
 
-       down(&priv->lock);
+       mutex_lock(&priv->lock);
 
        /* Continuous read, max clock = f(car) which may be less than
         * the peak rate available.  Some chips support commands with
@@ -279,7 +280,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
        /* plus 4 "don't care" bytes */
 
        status = spi_sync(priv->spi, &msg);
-       up(&priv->lock);
+       mutex_unlock(&priv->lock);
 
        if (status >= 0) {
                *retlen = msg.actual_length - 8;
@@ -336,7 +337,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
        else
                writelen = len;
 
-       down(&priv->lock);
+       mutex_lock(&priv->lock);
        while (remaining > 0) {
                DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n",
                        pageaddr, offset, writelen);
@@ -441,7 +442,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
                else
                        writelen = remaining;
        }
-       up(&priv->lock);
+       mutex_unlock(&priv->lock);
 
        return status;
 }
@@ -463,7 +464,7 @@ add_dataflash(struct spi_device *spi, char *name,
        if (!priv)
                return -ENOMEM;
 
-       init_MUTEX(&priv->lock);
+       mutex_init(&priv->lock);
        priv->spi = spi;
        priv->page_size = pagesize;
        priv->page_offset = pageoffset;
index e8f686f7a357bd0e06a408dfb1b668d9a71c0317..7060a0895ce26fd95bf67f2cdc85418bfbc0078e 100644 (file)
@@ -30,8 +30,8 @@
  *
  * Notes:
  *     Due to what I assume is more buggy SROM, the 64M PMC551 I
- *     have available claims that all 4 of it's DRAM banks have 64M
- *     of ram configured (making a grand total of 256M onboard).
+ *     have available claims that all 4 of its DRAM banks have 64MiB
+ *     of ram configured (making a grand total of 256MiB onboard).
  *     This is slightly annoying since the BAR0 size reflects the
  *     aperture size, not the dram size, and the V370PDC supplies no
  *     other method for memory size discovery.  This problem is
@@ -70,7 +70,7 @@
  *      made the memory unusable, added a fix to code to touch up
  *      the DRAM some.
  *
- * Bugs/FIXME's:
+ * Bugs/FIXMEs:
  *     * MUST fix the init function to not spin on a register
  *     waiting for it to set .. this does not safely handle busted
  *     devices that never reset the register correctly which will
@@ -562,10 +562,10 @@ static u32 fixup_pmc551(struct pci_dev *dev)
        /*
         * Some screen fun
         */
-       printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at "
+       printk(KERN_DEBUG "pmc551: %d%sB (0x%x) of %sprefetchable memory at "
                "0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
                size >> 10 : size >> 20,
-               (size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size,
+               (size < 1024) ? "" : (size < 1048576) ? "Ki" : "Mi", size,
                ((dcmd & (0x1 << 3)) == 0) ? "non-" : "",
                (unsigned long long)pci_resource_start(dev, 0));
 
@@ -649,14 +649,10 @@ MODULE_DESCRIPTION(PMC551_VERSION);
  * Stuff these outside the ifdef so as to not bust compiled in driver support
  */
 static int msize = 0;
-#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
-static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE;
-#else
 static int asize = 0;
-#endif
 
 module_param(msize, int, 0);
-MODULE_PARM_DESC(msize, "memory size in Megabytes [1 - 1024]");
+MODULE_PARM_DESC(msize, "memory size in MiB [1 - 1024]");
 module_param(asize, int, 0);
 MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]");
 
@@ -799,8 +795,7 @@ static int __init init_pmc551(void)
                mtd->owner = THIS_MODULE;
 
                if (add_mtd_device(mtd)) {
-                       printk(KERN_NOTICE "pmc551: Failed to register new "
-                               "device\n");
+                       printk(KERN_NOTICE "pmc551: Failed to register new device\n");
                        pci_iounmap(PCI_Device, priv->start);
                        kfree(mtd->priv);
                        kfree(mtd);
@@ -811,13 +806,13 @@ static int __init init_pmc551(void)
                pci_dev_get(PCI_Device);
 
                printk(KERN_NOTICE "Registered pmc551 memory device.\n");
-               printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
+               printk(KERN_NOTICE "Mapped %dMiB of memory from 0x%p to 0x%p\n",
                        priv->asize >> 20,
                        priv->start, priv->start + priv->asize);
-               printk(KERN_NOTICE "Total memory is %d%c\n",
+               printk(KERN_NOTICE "Total memory is %d%sB\n",
                        (length < 1024) ? length :
                        (length < 1048576) ? length >> 10 : length >> 20,
-                       (length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M');
+                       (length < 1024) ? "" : (length < 1048576) ? "Ki" : "Mi");
                priv->nextpmc551 = pmc551list;
                pmc551list = mtd;
                found++;
@@ -850,7 +845,7 @@ static void __exit cleanup_pmc551(void)
                pmc551list = priv->nextpmc551;
 
                if (priv->start) {
-                       printk(KERN_DEBUG "pmc551: unmapping %dM starting at "
+                       printk(KERN_DEBUG "pmc551: unmapping %dMiB starting at "
                                "0x%p\n", priv->asize >> 20, priv->start);
                        pci_iounmap(priv->dev, priv->start);
                }
index ecac0e438f4907c620bb3bb289e46f8114e7a8ed..b8917beeb65099262da1e316282d663e43933e39 100644 (file)
@@ -580,14 +580,13 @@ int INFTL_mount(struct INFTLrecord *s)
        logical_block = block = BLOCK_NIL;
 
        /* Temporary buffer to store ANAC numbers. */
-       ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL);
+       ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL);
        if (!ANACtable) {
                printk(KERN_WARNING "INFTL: allocation of ANACtable "
                                "failed (%zd bytes)\n",
                                s->nb_blocks * sizeof(u8));
                return -ENOMEM;
        }
-       memset(ANACtable, 0, s->nb_blocks);
 
        /*
         * First pass is to explore each physical unit, and construct the
index 6cd132c751877463b79fd6b16469a4f43a3b8c82..2a2a125b0c760a795be1f77bb8889aa21c381a15 100644 (file)
@@ -163,20 +163,12 @@ config MTD_SBC_GXX
          More info at
          <http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
 
-config MTD_LUBBOCK
-       tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
-       depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
-       help
-         This provides a driver for the on-board flash of the Intel
-         'Lubbock' XScale evaluation board.
-
-config MTD_MAINSTONE
-       tristate "CFI Flash device mapped on Intel Mainstone XScale eval board"
-       depends on MACH_MAINSTONE && MTD_CFI_INTELEXT
+config MTD_PXA2XX
+       tristate "CFI Flash device mapped on Intel XScale PXA2xx based boards"
+       depends on (PXA25x || PXA27x) && MTD_CFI_INTELEXT
        select MTD_PARTITIONS
        help
-         This provides a driver for the on-board flash of the Intel
-         'Mainstone PXA27x evaluation board.
+         This provides a driver for the NOR flash attached to a PXA2xx chip.
 
 config MTD_OCTAGON
        tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
@@ -354,7 +346,7 @@ config MTD_CFI_FLAGADM
 
 config MTD_WALNUT
        tristate "Flash device mapped on IBM 405GP Walnut"
-       depends on MTD_JEDECPROBE && WALNUT
+       depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE
        help
          This enables access routines for the flash chips on the IBM 405GP
          Walnut board. If you have one of these boards and would like to
@@ -370,7 +362,7 @@ config MTD_EBONY
 
 config MTD_OCOTEA
        tristate "Flash devices mapped on IBM 440GX Ocotea"
-       depends on MTD_CFI && OCOTEA
+       depends on MTD_CFI && OCOTEA && !PPC_MERGE
        help
          This enables access routines for the flash chips on the IBM 440GX
          Ocotea board. If you have one of these boards and would like to
@@ -384,22 +376,6 @@ config MTD_REDWOOD
          Redwood board. If you have one of these boards and would like to
          use the flash chips on it, say 'Y'.
 
-config MTD_TQM834x
-       tristate "Flash device mapped on TQ Components TQM834x Boards"
-       depends on MTD_CFI && TQM834x
-       help
-         This enables access routines for the flash chips on the
-         TQ Components TQM834x boards. If you have one of these boards
-         and would like to use the flash chips on it, say 'Y'.
-
-config MTD_OCELOT
-       tristate "Momenco Ocelot boot flash device"
-       depends on MOMENCO_OCELOT
-       help
-         This enables access routines for the boot flash device and for the
-         NVRAM on the Momenco Ocelot board. If you have one of these boards
-         and would like access to either of these, say 'Y'.
-
 config MTD_SOLUTIONENGINE
        tristate "CFI Flash device mapped on Hitachi SolutionEngine"
        depends on SUPERH && MTD_CFI && MTD_REDBOOT_PARTS
@@ -605,6 +581,13 @@ config MTD_SHARP_SL
        help
          This enables access to the flash chip on the Sharp SL Series of PDAs.
 
+config MTD_INTEL_VR_NOR
+       tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0"
+       depends on PCI
+       help
+         Map driver for a NOR flash bank located on the Expansion Bus of the
+         Intel Vermilion Range chipset.
+
 config MTD_PLATRAM
        tristate "Map driver for platform device RAM (mtd-ram)"
        select MTD_RAM
index 970b189271a289370970dc966fb4b5cb50795c76..316382a1401be8dced078b5e2736322a08c637f8 100644 (file)
@@ -20,8 +20,7 @@ obj-$(CONFIG_MTD_ESB2ROM)     += esb2rom.o
 obj-$(CONFIG_MTD_ICHXROM)      += ichxrom.o
 obj-$(CONFIG_MTD_CK804XROM)    += ck804xrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
-obj-$(CONFIG_MTD_LUBBOCK)      += lubbock-flash.o
-obj-$(CONFIG_MTD_MAINSTONE)    += mainstone-flash.o
+obj-$(CONFIG_MTD_PXA2XX)       += pxa2xx-flash.o
 obj-$(CONFIG_MTD_MBX860)       += mbx860.o
 obj-$(CONFIG_MTD_CEIVA)                += ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)      += octagon-5066.o
@@ -43,7 +42,6 @@ obj-$(CONFIG_MTD_SUN_UFLASH)  += sun_uflash.o
 obj-$(CONFIG_MTD_VMAX)         += vmax301.o
 obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_DBOX2)                += dbox2-flash.o
-obj-$(CONFIG_MTD_OCELOT)       += ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)          += pci.o
 obj-$(CONFIG_MTD_ALCHEMY)       += alchemy-flash.o
@@ -70,4 +68,4 @@ obj-$(CONFIG_MTD_SHARP_SL)    += sharpsl-flash.o
 obj-$(CONFIG_MTD_PLATRAM)      += plat-ram.o
 obj-$(CONFIG_MTD_OMAP_NOR)     += omap_nor.o
 obj-$(CONFIG_MTD_MTX1)         += mtx-1_flash.o
-obj-$(CONFIG_MTD_TQM834x)      += tqm834x.o
+obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
index 84fbe0e8c47e8be01bb68d82217ea9357221f54f..82811bcb04369840e083d81e15f60dfcd7ec9fbb 100644 (file)
 #define BOARD_FLASH_WIDTH 2 /* 16-bits */
 #endif
 
-#ifdef CONFIG_MIPS_HYDROGEN3
-#define BOARD_MAP_NAME "Hydrogen3 Flash"
-#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#define USE_LOCAL_ACCESSORS /* why? */
-#endif
-
 #ifdef CONFIG_MIPS_BOSPORUS
 #define BOARD_MAP_NAME "Bosporus Flash"
 #define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
@@ -130,13 +123,6 @@ int __init alchemy_mtd_init(void)
 
        window_addr = 0x20000000 - BOARD_FLASH_SIZE;
        window_size = BOARD_FLASH_SIZE;
-#ifdef CONFIG_MIPS_MIRAGE_WHY
-       /* Boot ROM flash bank only; no user bank */
-       window_addr = 0x1C000000;
-       window_size = 0x04000000;
-       /* USERFS from 0x1C00 0000 to 0x1FC00000 */
-       alchemy_partitions[0].size = 0x03C00000;
-#endif
 
        /*
         * Static partition definition selection
diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c
new file mode 100644 (file)
index 0000000..1e7814a
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * drivers/mtd/maps/intel_vr_nor.c
+ *
+ * An MTD map driver for a NOR flash bank on the Expansion Bus of the Intel
+ * Vermilion Range chipset.
+ *
+ * The Vermilion Range Expansion Bus supports four chip selects, each of which
+ * has 64MiB of address space.  The 2nd BAR of the Expansion Bus PCI Device
+ * is a 256MiB memory region containing the address spaces for all four of the
+ * chip selects, with start addresses hardcoded on 64MiB boundaries.
+ *
+ * This map driver only supports NOR flash on chip select 0.  The buswidth
+ * (either 8 bits or 16 bits) is determined by reading the Expansion Bus Timing
+ * and Control Register for Chip Select 0 (EXP_TIMING_CS0).  This driver does
+ * not modify the value in the EXP_TIMING_CS0 register except to enable writing
+ * and disable boot acceleration.  The timing parameters in the register are
+ * assumed to have been properly initialized by the BIOS.  The reset default
+ * timing parameters are maximally conservative (slow), so access to the flash
+ * will be slower than it should be if the BIOS has not initialized the timing
+ * parameters.
+ *
+ * Author: Andy Lowe <alowe@mvista.com>
+ *
+ * 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/flashchip.h>
+
+#define DRV_NAME "vr_nor"
+
+struct vr_nor_mtd {
+       void __iomem *csr_base;
+       struct map_info map;
+       struct mtd_info *info;
+       int nr_parts;
+       struct pci_dev *dev;
+};
+
+/* Expansion Bus Configuration and Status Registers are in BAR 0 */
+#define EXP_CSR_MBAR 0
+/* Expansion Bus Memory Window is BAR 1 */
+#define EXP_WIN_MBAR 1
+/* Maximum address space for Chip Select 0 is 64MiB */
+#define CS0_SIZE 0x04000000
+/* Chip Select 0 is at offset 0 in the Memory Window */
+#define CS0_START 0x0
+/* Chip Select 0 Timing Register is at offset 0 in CSR */
+#define EXP_TIMING_CS0 0x00
+#define TIMING_CS_EN           (1 << 31)       /* Chip Select Enable */
+#define TIMING_BOOT_ACCEL_DIS  (1 <<  8)       /* Boot Acceleration Disable */
+#define TIMING_WR_EN           (1 <<  1)       /* Write Enable */
+#define TIMING_BYTE_EN         (1 <<  0)       /* 8-bit vs 16-bit bus */
+#define TIMING_MASK            0x3FFF0000
+
+static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
+{
+       if (p->nr_parts > 0) {
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+               del_mtd_partitions(p->info);
+#endif
+       } else
+               del_mtd_device(p->info);
+}
+
+static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
+{
+       int err = 0;
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+       struct mtd_partition *parts;
+       static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+       /* register the flash bank */
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+       /* partition the flash bank */
+       p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0);
+       if (p->nr_parts > 0)
+               err = add_mtd_partitions(p->info, parts, p->nr_parts);
+#endif
+       if (p->nr_parts <= 0)
+               err = add_mtd_device(p->info);
+
+       return err;
+}
+
+static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
+{
+       map_destroy(p->info);
+}
+
+static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
+{
+       static const char *probe_types[] =
+           { "cfi_probe", "jedec_probe", NULL };
+       const char **type;
+
+       for (type = probe_types; !p->info && *type; type++)
+               p->info = do_map_probe(*type, &p->map);
+       if (!p->info)
+               return -ENODEV;
+
+       p->info->owner = THIS_MODULE;
+
+       return 0;
+}
+
+static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
+{
+       unsigned int exp_timing_cs0;
+
+       /* write-protect the flash bank */
+       exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+       exp_timing_cs0 &= ~TIMING_WR_EN;
+       writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+       /* unmap the flash window */
+       iounmap(p->map.virt);
+
+       /* unmap the csr window */
+       iounmap(p->csr_base);
+}
+
+/*
+ * Initialize the map_info structure and map the flash.
+ * Returns 0 on success, nonzero otherwise.
+ */
+static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p)
+{
+       unsigned long csr_phys, csr_len;
+       unsigned long win_phys, win_len;
+       unsigned int exp_timing_cs0;
+       int err;
+
+       csr_phys = pci_resource_start(p->dev, EXP_CSR_MBAR);
+       csr_len = pci_resource_len(p->dev, EXP_CSR_MBAR);
+       win_phys = pci_resource_start(p->dev, EXP_WIN_MBAR);
+       win_len = pci_resource_len(p->dev, EXP_WIN_MBAR);
+
+       if (!csr_phys || !csr_len || !win_phys || !win_len)
+               return -ENODEV;
+
+       if (win_len < (CS0_START + CS0_SIZE))
+               return -ENXIO;
+
+       p->csr_base = ioremap_nocache(csr_phys, csr_len);
+       if (!p->csr_base)
+               return -ENOMEM;
+
+       exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+       if (!(exp_timing_cs0 & TIMING_CS_EN)) {
+               dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
+                      "is disabled.\n");
+               err = -ENODEV;
+               goto release;
+       }
+       if ((exp_timing_cs0 & TIMING_MASK) == TIMING_MASK) {
+               dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
+                      "is configured for maximally slow access times.\n");
+       }
+       p->map.name = DRV_NAME;
+       p->map.bankwidth = (exp_timing_cs0 & TIMING_BYTE_EN) ? 1 : 2;
+       p->map.phys = win_phys + CS0_START;
+       p->map.size = CS0_SIZE;
+       p->map.virt = ioremap_nocache(p->map.phys, p->map.size);
+       if (!p->map.virt) {
+               err = -ENOMEM;
+               goto release;
+       }
+       simple_map_init(&p->map);
+
+       /* Enable writes to flash bank */
+       exp_timing_cs0 |= TIMING_BOOT_ACCEL_DIS | TIMING_WR_EN;
+       writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+       return 0;
+
+      release:
+       iounmap(p->csr_base);
+       return err;
+}
+
+static struct pci_device_id vr_nor_pci_ids[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)},
+       {0,}
+};
+
+static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
+{
+       struct vr_nor_mtd *p = pci_get_drvdata(dev);
+
+       pci_set_drvdata(dev, NULL);
+       vr_nor_destroy_partitions(p);
+       vr_nor_destroy_mtd_setup(p);
+       vr_nor_destroy_maps(p);
+       kfree(p);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+}
+
+static int __devinit
+vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct vr_nor_mtd *p = NULL;
+       unsigned int exp_timing_cs0;
+       int err;
+
+       err = pci_enable_device(dev);
+       if (err)
+               goto out;
+
+       err = pci_request_regions(dev, DRV_NAME);
+       if (err)
+               goto disable_dev;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       err = -ENOMEM;
+       if (!p)
+               goto release;
+
+       p->dev = dev;
+
+       err = vr_nor_init_maps(p);
+       if (err)
+               goto release;
+
+       err = vr_nor_mtd_setup(p);
+       if (err)
+               goto destroy_maps;
+
+       err = vr_nor_init_partitions(p);
+       if (err)
+               goto destroy_mtd_setup;
+
+       pci_set_drvdata(dev, p);
+
+       return 0;
+
+      destroy_mtd_setup:
+       map_destroy(p->info);
+
+      destroy_maps:
+       /* write-protect the flash bank */
+       exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+       exp_timing_cs0 &= ~TIMING_WR_EN;
+       writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+       /* unmap the flash window */
+       iounmap(p->map.virt);
+
+       /* unmap the csr window */
+       iounmap(p->csr_base);
+
+      release:
+       kfree(p);
+       pci_release_regions(dev);
+
+      disable_dev:
+       pci_disable_device(dev);
+
+      out:
+       return err;
+}
+
+static struct pci_driver vr_nor_pci_driver = {
+       .name = DRV_NAME,
+       .probe = vr_nor_pci_probe,
+       .remove = __devexit_p(vr_nor_pci_remove),
+       .id_table = vr_nor_pci_ids,
+};
+
+static int __init vr_nor_mtd_init(void)
+{
+       return pci_register_driver(&vr_nor_pci_driver);
+}
+
+static void __exit vr_nor_mtd_exit(void)
+{
+       pci_unregister_driver(&vr_nor_pci_driver);
+}
+
+module_init(vr_nor_mtd_init);
+module_exit(vr_nor_mtd_exit);
+
+MODULE_AUTHOR("Andy Lowe");
+MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, vr_nor_pci_ids);
diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c
deleted file mode 100644 (file)
index e856068..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
- *
- * Map driver for the Lubbock developer platform.
- *
- * Author:     Nicolas Pitre
- * Copyright:  (C) 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/lubbock.h>
-#include <asm/cacheflush.h>
-
-#define ROM_ADDR       0x00000000
-#define FLASH_ADDR     0x04000000
-
-#define WINDOW_SIZE    64*1024*1024
-
-static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
-{
-       flush_ioremap_region(map->phys, map->cached, from, len);
-}
-
-static struct map_info lubbock_maps[2] = { {
-       .size =         WINDOW_SIZE,
-       .phys =         0x00000000,
-       .inval_cache =  lubbock_map_inval_cache,
-}, {
-       .size =         WINDOW_SIZE,
-       .phys =         0x04000000,
-       .inval_cache =  lubbock_map_inval_cache,
-} };
-
-static struct mtd_partition lubbock_partitions[] = {
-       {
-               .name =         "Bootloader",
-               .size =         0x00040000,
-               .offset =       0,
-               .mask_flags =   MTD_WRITEABLE  /* force read-only */
-       },{
-               .name =         "Kernel",
-               .size =         0x00100000,
-               .offset =       0x00040000,
-       },{
-               .name =         "Filesystem",
-               .size =         MTDPART_SIZ_FULL,
-               .offset =       0x00140000
-       }
-};
-
-static struct mtd_info *mymtds[2];
-static struct mtd_partition *parsed_parts[2];
-static int nr_parsed_parts[2];
-
-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
-static int __init init_lubbock(void)
-{
-       int flashboot = (LUB_CONF_SWITCHES & 1);
-       int ret = 0, i;
-
-       lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth =
-               (BOOT_DEF & 1) ? 2 : 4;
-
-       /* Compensate for the nROMBT switch which swaps the flash banks */
-       printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n",
-              flashboot?"Flash":"ROM", flashboot);
-
-       lubbock_maps[flashboot^1].name = "Lubbock Application Flash";
-       lubbock_maps[flashboot].name = "Lubbock Boot ROM";
-
-       for (i = 0; i < 2; i++) {
-               lubbock_maps[i].virt = ioremap(lubbock_maps[i].phys, WINDOW_SIZE);
-               if (!lubbock_maps[i].virt) {
-                       printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name);
-                       if (!ret)
-                               ret = -ENOMEM;
-                       continue;
-               }
-               lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE);
-               if (!lubbock_maps[i].cached)
-                       printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name);
-               simple_map_init(&lubbock_maps[i]);
-
-               printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
-                      lubbock_maps[i].name, lubbock_maps[i].phys,
-                      lubbock_maps[i].bankwidth * 8);
-
-               mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
-
-               if (!mymtds[i]) {
-                       iounmap((void *)lubbock_maps[i].virt);
-                       if (lubbock_maps[i].cached)
-                               iounmap(lubbock_maps[i].cached);
-                       if (!ret)
-                               ret = -EIO;
-                       continue;
-               }
-               mymtds[i]->owner = THIS_MODULE;
-
-               ret = parse_mtd_partitions(mymtds[i], probes,
-                                          &parsed_parts[i], 0);
-
-               if (ret > 0)
-                       nr_parsed_parts[i] = ret;
-       }
-
-       if (!mymtds[0] && !mymtds[1])
-               return ret;
-
-       for (i = 0; i < 2; i++) {
-               if (!mymtds[i]) {
-                       printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
-               } else if (nr_parsed_parts[i]) {
-                       add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]);
-               } else if (!i) {
-                       printk("Using static partitions on %s\n", lubbock_maps[i].name);
-                       add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions));
-               } else {
-                       printk("Registering %s as whole device\n", lubbock_maps[i].name);
-                       add_mtd_device(mymtds[i]);
-               }
-       }
-       return 0;
-}
-
-static void __exit cleanup_lubbock(void)
-{
-       int i;
-       for (i = 0; i < 2; i++) {
-               if (!mymtds[i])
-                       continue;
-
-               if (nr_parsed_parts[i] || !i)
-                       del_mtd_partitions(mymtds[i]);
-               else
-                       del_mtd_device(mymtds[i]);
-
-               map_destroy(mymtds[i]);
-               iounmap((void *)lubbock_maps[i].virt);
-               if (lubbock_maps[i].cached)
-                       iounmap(lubbock_maps[i].cached);
-
-               kfree(parsed_parts[i]);
-       }
-}
-
-module_init(init_lubbock);
-module_exit(cleanup_lubbock);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("MTD map driver for Intel Lubbock");
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c
deleted file mode 100644 (file)
index d76487d..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * $Id:  $
- *
- * Map driver for the Mainstone developer platform.
- *
- * Author:     Nicolas Pitre
- * Copyright:  (C) 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/mainstone.h>
-#include <asm/cacheflush.h>
-
-
-#define ROM_ADDR       0x00000000
-#define FLASH_ADDR     0x04000000
-
-#define WINDOW_SIZE    0x04000000
-
-static void mainstone_map_inval_cache(struct map_info *map, unsigned long from,
-                                     ssize_t len)
-{
-       flush_ioremap_region(map->phys, map->cached, from, len);
-}
-
-static struct map_info mainstone_maps[2] = { {
-       .size =         WINDOW_SIZE,
-       .phys =         PXA_CS0_PHYS,
-       .inval_cache =  mainstone_map_inval_cache,
-}, {
-       .size =         WINDOW_SIZE,
-       .phys =         PXA_CS1_PHYS,
-       .inval_cache =  mainstone_map_inval_cache,
-} };
-
-static struct mtd_partition mainstone_partitions[] = {
-       {
-               .name =         "Bootloader",
-               .size =         0x00040000,
-               .offset =       0,
-               .mask_flags =   MTD_WRITEABLE  /* force read-only */
-       },{
-               .name =         "Kernel",
-               .size =         0x00400000,
-               .offset =       0x00040000,
-       },{
-               .name =         "Filesystem",
-               .size =         MTDPART_SIZ_FULL,
-               .offset =       0x00440000
-       }
-};
-
-static struct mtd_info *mymtds[2];
-static struct mtd_partition *parsed_parts[2];
-static int nr_parsed_parts[2];
-
-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
-static int __init init_mainstone(void)
-{
-       int SW7 = 0;  /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
-       int ret = 0, i;
-
-       mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4;
-       mainstone_maps[1].bankwidth = 4;
-
-       /* Compensate for SW7 which swaps the flash banks */
-       mainstone_maps[SW7].name = "processor flash";
-       mainstone_maps[SW7 ^ 1].name = "main board flash";
-
-       printk(KERN_NOTICE "Mainstone configured to boot from %s\n",
-              mainstone_maps[0].name);
-
-       for (i = 0; i < 2; i++) {
-               mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys,
-                                                WINDOW_SIZE);
-               if (!mainstone_maps[i].virt) {
-                       printk(KERN_WARNING "Failed to ioremap %s\n",
-                              mainstone_maps[i].name);
-                       if (!ret)
-                               ret = -ENOMEM;
-                       continue;
-               }
-               mainstone_maps[i].cached =
-                       ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE);
-               if (!mainstone_maps[i].cached)
-                       printk(KERN_WARNING "Failed to ioremap cached %s\n",
-                              mainstone_maps[i].name);
-               simple_map_init(&mainstone_maps[i]);
-
-               printk(KERN_NOTICE
-                      "Probing %s at physical address 0x%08lx"
-                      " (%d-bit bankwidth)\n",
-                      mainstone_maps[i].name, mainstone_maps[i].phys,
-                      mainstone_maps[i].bankwidth * 8);
-
-               mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]);
-
-               if (!mymtds[i]) {
-                       iounmap((void *)mainstone_maps[i].virt);
-                       if (mainstone_maps[i].cached)
-                               iounmap(mainstone_maps[i].cached);
-                       if (!ret)
-                               ret = -EIO;
-                       continue;
-               }
-               mymtds[i]->owner = THIS_MODULE;
-
-               ret = parse_mtd_partitions(mymtds[i], probes,
-                                          &parsed_parts[i], 0);
-
-               if (ret > 0)
-                       nr_parsed_parts[i] = ret;
-       }
-
-       if (!mymtds[0] && !mymtds[1])
-               return ret;
-
-       for (i = 0; i < 2; i++) {
-               if (!mymtds[i]) {
-                       printk(KERN_WARNING "%s is absent. Skipping\n",
-                              mainstone_maps[i].name);
-               } else if (nr_parsed_parts[i]) {
-                       add_mtd_partitions(mymtds[i], parsed_parts[i],
-                                          nr_parsed_parts[i]);
-               } else if (!i) {
-                       printk("Using static partitions on %s\n",
-                              mainstone_maps[i].name);
-                       add_mtd_partitions(mymtds[i], mainstone_partitions,
-                                          ARRAY_SIZE(mainstone_partitions));
-               } else {
-                       printk("Registering %s as whole device\n",
-                              mainstone_maps[i].name);
-                       add_mtd_device(mymtds[i]);
-               }
-       }
-       return 0;
-}
-
-static void __exit cleanup_mainstone(void)
-{
-       int i;
-       for (i = 0; i < 2; i++) {
-               if (!mymtds[i])
-                       continue;
-
-               if (nr_parsed_parts[i] || !i)
-                       del_mtd_partitions(mymtds[i]);
-               else
-                       del_mtd_device(mymtds[i]);
-
-               map_destroy(mymtds[i]);
-               iounmap((void *)mainstone_maps[i].virt);
-               if (mainstone_maps[i].cached)
-                       iounmap(mainstone_maps[i].cached);
-               kfree(parsed_parts[i]);
-       }
-}
-
-module_init(init_mainstone);
-module_exit(cleanup_mainstone);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("MTD map driver for Intel Mainstone");
index 7b96cd02f82b37c08a4ed0faad6c07b189aa11a3..0c9b305a72e0de104e8ad53514f4c36ceebdd2ee 100644 (file)
@@ -158,68 +158,11 @@ static struct notifier_block nettel_notifier_block = {
        nettel_reboot_notifier, NULL, 0
 };
 
-/*
- *     Erase the configuration file system.
- *     Used to support the software reset button.
- */
-static void nettel_erasecallback(struct erase_info *done)
-{
-       wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
-       wake_up(wait_q);
-}
-
-static struct erase_info nettel_erase;
-
-int nettel_eraseconfig(void)
-{
-       struct mtd_info *mtd;
-       DECLARE_WAITQUEUE(wait, current);
-       wait_queue_head_t wait_q;
-       int ret;
-
-       init_waitqueue_head(&wait_q);
-       mtd = get_mtd_device(NULL, 2);
-       if (!IS_ERR(mtd)) {
-               nettel_erase.mtd = mtd;
-               nettel_erase.callback = nettel_erasecallback;
-               nettel_erase.callback = NULL;
-               nettel_erase.addr = 0;
-               nettel_erase.len = mtd->size;
-               nettel_erase.priv = (u_long) &wait_q;
-               nettel_erase.priv = 0;
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&wait_q, &wait);
-
-               ret = mtd->erase(mtd, &nettel_erase);
-               if (ret) {
-                       set_current_state(TASK_RUNNING);
-                       remove_wait_queue(&wait_q, &wait);
-                       put_mtd_device(mtd);
-                       return(ret);
-               }
-
-               schedule();  /* Wait for erase to finish. */
-               remove_wait_queue(&wait_q, &wait);
-
-               put_mtd_device(mtd);
-       }
-
-       return(0);
-}
-
-#else
-
-int nettel_eraseconfig(void)
-{
-       return(0);
-}
-
 #endif
 
 /****************************************************************************/
 
-int __init nettel_init(void)
+static int __init nettel_init(void)
 {
        volatile unsigned long *amdpar;
        unsigned long amdaddr, maxsize;
@@ -421,10 +364,6 @@ int __init nettel_init(void)
 
        intel_mtd->owner = THIS_MODULE;
 
-#ifndef CONFIG_BLK_DEV_INITRD
-       ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
-#endif
-
        num_intel_partitions = sizeof(nettel_intel_partitions) /
                sizeof(nettel_intel_partitions[0]);
 
@@ -477,7 +416,7 @@ out_unmap2:
 
 /****************************************************************************/
 
-void __exit nettel_cleanup(void)
+static void __exit nettel_cleanup(void)
 {
 #ifdef CONFIG_MTD_CFI_INTELEXT
        unregister_reboot_notifier(&nettel_notifier_block);
diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c
deleted file mode 100644 (file)
index 6977963..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $
- *
- * Flash on Momenco Ocelot
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#define OCELOT_PLD 0x2c000000
-#define FLASH_WINDOW_ADDR 0x2fc00000
-#define FLASH_WINDOW_SIZE 0x00080000
-#define FLASH_BUSWIDTH 1
-#define NVRAM_WINDOW_ADDR 0x2c800000
-#define NVRAM_WINDOW_SIZE 0x00007FF0
-#define NVRAM_BUSWIDTH 1
-
-static unsigned int cacheflush = 0;
-
-static struct mtd_info *flash_mtd;
-static struct mtd_info *nvram_mtd;
-
-static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
-        struct map_info *map = mtd->priv;
-       size_t done = 0;
-
-       /* If we use memcpy, it does word-wide writes. Even though we told the
-          GT64120A that it's an 8-bit wide region, word-wide writes don't work.
-          We end up just writing the first byte of the four to all four bytes.
-          So we have this loop instead */
-       *retlen = len;
-       while(len) {
-               __raw_writeb(*(unsigned char *) from, map->virt + to);
-               from++;
-               to++;
-               len--;
-       }
-}
-
-static struct mtd_partition *parsed_parts;
-
-struct map_info ocelot_flash_map = {
-       .name = "Ocelot boot flash",
-       .size = FLASH_WINDOW_SIZE,
-       .bankwidth = FLASH_BUSWIDTH,
-       .phys = FLASH_WINDOW_ADDR,
-};
-
-struct map_info ocelot_nvram_map = {
-       .name = "Ocelot NVRAM",
-       .size = NVRAM_WINDOW_SIZE,
-       .bankwidth = NVRAM_BUSWIDTH,
-       .phys = NVRAM_WINDOW_ADDR,
-};
-
-static const char *probes[] = { "RedBoot", NULL };
-
-static int __init init_ocelot_maps(void)
-{
-       void *pld;
-       int nr_parts;
-       unsigned char brd_status;
-
-               printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n",
-              FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR);
-
-       /* First check whether the flash jumper is present */
-       pld = ioremap(OCELOT_PLD, 0x10);
-       if (!pld) {
-               printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n");
-               return -EIO;
-       }
-       brd_status = readb(pld+4);
-       iounmap(pld);
-
-       /* Now ioremap the NVRAM space */
-       ocelot_nvram_map.virt = ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
-       if (!ocelot_nvram_map.virt) {
-               printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
-               return -EIO;
-       }
-
-       simple_map_init(&ocelot_nvram_map);
-
-       /* And do the RAM probe on it to get an MTD device */
-       nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
-       if (!nvram_mtd) {
-               printk("NVRAM probe failed\n");
-               goto fail_1;
-       }
-       nvram_mtd->owner = THIS_MODULE;
-       nvram_mtd->erasesize = 16;
-       /* Override the write() method */
-       nvram_mtd->write = ocelot_ram_write;
-
-       /* Now map the flash space */
-       ocelot_flash_map.virt = ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
-       if (!ocelot_flash_map.virt) {
-               printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
-               goto fail_2;
-       }
-       /* Now the cached version */
-       ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
-
-       simple_map_init(&ocelot_flash_map);
-
-       /* Only probe for flash if the write jumper is present */
-       if (brd_status & 0x40) {
-               flash_mtd = do_map_probe("jedec", &ocelot_flash_map);
-       } else {
-               printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n");
-       }
-       /* If that failed or the jumper's absent, pretend it's ROM */
-       if (!flash_mtd) {
-               flash_mtd = do_map_probe("map_rom", &ocelot_flash_map);
-               /* If we're treating it as ROM, set the erase size */
-               if (flash_mtd)
-                       flash_mtd->erasesize = 0x10000;
-       }
-       if (!flash_mtd)
-               goto fail3;
-
-       add_mtd_device(nvram_mtd);
-
-       flash_mtd->owner = THIS_MODULE;
-       nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
-
-       if (nr_parts > 0)
-               add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
-       else
-               add_mtd_device(flash_mtd);
-
-       return 0;
-
- fail3:
-       iounmap((void *)ocelot_flash_map.virt);
-       if (ocelot_flash_map.cached)
-                       iounmap((void *)ocelot_flash_map.cached);
- fail_2:
-       map_destroy(nvram_mtd);
- fail_1:
-       iounmap((void *)ocelot_nvram_map.virt);
-
-       return -ENXIO;
-}
-
-static void __exit cleanup_ocelot_maps(void)
-{
-       del_mtd_device(nvram_mtd);
-       map_destroy(nvram_mtd);
-       iounmap((void *)ocelot_nvram_map.virt);
-
-       if (parsed_parts)
-               del_mtd_partitions(flash_mtd);
-       else
-               del_mtd_device(flash_mtd);
-       map_destroy(flash_mtd);
-       iounmap((void *)ocelot_flash_map.virt);
-       if (ocelot_flash_map.cached)
-               iounmap((void *)ocelot_flash_map.cached);
-}
-
-module_init(init_ocelot_maps);
-module_exit(cleanup_ocelot_maps);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
-MODULE_DESCRIPTION("MTD map driver for Momenco Ocelot board");
index cf75a566442ed790e70ef062b755bf3581db7afc..aeed9ea79714ab56454840ee34d6eb5395e60f12 100644 (file)
@@ -232,7 +232,6 @@ static int __devinit of_flash_probe(struct of_device *dev,
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                goto err_out;
-       memset(info, 0, sizeof(*info));
 
        dev_set_drvdata(&dev->dev, info);
 
index 7e0377ec1c40df1255953176e9be4e842f04341c..02bde8c982ec68978de22a6a424286019189d4d9 100644 (file)
@@ -73,13 +73,16 @@ int __init init_msp_flash(void)
                return -ENXIO;
 
        printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
-       msp_flash = (struct mtd_info **)kmalloc(
-                       fcnt * sizeof(struct map_info *), GFP_KERNEL);
-       msp_parts = (struct mtd_partition **)kmalloc(
-                       fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
-       msp_maps = (struct map_info *)kmalloc(
-                       fcnt * sizeof(struct mtd_info), GFP_KERNEL);
-       memset(msp_maps, 0, fcnt * sizeof(struct mtd_info));
+
+       msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
+       msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+       msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
+       if (!msp_flash || !msp_parts || !msp_maps) {
+               kfree(msp_maps);
+               kfree(msp_parts);
+               kfree(msp_flash);
+               return -ENOMEM;
+       }
 
        /* loop over the flash devices, initializing each */
        for (i = 0; i < fcnt; i++) {
@@ -95,9 +98,8 @@ int __init init_msp_flash(void)
                        continue;
                }
 
-               msp_parts[i] = (struct mtd_partition *)kmalloc(
-                       pcnt * sizeof(struct mtd_partition), GFP_KERNEL);
-               memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition));
+               msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition),
+                                      GFP_KERNEL);
 
                /* now initialize the devices proper */
                flash_name[5] = '0' + i;
index 18049bceba8dc8f1b539abb51fbf964c632b8345..30de5c0c09a92f57695796107911e11cbfc5e5bd 100644 (file)
@@ -79,7 +79,6 @@ static int __init init_rrmap(void)
                rr_mtd->owner = THIS_MODULE;
 
                add_mtd_device(rr_mtd);
-               ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index);
 
                return 0;
        }
diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c
deleted file mode 100644 (file)
index fb78d87..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * drivers/mtd/maps/pq2fads.c
- *
- * Mapping for the flash SIMM on 8272ADS and PQ2FADS board
- *
- * Author: Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/ppcboot.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-
-/*
-  NOTE: bank width and interleave relative to the installed flash
-  should have been chosen within MTD_CFI_GEOMETRY options.
-  */
-#define PQ2FADS_BANK_WIDTH 4
-
-static struct mtd_partition pq2fads_partitions[] = {
-       {
-#ifdef CONFIG_ADS8272
-               .name           = "HRCW",
-               .size           = 0x40000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "User FS",
-               .size           = 0x5c0000,
-               .offset         = 0x40000,
-#else
-               .name           = "User FS",
-               .size           = 0x600000,
-               .offset         = 0,
-#endif
-       }, {
-               .name           = "uImage",
-               .size           = 0x100000,
-               .offset         = 0x600000,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "bootloader",
-               .size           = 0x40000,
-               .offset         = 0x700000,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "bootloader env",
-               .size           = 0x40000,
-               .offset         = 0x740000,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }
-};
-
-
-/* pointer to MPC885ADS board info data */
-extern unsigned char __res[];
-
-static int __init init_pq2fads_mtd(void)
-{
-       bd_t *bd = (bd_t *)__res;
-       physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL);
-
-       physmap_set_partitions(pq2fads_partitions,
-                               sizeof (pq2fads_partitions) /
-                               sizeof (pq2fads_partitions[0]));
-       return 0;
-}
-
-static void __exit cleanup_pq2fads_mtd(void)
-{
-}
-
-module_init(init_pq2fads_mtd);
-module_exit(cleanup_pq2fads_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards");
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
new file mode 100644 (file)
index 0000000..8211329
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Map driver for Intel XScale PXA2xx platforms.
+ *
+ * Author:     Nicolas Pitre
+ * Copyright:  (C) 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/cacheflush.h>
+
+#include <asm/mach/flash.h>
+
+static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,
+                                     ssize_t len)
+{
+       flush_ioremap_region(map->phys, map->cached, from, len);
+}
+
+struct pxa2xx_flash_info {
+       struct mtd_partition    *parts;
+       int                     nr_parts;
+       struct mtd_info         *mtd;
+       struct map_info         map;
+};
+
+
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+
+static int __init pxa2xx_flash_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct flash_platform_data *flash = pdev->dev.platform_data;
+       struct pxa2xx_flash_info *info;
+       struct mtd_partition *parts;
+       struct resource *res;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       info = kmalloc(sizeof(struct pxa2xx_flash_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       memset(info, 0, sizeof(struct pxa2xx_flash_info));
+       info->map.name = (char *) flash->name;
+       info->map.bankwidth = flash->width;
+       info->map.phys = res->start;
+       info->map.size = res->end - res->start + 1;
+       info->parts = flash->parts;
+       info->nr_parts = flash->nr_parts;
+
+       info->map.virt = ioremap(info->map.phys, info->map.size);
+       if (!info->map.virt) {
+               printk(KERN_WARNING "Failed to ioremap %s\n",
+                      info->map.name);
+               return -ENOMEM;
+       }
+       info->map.cached =
+               ioremap_cached(info->map.phys, info->map.size);
+       if (!info->map.cached)
+               printk(KERN_WARNING "Failed to ioremap cached %s\n",
+                      info->map.name);
+       info->map.inval_cache = pxa2xx_map_inval_cache;
+       simple_map_init(&info->map);
+
+       printk(KERN_NOTICE
+              "Probing %s at physical address 0x%08lx"
+              " (%d-bit bankwidth)\n",
+              info->map.name, (unsigned long)info->map.phys,
+              info->map.bankwidth * 8);
+
+       info->mtd = do_map_probe(flash->map_name, &info->map);
+
+       if (!info->mtd) {
+               iounmap((void *)info->map.virt);
+               if (info->map.cached)
+                       iounmap(info->map.cached);
+               return -EIO;
+       }
+       info->mtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       ret = parse_mtd_partitions(info->mtd, probes, &parts, 0);
+
+       if (ret > 0) {
+               info->nr_parts = ret;
+               info->parts = parts;
+       }
+#endif
+
+       if (info->nr_parts) {
+               add_mtd_partitions(info->mtd, info->parts,
+                                  info->nr_parts);
+       } else {
+               printk("Registering %s as whole device\n",
+                      info->map.name);
+               add_mtd_device(info->mtd);
+       }
+
+       dev_set_drvdata(dev, info);
+       return 0;
+}
+
+static int __exit pxa2xx_flash_remove(struct device *dev)
+{
+       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+       dev_set_drvdata(dev, NULL);
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (info->nr_parts)
+               del_mtd_partitions(info->mtd);
+       else
+#endif
+               del_mtd_device(info->mtd);
+
+       map_destroy(info->mtd);
+       iounmap(info->map.virt);
+       if (info->map.cached)
+               iounmap(info->map.cached);
+       kfree(info->parts);
+       kfree(info);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state)
+{
+       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (info->mtd && info->mtd->suspend)
+               ret = info->mtd->suspend(info->mtd);
+       return ret;
+}
+
+static int pxa2xx_flash_resume(struct device *dev)
+{
+       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+       if (info->mtd && info->mtd->resume)
+               info->mtd->resume(info->mtd);
+       return 0;
+}
+static void pxa2xx_flash_shutdown(struct device *dev)
+{
+       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+       if (info && info->mtd->suspend(info->mtd) == 0)
+               info->mtd->resume(info->mtd);
+}
+#else
+#define pxa2xx_flash_suspend NULL
+#define pxa2xx_flash_resume NULL
+#define pxa2xx_flash_shutdown NULL
+#endif
+
+static struct device_driver pxa2xx_flash_driver = {
+       .name           = "pxa2xx-flash",
+       .bus            = &platform_bus_type,
+       .probe          = pxa2xx_flash_probe,
+       .remove         = __exit_p(pxa2xx_flash_remove),
+       .suspend        = pxa2xx_flash_suspend,
+       .resume         = pxa2xx_flash_resume,
+       .shutdown       = pxa2xx_flash_shutdown,
+};
+
+static int __init init_pxa2xx_flash(void)
+{
+       return driver_register(&pxa2xx_flash_driver);
+}
+
+static void __exit cleanup_pxa2xx_flash(void)
+{
+       driver_unregister(&pxa2xx_flash_driver);
+}
+
+module_init(init_pxa2xx_flash);
+module_exit(cleanup_pxa2xx_flash);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx");
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c
deleted file mode 100644 (file)
index 9adc970..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * drivers/mtd/maps/tqm834x.c
- *
- * MTD mapping driver for TQM834x boards
- *
- * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <asm/ppcboot.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#define FLASH_BANK_MAX 2
-
-extern unsigned char __res[];
-
-/* trivial struct to describe partition information */
-struct mtd_part_def
-{
-       int nums;
-       unsigned char *type;
-       struct mtd_partition* mtd_part;
-};
-
-static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
-static struct map_info* map_banks[FLASH_BANK_MAX];
-static struct mtd_part_def part_banks[FLASH_BANK_MAX];
-
-static unsigned long num_banks;
-static unsigned long start_scan_addr;
-
-#ifdef CONFIG_MTD_PARTITIONS
-/*
- * The following defines the partition layout of TQM834x boards.
- *
- * See include/linux/mtd/partitions.h for definition of the
- * mtd_partition structure.
- *
- * Assume minimal initial size of 4 MiB per bank, will be updated
- * later in init_tqm834x_mtd() routine.
- */
-
-/* Partition definition for the first flash bank which is always present. */
-static struct mtd_partition tqm834x_partitions_bank1[] = {
-       {
-               .name   = "u-boot",             /* u-boot firmware      */
-               .offset = 0x00000000,
-               .size   = 0x00040000,           /* 256 KiB              */
-               /*mask_flags: MTD_WRITEABLE,     * force read-only      */
-       },
-       {
-               .name   = "env",                /* u-boot environment   */
-               .offset = 0x00040000,
-               .size   = 0x00020000,           /* 128 KiB              */
-               /*mask_flags: MTD_WRITEABLE,     * force read-only      */
-       },
-       {
-               .name   = "kernel",             /* linux kernel image   */
-               .offset = 0x00060000,
-               .size   = 0x00100000,           /* 1 MiB                */
-               /*mask_flags: MTD_WRITEABLE,     * force read-only      */
-       },
-       {
-               .name   = "initrd",             /* ramdisk image        */
-               .offset = 0x00160000,
-               .size   = 0x00200000,           /* 2 MiB                */
-       },
-       {
-               .name   = "user",               /* user data            */
-               .offset = 0x00360000,
-               .size   = 0x000a0000,           /* remaining space      */
-               /* NOTE: this parttion size is re-calcated in           */
-               /* init_tqm834x_mtd() to cover actual remaining space.  */
-       },
-};
-
-/* Partition definition for the second flash bank which may be present on some
- * TQM834x boards.
- */
-static struct mtd_partition tqm834x_partitions_bank2[] = {
-       {
-               .name   = "jffs2",              /* jffs2 filesystem     */
-               .offset = 0x00000000,
-               .size   = 0x00400000,           /* whole device         */
-               /* NOTE: this parttion size is re-calcated in           */
-               /* init_tqm834x_mtd() to cover actual device size.      */
-       },
-};
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
-static int __init init_tqm834x_mtd(void)
-{
-       int idx = 0, ret = 0;
-       unsigned long flash_addr, flash_size, mtd_size = 0;
-
-       /* pointer to TQM834x board info data */
-       bd_t *bd = (bd_t *)__res;
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-       int n;
-       char mtdid[4];
-       const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
-
-       flash_addr = bd->bi_flashstart;
-       flash_size = bd->bi_flashsize;
-
-       /* request maximum flash size address space */
-       start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
-       if (!start_scan_addr) {
-               printk("%s: Failed to ioremap address: 0x%lx\n",
-                      __FUNCTION__, flash_addr);
-               return -EIO;
-       }
-
-       for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
-               if (mtd_size >= flash_size)
-                       break;
-
-               pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx);
-
-               map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
-               if (map_banks[idx] == NULL) {
-                       ret = -ENOMEM;
-                       goto error_mem;
-               }
-               map_banks[idx]->name = kzalloc(16, GFP_KERNEL);
-               if (map_banks[idx]->name == NULL) {
-                       ret = -ENOMEM;
-                       goto error_mem;
-               }
-
-               sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
-               map_banks[idx]->size = flash_size;
-               map_banks[idx]->bankwidth = 4;
-
-               simple_map_init(map_banks[idx]);
-
-               map_banks[idx]->virt = (void __iomem *)
-                       (start_scan_addr + ((idx > 0) ?
-                       (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0));
-               map_banks[idx]->phys =
-                       flash_addr + ((idx > 0) ?
-                       (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
-
-               /* start to probe flash chips */
-               mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
-               if (mtd_banks[idx]) {
-                       mtd_banks[idx]->owner = THIS_MODULE;
-                       mtd_size += mtd_banks[idx]->size;
-                       num_banks++;
-                       pr_debug("%s: bank %ld, name: %s, size: %d bytes \n",
-                                __FUNCTION__, num_banks,
-                                mtd_banks[idx]->name, mtd_banks[idx]->size);
-               }
-       }
-
-       /* no supported flash chips found */
-       if (!num_banks) {
-               printk("TQM834x: No supported flash chips found!\n");
-               ret = -ENXIO;
-               goto error_mem;
-       }
-
-#ifdef CONFIG_MTD_PARTITIONS
-       /*
-        * Select static partition definitions
-        */
-       n = ARRAY_SIZE(tqm834x_partitions_bank1);
-       part_banks[0].mtd_part  = tqm834x_partitions_bank1;
-       part_banks[0].type      = "static image bank1";
-       part_banks[0].nums      = n;
-
-       /* update last partition size to cover actual remaining space */
-       tqm834x_partitions_bank1[n - 1].size =
-               mtd_banks[0]->size -
-               tqm834x_partitions_bank1[n - 1].offset;
-
-       /* check if we have second bank? */
-       if (num_banks == 2) {
-               n = ARRAY_SIZE(tqm834x_partitions_bank2);
-               part_banks[1].mtd_part  = tqm834x_partitions_bank2;
-               part_banks[1].type      = "static image bank2";
-               part_banks[1].nums      = n;
-
-               /* update last partition size to cover actual remaining space */
-               tqm834x_partitions_bank2[n - 1].size =
-                       mtd_banks[1]->size -
-                       tqm834x_partitions_bank2[n - 1].offset;
-       }
-
-       for(idx = 0; idx < num_banks ; idx++) {
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-               sprintf(mtdid, "%d", idx);
-               n = parse_mtd_partitions(mtd_banks[idx],
-                                        part_probes,
-                                        &part_banks[idx].mtd_part,
-                                        0);
-               pr_debug("%s: %d command line partitions on bank %s\n",
-                        __FUNCTION__, n, mtdid);
-               if (n > 0) {
-                       part_banks[idx].type = "command line";
-                       part_banks[idx].nums = n;
-               }
-#endif /* CONFIG_MTD_CMDLINE_PARTS */
-               if (part_banks[idx].nums == 0) {
-                       printk(KERN_NOTICE
-                              "TQM834x flash bank %d: no partition info "
-                              "available, registering whole device\n", idx);
-                       add_mtd_device(mtd_banks[idx]);
-               } else {
-                       printk(KERN_NOTICE
-                              "TQM834x flash bank %d: Using %s partition "
-                              "definition\n", idx, part_banks[idx].type);
-                       add_mtd_partitions(mtd_banks[idx],
-                                          part_banks[idx].mtd_part,
-                                          part_banks[idx].nums);
-               }
-       }
-#else  /* ! CONFIG_MTD_PARTITIONS */
-       printk(KERN_NOTICE "TQM834x flash: registering %d flash banks "
-                       "at once\n", num_banks);
-
-       for(idx = 0 ; idx < num_banks ; idx++)
-               add_mtd_device(mtd_banks[idx]);
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
-       return 0;
-error_mem:
-       for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
-               if (map_banks[idx] != NULL) {
-                       if (map_banks[idx]->name != NULL) {
-                               kfree(map_banks[idx]->name);
-                               map_banks[idx]->name = NULL;
-                       }
-                       kfree(map_banks[idx]);
-                       map_banks[idx] = NULL;
-               }
-       }
-
-       iounmap((void *)start_scan_addr);
-
-       return ret;
-}
-
-static void __exit cleanup_tqm834x_mtd(void)
-{
-       unsigned int idx = 0;
-       for(idx = 0 ; idx < num_banks ; idx++) {
-               /* destroy mtd_info previously allocated */
-               if (mtd_banks[idx]) {
-                       del_mtd_partitions(mtd_banks[idx]);
-                       map_destroy(mtd_banks[idx]);
-               }
-
-               /* release map_info not used anymore */
-               kfree(map_banks[idx]->name);
-               kfree(map_banks[idx]);
-       }
-
-       if (start_scan_addr) {
-               iounmap((void *)start_scan_addr);
-               start_scan_addr = 0;
-       }
-}
-
-module_init(init_tqm834x_mtd);
-module_exit(cleanup_tqm834x_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>");
-MODULE_DESCRIPTION("MTD map driver for TQM834x boards");
index ef89780eb9d6d213ba186348a2f73304b3479428..74d9d30edabdc49c04f42b435b53e851f159c3c5 100644 (file)
 #include <linux/kthread.h>
 #include <asm/uaccess.h>
 
-static LIST_HEAD(blktrans_majors);
+#include "mtdcore.h"
 
-extern struct mutex mtd_table_mutex;
-extern struct mtd_info *mtd_table[];
+static LIST_HEAD(blktrans_majors);
 
 struct mtd_blkcore_priv {
        struct task_struct *thread;
@@ -202,7 +201,7 @@ static int blktrans_ioctl(struct inode *inode, struct file *file,
        }
 }
 
-struct block_device_operations mtd_blktrans_ops = {
+static struct block_device_operations mtd_blktrans_ops = {
        .owner          = THIS_MODULE,
        .open           = blktrans_open,
        .release        = blktrans_release,
index d091b2430b480254c4cb2743a28def0e6805486a..22ed96c4b7bd75a7bedd4a9936f78f9094a7a95a 100644 (file)
@@ -136,7 +136,8 @@ static int mtd_close(struct inode *inode, struct file *file)
 
        DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
 
-       if (mtd->sync)
+       /* Only sync if opened RW */
+       if ((file->f_mode & 2) && mtd->sync)
                mtd->sync(mtd);
 
        put_mtd_device(mtd);
index 41844ea02462486a3e3b4eedb978debbc6f7eb62..d563dcd4b2644e2330398909e02f8e8146dbca9a 100644 (file)
@@ -178,7 +178,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
 
        /* Check alignment */
        if (mtd->writesize > 1) {
-               loff_t __to = to;
+               uint64_t __to = to;
                if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize))
                        return -EINVAL;
        }
@@ -726,6 +726,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
        concat->mtd.size = subdev[0]->size;
        concat->mtd.erasesize = subdev[0]->erasesize;
        concat->mtd.writesize = subdev[0]->writesize;
+       concat->mtd.subpage_sft = subdev[0]->subpage_sft;
        concat->mtd.oobsize = subdev[0]->oobsize;
        concat->mtd.oobavail = subdev[0]->oobavail;
        if (subdev[0]->writev)
index c153b64a830063f719e363917aacdd69fc7afff8..6c2645e2837191e57d539222c92d68b3debac806 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <linux/mtd/mtd.h>
 
+#include "mtdcore.h"
+
 /* These are exported solely for the purpose of mtd_blkdevs.c. You
    should not use them for _anything_ else */
 DEFINE_MUTEX(mtd_table_mutex);
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
new file mode 100644 (file)
index 0000000..a33251f
--- /dev/null
@@ -0,0 +1,11 @@
+/* linux/drivers/mtd/mtdcore.h
+ *
+ * Header file for driver private mtdcore exports
+ *
+ */
+
+/* These are exported solely for the purpose of mtd_blkdevs.c. You
+   should not use them for _anything_ else */
+
+extern struct mutex mtd_table_mutex;
+extern struct mtd_info *mtd_table[MAX_MTD_DEVICES];
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
new file mode 100644 (file)
index 0000000..f8af627
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * MTD Oops/Panic logger
+ *
+ * Copyright (C) 2007 Nokia Corporation. All rights reserved.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mtd/mtd.h>
+
+#define OOPS_PAGE_SIZE 4096
+
+static struct mtdoops_context {
+       int mtd_index;
+       struct work_struct work;
+       struct mtd_info *mtd;
+       int oops_pages;
+       int nextpage;
+       int nextcount;
+
+       void *oops_buf;
+       int ready;
+       int writecount;
+} oops_cxt;
+
+static void mtdoops_erase_callback(struct erase_info *done)
+{
+       wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+       wake_up(wait_q);
+}
+
+static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
+{
+       struct erase_info erase;
+       DECLARE_WAITQUEUE(wait, current);
+       wait_queue_head_t wait_q;
+       int ret;
+
+       init_waitqueue_head(&wait_q);
+       erase.mtd = mtd;
+       erase.callback = mtdoops_erase_callback;
+       erase.addr = offset;
+       if (mtd->erasesize < OOPS_PAGE_SIZE)
+               erase.len = OOPS_PAGE_SIZE;
+       else
+               erase.len = mtd->erasesize;
+       erase.priv = (u_long)&wait_q;
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&wait_q, &wait);
+
+       ret = mtd->erase(mtd, &erase);
+       if (ret) {
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&wait_q, &wait);
+               printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] "
+                                    "on \"%s\" failed\n",
+                       erase.addr, erase.len, mtd->name);
+               return ret;
+       }
+
+       schedule();  /* Wait for erase to finish. */
+       remove_wait_queue(&wait_q, &wait);
+
+       return 0;
+}
+
+static int mtdoops_inc_counter(struct mtdoops_context *cxt)
+{
+       struct mtd_info *mtd = cxt->mtd;
+       size_t retlen;
+       u32 count;
+       int ret;
+
+       cxt->nextpage++;
+       if (cxt->nextpage > cxt->oops_pages)
+               cxt->nextpage = 0;
+       cxt->nextcount++;
+       if (cxt->nextcount == 0xffffffff)
+               cxt->nextcount = 0;
+
+       ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
+                       &retlen, (u_char *) &count);
+       if ((retlen != 4) || (ret < 0)) {
+               printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
+                               ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE,
+                               retlen, ret);
+               return 1;
+       }
+
+       /* See if we need to erase the next block */
+       if (count != 0xffffffff)
+               return 1;
+
+       printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n",
+                       cxt->nextpage, cxt->nextcount);
+       cxt->ready = 1;
+       return 0;
+}
+
+static void mtdoops_prepare(struct mtdoops_context *cxt)
+{
+       struct mtd_info *mtd = cxt->mtd;
+       int i = 0, j, ret, mod;
+
+       /* We were unregistered */
+       if (!mtd)
+               return;
+
+       mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize;
+       if (mod != 0) {
+               cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE);
+               if (cxt->nextpage > cxt->oops_pages)
+                       cxt->nextpage = 0;
+       }
+
+       while (mtd->block_isbad &&
+                       mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) {
+badblock:
+               printk(KERN_WARNING "mtdoops: Bad block at %08x\n",
+                               cxt->nextpage * OOPS_PAGE_SIZE);
+               i++;
+               cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE);
+               if (cxt->nextpage > cxt->oops_pages)
+                       cxt->nextpage = 0;
+               if (i == (cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE))) {
+                       printk(KERN_ERR "mtdoops: All blocks bad!\n");
+                       return;
+               }
+       }
+
+       for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
+               ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+
+       if (ret < 0) {
+               if (mtd->block_markbad)
+                       mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+               goto badblock;
+       }
+
+       printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
+
+       cxt->ready = 1;
+}
+
+static void mtdoops_workfunc(struct work_struct *work)
+{
+       struct mtdoops_context *cxt =
+                       container_of(work, struct mtdoops_context, work);
+
+       mtdoops_prepare(cxt);
+}
+
+static int find_next_position(struct mtdoops_context *cxt)
+{
+       struct mtd_info *mtd = cxt->mtd;
+       int page, maxpos = 0;
+       u32 count, maxcount = 0xffffffff;
+       size_t retlen;
+
+       for (page = 0; page < cxt->oops_pages; page++) {
+               mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+               if (count == 0xffffffff)
+                       continue;
+               if (maxcount == 0xffffffff) {
+                       maxcount = count;
+                       maxpos = page;
+               } else if ((count < 0x40000000) && (maxcount > 0xc0000000)) {
+                       maxcount = count;
+                       maxpos = page;
+               } else if ((count > maxcount) && (count < 0xc0000000)) {
+                       maxcount = count;
+                       maxpos = page;
+               } else if ((count > maxcount) && (count > 0xc0000000)
+                                       && (maxcount > 0x80000000)) {
+                       maxcount = count;
+                       maxpos = page;
+               }
+       }
+       if (maxcount == 0xffffffff) {
+               cxt->nextpage = 0;
+               cxt->nextcount = 1;
+               cxt->ready = 1;
+               printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n",
+                               cxt->nextpage, cxt->nextcount);
+               return 0;
+       }
+
+       cxt->nextpage = maxpos;
+       cxt->nextcount = maxcount;
+
+       return mtdoops_inc_counter(cxt);
+}
+
+
+static void mtdoops_notify_add(struct mtd_info *mtd)
+{
+       struct mtdoops_context *cxt = &oops_cxt;
+       int ret;
+
+       if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
+               return;
+
+       if (mtd->size < (mtd->erasesize * 2)) {
+               printk(KERN_ERR "MTD partition %d not big enough for mtdoops\n",
+                               mtd->index);
+               return;
+       }
+
+       cxt->mtd = mtd;
+       cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
+
+       ret = find_next_position(cxt);
+       if (ret == 1)
+               mtdoops_prepare(cxt);
+
+       printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index);
+}
+
+static void mtdoops_notify_remove(struct mtd_info *mtd)
+{
+       struct mtdoops_context *cxt = &oops_cxt;
+
+       if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
+               return;
+
+       cxt->mtd = NULL;
+       flush_scheduled_work();
+}
+
+static void mtdoops_console_sync(void)
+{
+       struct mtdoops_context *cxt = &oops_cxt;
+       struct mtd_info *mtd = cxt->mtd;
+       size_t retlen;
+       int ret;
+
+       if (!cxt->ready || !mtd)
+               return;
+
+       if (cxt->writecount == 0)
+               return;
+
+       if (cxt->writecount < OOPS_PAGE_SIZE)
+               memset(cxt->oops_buf + cxt->writecount, 0xff,
+                                       OOPS_PAGE_SIZE - cxt->writecount);
+
+       ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+                                       OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+       cxt->ready = 0;
+       cxt->writecount = 0;
+
+       if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
+               printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
+                       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+
+       ret = mtdoops_inc_counter(cxt);
+       if (ret == 1)
+               schedule_work(&cxt->work);
+}
+
+static void
+mtdoops_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct mtdoops_context *cxt = co->data;
+       struct mtd_info *mtd = cxt->mtd;
+       int i;
+
+       if (!oops_in_progress) {
+               mtdoops_console_sync();
+               return;
+       }
+
+       if (!cxt->ready || !mtd)
+               return;
+
+       if (cxt->writecount == 0) {
+               u32 *stamp = cxt->oops_buf;
+               *stamp = cxt->nextcount;
+               cxt->writecount = 4;
+       }
+
+       if ((count + cxt->writecount) > OOPS_PAGE_SIZE)
+               count = OOPS_PAGE_SIZE - cxt->writecount;
+
+       for (i = 0; i < count; i++, s++)
+               *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s;
+
+       cxt->writecount = cxt->writecount + count;
+}
+
+static int __init mtdoops_console_setup(struct console *co, char *options)
+{
+       struct mtdoops_context *cxt = co->data;
+
+       if (cxt->mtd_index != -1)
+               return -EBUSY;
+       if (co->index == -1)
+               return -EINVAL;
+
+       cxt->mtd_index = co->index;
+       return 0;
+}
+
+static struct mtd_notifier mtdoops_notifier = {
+       .add    = mtdoops_notify_add,
+       .remove = mtdoops_notify_remove,
+};
+
+static struct console mtdoops_console = {
+       .name           = "ttyMTD",
+       .write          = mtdoops_console_write,
+       .setup          = mtdoops_console_setup,
+       .unblank        = mtdoops_console_sync,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &oops_cxt,
+};
+
+static int __init mtdoops_console_init(void)
+{
+       struct mtdoops_context *cxt = &oops_cxt;
+
+       cxt->mtd_index = -1;
+       cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
+
+       if (!cxt->oops_buf) {
+               printk(KERN_ERR "Failed to allocate oops buffer workspace\n");
+               return -ENOMEM;
+       }
+
+       INIT_WORK(&cxt->work, mtdoops_workfunc);
+
+       register_console(&mtdoops_console);
+       register_mtd_user(&mtdoops_notifier);
+       return 0;
+}
+
+static void __exit mtdoops_console_exit(void)
+{
+       struct mtdoops_context *cxt = &oops_cxt;
+
+       unregister_mtd_user(&mtdoops_notifier);
+       unregister_console(&mtdoops_console);
+       vfree(cxt->oops_buf);
+}
+
+
+subsys_initcall(mtdoops_console_init);
+module_exit(mtdoops_console_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("MTD Oops/Panic console logger/driver");
index f1d60b6f048e6f08aa855e19fed1337a292cfe79..8f9c3baeb38e77ec82a17cc10a80a9e036adba35 100644 (file)
@@ -91,6 +91,25 @@ config MTD_NAND_AU1550
          This enables the driver for the NAND flash controller on the
          AMD/Alchemy 1550 SOC.
 
+config MTD_NAND_BF5XX
+       tristate "Blackfin on-chip NAND Flash Controller driver"
+       depends on BF54x && MTD_NAND
+       help
+         This enables the Blackfin on-chip NAND flash controller
+
+         No board specific support is done by this driver, each board
+         must advertise a platform_device for the driver to attach.
+
+         This driver can also be built as a module. If so, the module
+         will be called bf5xx-nand.
+
+config MTD_NAND_BF5XX_HWECC
+       bool "BF5XX NAND Hardware ECC"
+       depends on MTD_NAND_BF5XX
+       help
+         Enable the use of the BF5XX's internal ECC generator when
+         using NAND.
+
 config MTD_NAND_RTC_FROM4
        tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
        depends on SH_SOLUTION_ENGINE
@@ -134,10 +153,10 @@ config MTD_NAND_S3C2410_HWECC
 
 config MTD_NAND_NDFC
        tristate "NDFC NanD Flash Controller"
-       depends on 44x
+       depends on 4xx && !PPC_MERGE
        select MTD_NAND_ECC_SMC
        help
-        NDFC Nand Flash Controllers are integrated in EP44x SoCs
+        NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
 
 config MTD_NAND_S3C2410_CLKSTOP
        bool "S3C2410 NAND IDLE clock stop"
@@ -237,7 +256,7 @@ config MTD_NAND_CAFE
        select REED_SOLOMON
        select REED_SOLOMON_DEC16
        help
-         Use NAND flash attached to the CAFÉ chip designed for the $100
+         Use NAND flash attached to the CAFÉ chip designed for the OLPC
          laptop.
 
 config MTD_NAND_CS553X
@@ -280,5 +299,11 @@ config MTD_NAND_PLATFORM
          devices. You will need to provide platform-specific functions
          via platform_data.
 
+config MTD_ALAUDA
+       tristate "MTD driver for Olympus MAUSB-10 and Fijufilm DPC-R1"
+       depends on MTD_NAND && USB
+       help
+         These two (and possibly other) Alauda-based cardreaders for
+         SmartMedia and xD allow raw flash access.
 
 endif # MTD_NAND
index edba1db14bfad6581260b822b60a260063fc542c..3ad6c0165da3ab77ef17c80196b313ce29305cc4 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_TOTO)           += toto.o
 obj-$(CONFIG_MTD_NAND_AUTCPU12)                += autcpu12.o
 obj-$(CONFIG_MTD_NAND_EDB7312)         += edb7312.o
 obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
+obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)  += ppchameleonevb.o
 obj-$(CONFIG_MTD_NAND_S3C2410)         += s3c2410.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)      += diskonchip.o
@@ -27,5 +28,6 @@ obj-$(CONFIG_MTD_NAND_AT91)           += at91_nand.o
 obj-$(CONFIG_MTD_NAND_CM_X270)         += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)   += excite_nandflash.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
+obj-$(CONFIG_MTD_ALAUDA)               += alauda.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
new file mode 100644 (file)
index 0000000..257937c
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * MTD driver for Alauda chips
+ *
+ * Copyright (C) 2007 Joern Engel <joern@logfs.org>
+ *
+ * Based on drivers/usb/usb-skeleton.c which is:
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * and on drivers/usb/storage/alauda.c, which is:
+ *   (c) 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * Idea and initial work by Arnd Bergmann <arnd@arndb.de>
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand_ecc.h>
+
+/* Control commands */
+#define ALAUDA_GET_XD_MEDIA_STATUS     0x08
+#define ALAUDA_ACK_XD_MEDIA_CHANGE     0x0a
+#define ALAUDA_GET_XD_MEDIA_SIG                0x86
+
+/* Common prefix */
+#define ALAUDA_BULK_CMD                        0x40
+
+/* The two ports */
+#define ALAUDA_PORT_XD                 0x00
+#define ALAUDA_PORT_SM                 0x01
+
+/* Bulk commands */
+#define ALAUDA_BULK_READ_PAGE          0x84
+#define ALAUDA_BULK_READ_OOB           0x85 /* don't use, there's a chip bug */
+#define ALAUDA_BULK_READ_BLOCK         0x94
+#define ALAUDA_BULK_ERASE_BLOCK                0xa3
+#define ALAUDA_BULK_WRITE_PAGE         0xa4
+#define ALAUDA_BULK_WRITE_BLOCK                0xb4
+#define ALAUDA_BULK_RESET_MEDIA                0xe0
+
+/* Address shifting */
+#define PBA_LO(pba) ((pba & 0xF) << 5)
+#define PBA_HI(pba) (pba >> 3)
+#define PBA_ZONE(pba) (pba >> 11)
+
+#define TIMEOUT HZ
+
+static struct usb_device_id alauda_table [] = {
+       { USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */
+       { USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, alauda_table);
+
+struct alauda_card {
+       u8      id;             /* id byte */
+       u8      chipshift;      /* 1<<chipshift total size */
+       u8      pageshift;      /* 1<<pageshift page size */
+       u8      blockshift;     /* 1<<blockshift block size */
+};
+
+struct alauda {
+       struct usb_device       *dev;
+       struct usb_interface    *interface;
+       struct mtd_info         *mtd;
+       struct alauda_card      *card;
+       struct mutex            card_mutex;
+       u32                     pagemask;
+       u32                     bytemask;
+       u32                     blockmask;
+       unsigned int            write_out;
+       unsigned int            bulk_in;
+       unsigned int            bulk_out;
+       u8                      port;
+       struct kref             kref;
+};
+
+static struct alauda_card alauda_card_ids[] = {
+       /* NAND flash */
+       { 0x6e, 20, 8, 12},     /* 1 MB */
+       { 0xe8, 20, 8, 12},     /* 1 MB */
+       { 0xec, 20, 8, 12},     /* 1 MB */
+       { 0x64, 21, 8, 12},     /* 2 MB */
+       { 0xea, 21, 8, 12},     /* 2 MB */
+       { 0x6b, 22, 9, 13},     /* 4 MB */
+       { 0xe3, 22, 9, 13},     /* 4 MB */
+       { 0xe5, 22, 9, 13},     /* 4 MB */
+       { 0xe6, 23, 9, 13},     /* 8 MB */
+       { 0x73, 24, 9, 14},     /* 16 MB */
+       { 0x75, 25, 9, 14},     /* 32 MB */
+       { 0x76, 26, 9, 14},     /* 64 MB */
+       { 0x79, 27, 9, 14},     /* 128 MB */
+       { 0x71, 28, 9, 14},     /* 256 MB */
+
+       /* MASK ROM */
+       { 0x5d, 21, 9, 13},     /* 2 MB */
+       { 0xd5, 22, 9, 13},     /* 4 MB */
+       { 0xd6, 23, 9, 13},     /* 8 MB */
+       { 0x57, 24, 9, 13},     /* 16 MB */
+       { 0x58, 25, 9, 13},     /* 32 MB */
+       { }
+};
+
+static struct alauda_card *get_card(u8 id)
+{
+       struct alauda_card *card;
+
+       for (card = alauda_card_ids; card->id; card++)
+               if (card->id == id)
+                       return card;
+       return NULL;
+}
+
+static void alauda_delete(struct kref *kref)
+{
+       struct alauda *al = container_of(kref, struct alauda, kref);
+
+       if (al->mtd) {
+               del_mtd_device(al->mtd);
+               kfree(al->mtd);
+       }
+       usb_put_dev(al->dev);
+       kfree(al);
+}
+
+static int alauda_get_media_status(struct alauda *al, void *buf)
+{
+       int ret;
+
+       mutex_lock(&al->card_mutex);
+       ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
+                       ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ);
+       mutex_unlock(&al->card_mutex);
+       return ret;
+}
+
+static int alauda_ack_media(struct alauda *al)
+{
+       int ret;
+
+       mutex_lock(&al->card_mutex);
+       ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0),
+                       ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ);
+       mutex_unlock(&al->card_mutex);
+       return ret;
+}
+
+static int alauda_get_media_signatures(struct alauda *al, void *buf)
+{
+       int ret;
+
+       mutex_lock(&al->card_mutex);
+       ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
+                       ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ);
+       mutex_unlock(&al->card_mutex);
+       return ret;
+}
+
+static void alauda_reset(struct alauda *al)
+{
+       u8 command[] = {
+               ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0,
+               0, 0, 0, 0, al->port
+       };
+       mutex_lock(&al->card_mutex);
+       usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ);
+       mutex_unlock(&al->card_mutex);
+}
+
+static void correct_data(void *buf, void *read_ecc,
+               int *corrected, int *uncorrected)
+{
+       u8 calc_ecc[3];
+       int err;
+
+       nand_calculate_ecc(NULL, buf, calc_ecc);
+       err = nand_correct_data(NULL, buf, read_ecc, calc_ecc);
+       if (err) {
+               if (err > 0)
+                       (*corrected)++;
+               else
+                       (*uncorrected)++;
+       }
+}
+
+struct alauda_sg_request {
+       struct urb *urb[3];
+       struct completion comp;
+};
+
+static void alauda_complete(struct urb *urb)
+{
+       struct completion *comp = urb->context;
+
+       if (comp)
+               complete(comp);
+}
+
+static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf,
+               void *oob)
+{
+       struct alauda_sg_request sg;
+       struct alauda *al = mtd->priv;
+       u32 pba = from >> al->card->blockshift;
+       u32 page = (from >> al->card->pageshift) & al->pagemask;
+       u8 command[] = {
+               ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba),
+               PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port
+       };
+       int i, err;
+
+       for (i=0; i<3; i++)
+               sg.urb[i] = NULL;
+
+       err = -ENOMEM;
+       for (i=0; i<3; i++) {
+               sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+               if (!sg.urb[i])
+                       goto out;
+       }
+       init_completion(&sg.comp);
+       usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+                       alauda_complete, NULL);
+       usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize,
+                       alauda_complete, NULL);
+       usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16,
+                       alauda_complete, &sg.comp);
+
+       mutex_lock(&al->card_mutex);
+       for (i=0; i<3; i++) {
+               err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+               if (err)
+                       goto cancel;
+       }
+       if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+               err = -ETIMEDOUT;
+cancel:
+               for (i=0; i<3; i++) {
+                       usb_kill_urb(sg.urb[i]);
+               }
+       }
+       mutex_unlock(&al->card_mutex);
+
+out:
+       usb_free_urb(sg.urb[0]);
+       usb_free_urb(sg.urb[1]);
+       usb_free_urb(sg.urb[2]);
+       return err;
+}
+
+static int alauda_read_page(struct mtd_info *mtd, loff_t from,
+               void *buf, u8 *oob, int *corrected, int *uncorrected)
+{
+       int err;
+
+       err = __alauda_read_page(mtd, from, buf, oob);
+       if (err)
+               return err;
+       correct_data(buf, oob+13, corrected, uncorrected);
+       correct_data(buf+256, oob+8, corrected, uncorrected);
+       return 0;
+}
+
+static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf,
+               void *oob)
+{
+       struct alauda_sg_request sg;
+       struct alauda *al = mtd->priv;
+       u32 pba = to >> al->card->blockshift;
+       u32 page = (to >> al->card->pageshift) & al->pagemask;
+       u8 command[] = {
+               ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba),
+               PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port
+       };
+       int i, err;
+
+       for (i=0; i<3; i++)
+               sg.urb[i] = NULL;
+
+       err = -ENOMEM;
+       for (i=0; i<3; i++) {
+               sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+               if (!sg.urb[i])
+                       goto out;
+       }
+       init_completion(&sg.comp);
+       usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+                       alauda_complete, NULL);
+       usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize,
+                       alauda_complete, NULL);
+       usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16,
+                       alauda_complete, &sg.comp);
+
+       mutex_lock(&al->card_mutex);
+       for (i=0; i<3; i++) {
+               err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+               if (err)
+                       goto cancel;
+       }
+       if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+               err = -ETIMEDOUT;
+cancel:
+               for (i=0; i<3; i++) {
+                       usb_kill_urb(sg.urb[i]);
+               }
+       }
+       mutex_unlock(&al->card_mutex);
+
+out:
+       usb_free_urb(sg.urb[0]);
+       usb_free_urb(sg.urb[1]);
+       usb_free_urb(sg.urb[2]);
+       return err;
+}
+
+static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs)
+{
+       struct alauda_sg_request sg;
+       struct alauda *al = mtd->priv;
+       u32 pba = ofs >> al->card->blockshift;
+       u8 command[] = {
+               ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
+               PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port
+       };
+       u8 buf[2];
+       int i, err;
+
+       for (i=0; i<2; i++)
+               sg.urb[i] = NULL;
+
+       err = -ENOMEM;
+       for (i=0; i<2; i++) {
+               sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+               if (!sg.urb[i])
+                       goto out;
+       }
+       init_completion(&sg.comp);
+       usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+                       alauda_complete, NULL);
+       usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2,
+                       alauda_complete, &sg.comp);
+
+       mutex_lock(&al->card_mutex);
+       for (i=0; i<2; i++) {
+               err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+               if (err)
+                       goto cancel;
+       }
+       if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+               err = -ETIMEDOUT;
+cancel:
+               for (i=0; i<2; i++) {
+                       usb_kill_urb(sg.urb[i]);
+               }
+       }
+       mutex_unlock(&al->card_mutex);
+
+out:
+       usb_free_urb(sg.urb[0]);
+       usb_free_urb(sg.urb[1]);
+       return err;
+}
+
+static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob)
+{
+       static u8 ignore_buf[512]; /* write only */
+
+       return __alauda_read_page(mtd, from, ignore_buf, oob);
+}
+
+static int popcount8(u8 c)
+{
+       int ret = 0;
+
+       for ( ; c; c>>=1)
+               ret += c & 1;
+       return ret;
+}
+
+static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+       u8 oob[16];
+       int err;
+
+       err = alauda_read_oob(mtd, ofs, oob);
+       if (err)
+               return err;
+
+       /* A block is marked bad if two or more bits are zero */
+       return popcount8(oob[5]) >= 7 ? 0 : 1;
+}
+
+static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char *buf)
+{
+       struct alauda *al = mtd->priv;
+       void *bounce_buf;
+       int err, corrected=0, uncorrected=0;
+
+       bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
+       if (!bounce_buf)
+               return -ENOMEM;
+
+       *retlen = len;
+       while (len) {
+               u8 oob[16];
+               size_t byte = from & al->bytemask;
+               size_t cplen = min(len, mtd->writesize - byte);
+
+               err = alauda_read_page(mtd, from, bounce_buf, oob,
+                               &corrected, &uncorrected);
+               if (err)
+                       goto out;
+
+               memcpy(buf, bounce_buf + byte, cplen);
+               buf += cplen;
+               from += cplen;
+               len -= cplen;
+       }
+       err = 0;
+       if (corrected)
+               err = -EUCLEAN;
+       if (uncorrected)
+               err = -EBADMSG;
+out:
+       kfree(bounce_buf);
+       return err;
+}
+
+static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char *buf)
+{
+       struct alauda *al = mtd->priv;
+       int err, corrected=0, uncorrected=0;
+
+       if ((from & al->bytemask) || (len & al->bytemask))
+               return alauda_bounce_read(mtd, from, len, retlen, buf);
+
+       *retlen = len;
+       while (len) {
+               u8 oob[16];
+
+               err = alauda_read_page(mtd, from, buf, oob,
+                               &corrected, &uncorrected);
+               if (err)
+                       return err;
+
+               buf += mtd->writesize;
+               from += mtd->writesize;
+               len -= mtd->writesize;
+       }
+       err = 0;
+       if (corrected)
+               err = -EUCLEAN;
+       if (uncorrected)
+               err = -EBADMSG;
+       return err;
+}
+
+static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len,
+               size_t *retlen, const u_char *buf)
+{
+       struct alauda *al = mtd->priv;
+       int err;
+
+       if ((to & al->bytemask) || (len & al->bytemask))
+               return -EINVAL;
+
+       *retlen = len;
+       while (len) {
+               u32 page = (to >> al->card->pageshift) & al->pagemask;
+               u8 oob[16] = {  'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+               /* don't write to bad blocks */
+               if (page == 0) {
+                       err = alauda_isbad(mtd, to);
+                       if (err) {
+                               return -EIO;
+                       }
+               }
+               nand_calculate_ecc(mtd, buf, &oob[13]);
+               nand_calculate_ecc(mtd, buf+256, &oob[8]);
+
+               err = alauda_write_page(mtd, to, (void*)buf, oob);
+               if (err)
+                       return err;
+
+               buf += mtd->writesize;
+               to += mtd->writesize;
+               len -= mtd->writesize;
+       }
+       return 0;
+}
+
+static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct alauda *al = mtd->priv;
+       u32 ofs = instr->addr;
+       u32 len = instr->len;
+       int err;
+
+       if ((ofs & al->blockmask) || (len & al->blockmask))
+               return -EINVAL;
+
+       while (len) {
+               /* don't erase bad blocks */
+               err = alauda_isbad(mtd, ofs);
+               if (err > 0)
+                       err = -EIO;
+               if (err < 0)
+                       return err;
+
+               err = alauda_erase_block(mtd, ofs);
+               if (err < 0)
+                       return err;
+
+               ofs += mtd->erasesize;
+               len -= mtd->erasesize;
+       }
+       return 0;
+}
+
+static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       int err;
+
+       err = __alauda_erase(mtd, instr);
+       instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+       return err;
+}
+
+static int alauda_init_media(struct alauda *al)
+{
+       u8 buf[4], *b0=buf, *b1=buf+1;
+       struct alauda_card *card;
+       struct mtd_info *mtd;
+       int err;
+
+       mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
+       if (!mtd)
+               return -ENOMEM;
+
+       for (;;) {
+               err = alauda_get_media_status(al, buf);
+               if (err < 0)
+                       goto error;
+               if (*b0 & 0x10)
+                       break;
+               msleep(20);
+       }
+
+       err = alauda_ack_media(al);
+       if (err)
+               goto error;
+
+       msleep(10);
+
+       err = alauda_get_media_status(al, buf);
+       if (err < 0)
+               goto error;
+
+       if (*b0 != 0x14) {
+               /* media not ready */
+               err = -EIO;
+               goto error;
+       }
+       err = alauda_get_media_signatures(al, buf);
+       if (err < 0)
+               goto error;
+
+       card = get_card(*b1);
+       if (!card) {
+               printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1);
+               err = -EIO;
+               goto error;
+       }
+       printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n",
+                       1<<card->pageshift, 1<<card->blockshift,
+                       1<<(card->chipshift-20));
+       al->card = card;
+       al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1;
+       al->bytemask = (1 << card->pageshift) - 1;
+       al->blockmask = (1 << card->blockshift) - 1;
+
+       mtd->name = "alauda";
+       mtd->size = 1<<card->chipshift;
+       mtd->erasesize = 1<<card->blockshift;
+       mtd->writesize = 1<<card->pageshift;
+       mtd->type = MTD_NANDFLASH;
+       mtd->flags = MTD_CAP_NANDFLASH;
+       mtd->read = alauda_read;
+       mtd->write = alauda_write;
+       mtd->erase = alauda_erase;
+       mtd->block_isbad = alauda_isbad;
+       mtd->priv = al;
+       mtd->owner = THIS_MODULE;
+
+       err = add_mtd_device(mtd);
+       if (err) {
+               err = -ENFILE;
+               goto error;
+       }
+
+       al->mtd = mtd;
+       alauda_reset(al); /* no clue whether this is necessary */
+       return 0;
+error:
+       kfree(mtd);
+       return err;
+}
+
+static int alauda_check_media(struct alauda *al)
+{
+       u8 buf[2], *b0 = buf, *b1 = buf+1;
+       int err;
+
+       err = alauda_get_media_status(al, buf);
+       if (err < 0)
+               return err;
+
+       if ((*b1 & 0x01) == 0) {
+               /* door open */
+               return -EIO;
+       }
+       if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) {
+               /* no media ? */
+               return -EIO;
+       }
+       if (*b0 & 0x08) {
+               /* media change ? */
+               return alauda_init_media(al);
+       }
+       return 0;
+}
+
+static int alauda_probe(struct usb_interface *interface,
+               const struct usb_device_id *id)
+{
+       struct alauda *al;
+       struct usb_host_interface *iface;
+       struct usb_endpoint_descriptor *ep,
+                       *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL;
+       int i, err = -ENOMEM;
+
+       al = kzalloc(2*sizeof(*al), GFP_KERNEL);
+       if (!al)
+               goto error;
+
+       kref_init(&al->kref);
+       usb_set_intfdata(interface, al);
+
+       al->dev = usb_get_dev(interface_to_usbdev(interface));
+       al->interface = interface;
+
+       iface = interface->cur_altsetting;
+       for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+               ep = &iface->endpoint[i].desc;
+
+               if (usb_endpoint_is_bulk_in(ep)) {
+                       ep_in = ep;
+               } else if (usb_endpoint_is_bulk_out(ep)) {
+                       if (i==0)
+                               ep_wr = ep;
+                       else
+                               ep_out = ep;
+               }
+       }
+       err = -EIO;
+       if (!ep_wr || !ep_in || !ep_out)
+               goto error;
+
+       al->write_out = usb_sndbulkpipe(al->dev,
+                       ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+       al->bulk_in = usb_rcvbulkpipe(al->dev,
+                       ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+       al->bulk_out = usb_sndbulkpipe(al->dev,
+                       ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+       /* second device is identical up to now */
+       memcpy(al+1, al, sizeof(*al));
+
+       mutex_init(&al[0].card_mutex);
+       mutex_init(&al[1].card_mutex);
+
+       al[0].port = ALAUDA_PORT_XD;
+       al[1].port = ALAUDA_PORT_SM;
+
+       info("alauda probed");
+       alauda_check_media(al);
+       alauda_check_media(al+1);
+
+       return 0;
+
+error:
+       if (al)
+               kref_put(&al->kref, alauda_delete);
+       return err;
+}
+
+static void alauda_disconnect(struct usb_interface *interface)
+{
+       struct alauda *al;
+
+       al = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       /* FIXME: prevent more I/O from starting */
+
+       /* decrement our usage count */
+       if (al)
+               kref_put(&al->kref, alauda_delete);
+
+       info("alauda gone");
+}
+
+static struct usb_driver alauda_driver = {
+       .name =         "alauda",
+       .probe =        alauda_probe,
+       .disconnect =   alauda_disconnect,
+       .id_table =     alauda_table,
+};
+
+static int __init alauda_init(void)
+{
+       return usb_register(&alauda_driver);
+}
+
+static void __exit alauda_exit(void)
+{
+       usb_deregister(&alauda_driver);
+}
+
+module_init(alauda_init);
+module_exit(alauda_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
new file mode 100644 (file)
index 0000000..1657ecd
--- /dev/null
@@ -0,0 +1,788 @@
+/* linux/drivers/mtd/nand/bf5xx_nand.c
+ *
+ * Copyright 2006-2007 Analog Devices Inc.
+ *     http://blackfin.uclinux.org/
+ *     Bryan Wu <bryan.wu@analog.com>
+ *
+ * Blackfin BF5xx on-chip NAND flash controler driver
+ *
+ * Derived from drivers/mtd/nand/s3c2410.c
+ * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
+ *
+ * Derived from drivers/mtd/nand/cafe.c
+ * Copyright Â© 2006 Red Hat, Inc.
+ * Copyright Â© 2006 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Changelog:
+ *     12-Jun-2007  Bryan Wu:  Initial version
+ *     18-Jul-2007  Bryan Wu:
+ *             - ECC_HW and ECC_SW supported
+ *             - DMA supported in ECC_HW
+ *             - YAFFS tested as rootfs in both ECC_HW and ECC_SW
+ *
+ * TODO:
+ *     Enable JFFS2 over NAND as rootfs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME       "bf5xx-nand"
+#define DRV_VERSION    "1.2"
+#define DRV_AUTHOR     "Bryan Wu <bryan.wu@analog.com>"
+#define DRV_DESC       "BF5xx on-chip NAND FLash Controller Driver"
+
+#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
+static int hardware_ecc = 1;
+#else
+static int hardware_ecc;
+#endif
+
+static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0};
+
+/*
+ * Data structures for bf5xx nand flash controller driver
+ */
+
+/* bf5xx nand info */
+struct bf5xx_nand_info {
+       /* mtd info */
+       struct nand_hw_control          controller;
+       struct mtd_info                 mtd;
+       struct nand_chip                chip;
+
+       /* platform info */
+       struct bf5xx_nand_platform      *platform;
+
+       /* device info */
+       struct device                   *device;
+
+       /* DMA stuff */
+       struct completion               dma_completion;
+};
+
+/*
+ * Conversion functions
+ */
+static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
+{
+       return container_of(mtd, struct bf5xx_nand_info, mtd);
+}
+
+static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
+{
+       return platform_get_drvdata(pdev);
+}
+
+static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
+{
+       return pdev->dev.platform_data;
+}
+
+/*
+ * struct nand_chip interface function pointers
+ */
+
+/*
+ * bf5xx_nand_hwcontrol
+ *
+ * Issue command and address cycles to the chip
+ */
+static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+                                  unsigned int ctrl)
+{
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       while (bfin_read_NFC_STAT() & WB_FULL)
+               cpu_relax();
+
+       if (ctrl & NAND_CLE)
+               bfin_write_NFC_CMD(cmd);
+       else
+               bfin_write_NFC_ADDR(cmd);
+       SSYNC();
+}
+
+/*
+ * bf5xx_nand_devready()
+ *
+ * returns 0 if the nand is busy, 1 if it is ready
+ */
+static int bf5xx_nand_devready(struct mtd_info *mtd)
+{
+       unsigned short val = bfin_read_NFC_IRQSTAT();
+
+       if ((val & NBUSYIRQ) == NBUSYIRQ)
+               return 1;
+       else
+               return 0;
+}
+
+/*
+ * ECC functions
+ * These allow the bf5xx to use the controller's ECC
+ * generator block to ECC the data as it passes through
+ */
+
+/*
+ * ECC error correction function
+ */
+static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
+                                       u_char *read_ecc, u_char *calc_ecc)
+{
+       struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+       u32 syndrome[5];
+       u32 calced, stored;
+       int i;
+       unsigned short failing_bit, failing_byte;
+       u_char data;
+
+       calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
+       stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
+
+       syndrome[0] = (calced ^ stored);
+
+       /*
+        * syndrome 0: all zero
+        * No error in data
+        * No action
+        */
+       if (!syndrome[0] || !calced || !stored)
+               return 0;
+
+       /*
+        * sysdrome 0: only one bit is one
+        * ECC data was incorrect
+        * No action
+        */
+       if (hweight32(syndrome[0]) == 1) {
+               dev_err(info->device, "ECC data was incorrect!\n");
+               return 1;
+       }
+
+       syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
+       syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
+       syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
+       syndrome[4] = syndrome[2] ^ syndrome[3];
+
+       for (i = 0; i < 5; i++)
+               dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
+
+       dev_info(info->device,
+               "calced[0x%08x], stored[0x%08x]\n",
+               calced, stored);
+
+       /*
+        * sysdrome 0: exactly 11 bits are one, each parity
+        * and parity' pair is 1 & 0 or 0 & 1.
+        * 1-bit correctable error
+        * Correct the error
+        */
+       if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
+               dev_info(info->device,
+                       "1-bit correctable error, correct it.\n");
+               dev_info(info->device,
+                       "syndrome[1] 0x%08x\n", syndrome[1]);
+
+               failing_bit = syndrome[1] & 0x7;
+               failing_byte = syndrome[1] >> 0x3;
+               data = *(dat + failing_byte);
+               data = data ^ (0x1 << failing_bit);
+               *(dat + failing_byte) = data;
+
+               return 0;
+       }
+
+       /*
+        * sysdrome 0: random data
+        * More than 1-bit error, non-correctable error
+        * Discard data, mark bad block
+        */
+       dev_err(info->device,
+               "More than 1-bit error, non-correctable error.\n");
+       dev_err(info->device,
+               "Please discard data, mark bad block\n");
+
+       return 1;
+}
+
+static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+                                       u_char *read_ecc, u_char *calc_ecc)
+{
+       struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+       struct bf5xx_nand_platform *plat = info->platform;
+       unsigned short page_size = (plat->page_size ? 512 : 256);
+       int ret;
+
+       ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+
+       /* If page size is 512, correct second 256 bytes */
+       if (page_size == 512) {
+               dat += 256;
+               read_ecc += 8;
+               calc_ecc += 8;
+               ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+       }
+
+       return ret;
+}
+
+static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       return;
+}
+
+static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
+               const u_char *dat, u_char *ecc_code)
+{
+       struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+       struct bf5xx_nand_platform *plat = info->platform;
+       u16 page_size = (plat->page_size ? 512 : 256);
+       u16 ecc0, ecc1;
+       u32 code[2];
+       u8 *p;
+       int bytes = 3, i;
+
+       /* first 4 bytes ECC code for 256 page size */
+       ecc0 = bfin_read_NFC_ECC0();
+       ecc1 = bfin_read_NFC_ECC1();
+
+       code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
+
+       dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
+
+       /* second 4 bytes ECC code for 512 page size */
+       if (page_size == 512) {
+               ecc0 = bfin_read_NFC_ECC2();
+               ecc1 = bfin_read_NFC_ECC3();
+               code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
+               bytes = 6;
+               dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
+       }
+
+       p = (u8 *)code;
+       for (i = 0; i < bytes; i++)
+               ecc_code[i] = p[i];
+
+       return 0;
+}
+
+/*
+ * PIO mode for buffer writing and reading
+ */
+static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+       int i;
+       unsigned short val;
+
+       /*
+        * Data reads are requested by first writing to NFC_DATA_RD
+        * and then reading back from NFC_READ.
+        */
+       for (i = 0; i < len; i++) {
+               while (bfin_read_NFC_STAT() & WB_FULL)
+                       cpu_relax();
+
+               /* Contents do not matter */
+               bfin_write_NFC_DATA_RD(0x0000);
+               SSYNC();
+
+               while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
+                       cpu_relax();
+
+               buf[i] = bfin_read_NFC_READ();
+
+               val = bfin_read_NFC_IRQSTAT();
+               val |= RD_RDY;
+               bfin_write_NFC_IRQSTAT(val);
+               SSYNC();
+       }
+}
+
+static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
+{
+       uint8_t val;
+
+       bf5xx_nand_read_buf(mtd, &val, 1);
+
+       return val;
+}
+
+static void bf5xx_nand_write_buf(struct mtd_info *mtd,
+                               const uint8_t *buf, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               while (bfin_read_NFC_STAT() & WB_FULL)
+                       cpu_relax();
+
+               bfin_write_NFC_DATA_WR(buf[i]);
+               SSYNC();
+       }
+}
+
+static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+       int i;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
+
+       /*
+        * Data reads are requested by first writing to NFC_DATA_RD
+        * and then reading back from NFC_READ.
+        */
+       bfin_write_NFC_DATA_RD(0x5555);
+
+       SSYNC();
+
+       for (i = 0; i < len; i++)
+               p[i] = bfin_read_NFC_READ();
+}
+
+static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
+                               const uint8_t *buf, int len)
+{
+       int i;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
+
+       for (i = 0; i < len; i++)
+               bfin_write_NFC_DATA_WR(p[i]);
+
+       SSYNC();
+}
+
+/*
+ * DMA functions for buffer writing and reading
+ */
+static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
+{
+       struct bf5xx_nand_info *info = dev_id;
+
+       clear_dma_irqstat(CH_NFC);
+       disable_dma(CH_NFC);
+       complete(&info->dma_completion);
+
+       return IRQ_HANDLED;
+}
+
+static int bf5xx_nand_dma_rw(struct mtd_info *mtd,
+                               uint8_t *buf, int is_read)
+{
+       struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+       struct bf5xx_nand_platform *plat = info->platform;
+       unsigned short page_size = (plat->page_size ? 512 : 256);
+       unsigned short val;
+
+       dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
+                       mtd, buf, is_read);
+
+       /*
+        * Before starting a dma transfer, be sure to invalidate/flush
+        * the cache over the address range of your DMA buffer to
+        * prevent cache coherency problems. Otherwise very subtle bugs
+        * can be introduced to your driver.
+        */
+       if (is_read)
+               invalidate_dcache_range((unsigned int)buf,
+                               (unsigned int)(buf + page_size));
+       else
+               flush_dcache_range((unsigned int)buf,
+                               (unsigned int)(buf + page_size));
+
+       /*
+        * This register must be written before each page is
+        * transferred to generate the correct ECC register
+        * values.
+        */
+       bfin_write_NFC_RST(0x1);
+       SSYNC();
+
+       disable_dma(CH_NFC);
+       clear_dma_irqstat(CH_NFC);
+
+       /* setup DMA register with Blackfin DMA API */
+       set_dma_config(CH_NFC, 0x0);
+       set_dma_start_addr(CH_NFC, (unsigned long) buf);
+       set_dma_x_count(CH_NFC, (page_size >> 2));
+       set_dma_x_modify(CH_NFC, 4);
+
+       /* setup write or read operation */
+       val = DI_EN | WDSIZE_32;
+       if (is_read)
+               val |= WNR;
+       set_dma_config(CH_NFC, val);
+       enable_dma(CH_NFC);
+
+       /* Start PAGE read/write operation */
+       if (is_read)
+               bfin_write_NFC_PGCTL(0x1);
+       else
+               bfin_write_NFC_PGCTL(0x2);
+       wait_for_completion(&info->dma_completion);
+
+       return 0;
+}
+
+static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
+                                       uint8_t *buf, int len)
+{
+       struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+       struct bf5xx_nand_platform *plat = info->platform;
+       unsigned short page_size = (plat->page_size ? 512 : 256);
+
+       dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
+
+       if (len == page_size)
+               bf5xx_nand_dma_rw(mtd, buf, 1);
+       else
+               bf5xx_nand_read_buf(mtd, buf, len);
+}
+
+static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
+                               const uint8_t *buf, int len)
+{
+       struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+       struct bf5xx_nand_platform *plat = info->platform;
+       unsigned short page_size = (plat->page_size ? 512 : 256);
+
+       dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
+
+       if (len == page_size)
+               bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
+       else
+               bf5xx_nand_write_buf(mtd, buf, len);
+}
+
+/*
+ * System initialization functions
+ */
+
+static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
+{
+       int ret;
+       unsigned short val;
+
+       /* Do not use dma */
+       if (!hardware_ecc)
+               return 0;
+
+       init_completion(&info->dma_completion);
+
+       /* Setup DMAC1 channel mux for NFC which shared with SDH */
+       val = bfin_read_DMAC1_PERIMUX();
+       val &= 0xFFFE;
+       bfin_write_DMAC1_PERIMUX(val);
+       SSYNC();
+
+       /* Request NFC DMA channel */
+       ret = request_dma(CH_NFC, "BF5XX NFC driver");
+       if (ret < 0) {
+               dev_err(info->device, " unable to get DMA channel\n");
+               return ret;
+       }
+
+       set_dma_callback(CH_NFC, (void *) bf5xx_nand_dma_irq, (void *) info);
+
+       /* Turn off the DMA channel first */
+       disable_dma(CH_NFC);
+       return 0;
+}
+
+/*
+ * BF5XX NFC hardware initialization
+ *  - pin mux setup
+ *  - clear interrupt status
+ */
+static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
+{
+       int err = 0;
+       unsigned short val;
+       struct bf5xx_nand_platform *plat = info->platform;
+
+       /* setup NFC_CTL register */
+       dev_info(info->device,
+               "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n",
+               (plat->page_size ? 512 : 256),
+               (plat->data_width ? 16 : 8),
+               plat->wr_dly, plat->rd_dly);
+
+       val = (plat->page_size << NFC_PG_SIZE_OFFSET) |
+               (plat->data_width << NFC_NWIDTH_OFFSET) |
+               (plat->rd_dly << NFC_RDDLY_OFFSET) |
+               (plat->rd_dly << NFC_WRDLY_OFFSET);
+       dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
+
+       bfin_write_NFC_CTL(val);
+       SSYNC();
+
+       /* clear interrupt status */
+       bfin_write_NFC_IRQMASK(0x0);
+       SSYNC();
+       val = bfin_read_NFC_IRQSTAT();
+       bfin_write_NFC_IRQSTAT(val);
+       SSYNC();
+
+       if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
+               printk(KERN_ERR DRV_NAME
+               ": Requesting Peripherals failed\n");
+               return -EFAULT;
+       }
+
+       /* DMA initialization  */
+       if (bf5xx_nand_dma_init(info))
+               err = -ENXIO;
+
+       return err;
+}
+
+/*
+ * Device management interface
+ */
+static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+{
+       struct mtd_info *mtd = &info->mtd;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       struct mtd_partition *parts = info->platform->partitions;
+       int nr = info->platform->nr_partitions;
+
+       return add_mtd_partitions(mtd, parts, nr);
+#else
+       return add_mtd_device(mtd);
+#endif
+}
+
+static int bf5xx_nand_remove(struct platform_device *pdev)
+{
+       struct bf5xx_nand_info *info = to_nand_info(pdev);
+       struct mtd_info *mtd = NULL;
+
+       platform_set_drvdata(pdev, NULL);
+
+       /* first thing we need to do is release all our mtds
+        * and their partitions, then go through freeing the
+        * resources used
+        */
+       mtd = &info->mtd;
+       if (mtd) {
+               nand_release(mtd);
+               kfree(mtd);
+       }
+
+       peripheral_free_list(bfin_nfc_pin_req);
+
+       /* free the common resources */
+       kfree(info);
+
+       return 0;
+}
+
+/*
+ * bf5xx_nand_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code checks to see if
+ * it can allocate all necessary resources then calls the
+ * nand layer to look for devices
+ */
+static int bf5xx_nand_probe(struct platform_device *pdev)
+{
+       struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
+       struct bf5xx_nand_info *info = NULL;
+       struct nand_chip *chip = NULL;
+       struct mtd_info *mtd = NULL;
+       int err = 0;
+
+       dev_dbg(&pdev->dev, "(%p)\n", pdev);
+
+       if (!plat) {
+               dev_err(&pdev->dev, "no platform specific information\n");
+               goto exit_error;
+       }
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL) {
+               dev_err(&pdev->dev, "no memory for flash info\n");
+               err = -ENOMEM;
+               goto exit_error;
+       }
+
+       platform_set_drvdata(pdev, info);
+
+       spin_lock_init(&info->controller.lock);
+       init_waitqueue_head(&info->controller.wq);
+
+       info->device     = &pdev->dev;
+       info->platform   = plat;
+
+       /* initialise chip data struct */
+       chip = &info->chip;
+
+       if (plat->data_width)
+               chip->options |= NAND_BUSWIDTH_16;
+
+       chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
+
+       chip->read_buf = (plat->data_width) ?
+               bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
+       chip->write_buf = (plat->data_width) ?
+               bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
+
+       chip->read_byte    = bf5xx_nand_read_byte;
+
+       chip->cmd_ctrl     = bf5xx_nand_hwcontrol;
+       chip->dev_ready    = bf5xx_nand_devready;
+
+       chip->priv         = &info->mtd;
+       chip->controller   = &info->controller;
+
+       chip->IO_ADDR_R    = (void __iomem *) NFC_READ;
+       chip->IO_ADDR_W    = (void __iomem *) NFC_DATA_WR;
+
+       chip->chip_delay   = 0;
+
+       /* initialise mtd info data struct */
+       mtd             = &info->mtd;
+       mtd->priv       = chip;
+       mtd->owner      = THIS_MODULE;
+
+       /* initialise the hardware */
+       err = bf5xx_nand_hw_init(info);
+       if (err != 0)
+               goto exit_error;
+
+       /* setup hardware ECC data struct */
+       if (hardware_ecc) {
+               if (plat->page_size == NFC_PG_SIZE_256) {
+                       chip->ecc.bytes = 3;
+                       chip->ecc.size = 256;
+               } else if (plat->page_size == NFC_PG_SIZE_512) {
+                       chip->ecc.bytes = 6;
+                       chip->ecc.size = 512;
+               }
+
+               chip->read_buf      = bf5xx_nand_dma_read_buf;
+               chip->write_buf     = bf5xx_nand_dma_write_buf;
+               chip->ecc.calculate = bf5xx_nand_calculate_ecc;
+               chip->ecc.correct   = bf5xx_nand_correct_data;
+               chip->ecc.mode      = NAND_ECC_HW;
+               chip->ecc.hwctl     = bf5xx_nand_enable_hwecc;
+       } else {
+               chip->ecc.mode      = NAND_ECC_SOFT;
+       }
+
+       /* scan hardware nand chip and setup mtd info data struct */
+       if (nand_scan(mtd, 1)) {
+               err = -ENXIO;
+               goto exit_error;
+       }
+
+       /* add NAND partition */
+       bf5xx_nand_add_partition(info);
+
+       dev_dbg(&pdev->dev, "initialised ok\n");
+       return 0;
+
+exit_error:
+       bf5xx_nand_remove(pdev);
+
+       if (err == 0)
+               err = -EINVAL;
+       return err;
+}
+
+/* PM Support */
+#ifdef CONFIG_PM
+
+static int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
+{
+       struct bf5xx_nand_info *info = platform_get_drvdata(dev);
+
+       return 0;
+}
+
+static int bf5xx_nand_resume(struct platform_device *dev)
+{
+       struct bf5xx_nand_info *info = platform_get_drvdata(dev);
+
+       if (info)
+               bf5xx_nand_hw_init(info);
+
+       return 0;
+}
+
+#else
+#define bf5xx_nand_suspend NULL
+#define bf5xx_nand_resume NULL
+#endif
+
+/* driver device registration */
+static struct platform_driver bf5xx_nand_driver = {
+       .probe          = bf5xx_nand_probe,
+       .remove         = bf5xx_nand_remove,
+       .suspend        = bf5xx_nand_suspend,
+       .resume         = bf5xx_nand_resume,
+       .driver         = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init bf5xx_nand_init(void)
+{
+       printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n",
+               DRV_DESC, DRV_VERSION);
+
+       return platform_driver_register(&bf5xx_nand_driver);
+}
+
+static void __exit bf5xx_nand_exit(void)
+{
+       platform_driver_unregister(&bf5xx_nand_driver);
+}
+
+module_init(bf5xx_nand_init);
+module_exit(bf5xx_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
index 6f32a35eb1069142ade478b2860d2c0297568827..1e811715211a56f8417bd1c8f107566b6a06d2b4 100644 (file)
@@ -80,7 +80,7 @@ module_param(regdebug, int, 0644);
 static int checkecc = 1;
 module_param(checkecc, int, 0644);
 
-static int numtimings;
+static unsigned int numtimings;
 static int timing[3];
 module_param_array(timing, int, &numtimings, 0644);
 
@@ -623,6 +623,11 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        uint32_t ctrl;
        int err = 0;
 
+       /* Very old versions shared the same PCI ident for all three
+          functions on the chip. Verify the class too... */
+       if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH)
+               return -ENODEV;
+
        err = pci_enable_device(pdev);
        if (err)
                return err;
@@ -816,21 +821,57 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
 }
 
 static struct pci_device_id cafe_nand_tbl[] = {
-       { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 },
-       { 0, }
+       { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID },
+       { }
 };
 
 MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
 
+static int cafe_nand_resume(struct pci_dev *pdev)
+{
+       uint32_t ctrl;
+       struct mtd_info *mtd = pci_get_drvdata(pdev);
+       struct cafe_priv *cafe = mtd->priv;
+
+       /* Start off by resetting the NAND controller completely */
+       cafe_writel(cafe, 1, NAND_RESET);
+       cafe_writel(cafe, 0, NAND_RESET);
+       cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+
+       /* Restore timing configuration */
+       cafe_writel(cafe, timing[0], NAND_TIMING1);
+       cafe_writel(cafe, timing[1], NAND_TIMING2);
+       cafe_writel(cafe, timing[2], NAND_TIMING3);
+
+        /* Disable master reset, enable NAND clock */
+       ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+       ctrl &= 0xffffeff0;
+       ctrl |= 0x00007000;
+       cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+       cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+       cafe_writel(cafe, 0, NAND_DMA_CTRL);
+       cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+       cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+
+       /* Set up DMA address */
+       cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+       if (sizeof(cafe->dmaaddr) > 4)
+       /* Shift in two parts to shut the compiler up */
+               cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+       else
+               cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+
+       /* Enable NAND IRQ in global IRQ mask register */
+       cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+       return 0;
+}
+
 static struct pci_driver cafe_nand_pci_driver = {
        .name = "CAFÉ NAND",
        .id_table = cafe_nand_tbl,
        .probe = cafe_nand_probe,
        .remove = __devexit_p(cafe_nand_remove),
-#ifdef CONFIG_PMx
-       .suspend = cafe_nand_suspend,
        .resume = cafe_nand_resume,
-#endif
 };
 
 static int cafe_nand_init(void)
index e96259f22cca3405b6919c2d01f3b5eb11049552..ab9f5c5db38d35287c249a93b61c23246d249717 100644 (file)
@@ -56,8 +56,6 @@ static unsigned long __initdata doc_locations[] = {
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
 #elif defined(__PPC__)
        0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT_G)
-       0xff000000,
 #else
 #warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
index 7e9afc4c77577190eae94bcbbdbc2afeec9bc72e..bed87290deccd3b07e120278d77f47c347e57517 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/kernel.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
index 24ac6778b1a8cda528ff6426abd37cd24fe12e8b..b4e0e7723894749a42752dd0fe26db91bae4743c 100644 (file)
@@ -7,7 +7,7 @@
  *   Basic support for AG-AND chips is provided.
  *
  *     Additional technical information is available on
- *     http://www.linux-mtd.infradead.org/tech/nand.html
+ *     http://www.linux-mtd.infradead.org/doc/nand.html
  *
  *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *               2002-2006 Thomas Gleixner (tglx@linutronix.de)
@@ -2069,13 +2069,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
  erase_exit:
 
        ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
-       /* Do call back function */
-       if (!ret)
-               mtd_erase_callback(instr);
 
        /* Deselect and wake up anyone waiting on the device */
        nand_release_device(mtd);
 
+       /* Do call back function */
+       if (!ret)
+               mtd_erase_callback(instr);
+
        /*
         * If BBT requires refresh and erase was successful, rewrite any
         * selected bad block tables
index 2fc674a190cfbe704c32ee3779e9af15953db772..a3e3ab0185d52b6e076f7380279ca6a8caf29cd2 100644 (file)
@@ -141,6 +141,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_STMICRO, "ST Micro"},
        {NAND_MFR_HYNIX, "Hynix"},
        {NAND_MFR_MICRON, "Micron"},
+       {NAND_MFR_AMD, "AMD"},
        {0x0, "Unknown"}
 };
 
index 205df0f771febb2230b6698aa50e15c2e09e091c..a7574807dc46a1e2c6ac5697cb1c253cffca8087 100644 (file)
@@ -1272,7 +1272,13 @@ static int prog_page(struct nandsim *ns, int num)
        mypage = NS_GET_PAGE(ns);
        if (mypage->byte == NULL) {
                NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
-               mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+               /*
+                * We allocate memory with GFP_NOFS because a flash FS may
+                * utilize this. If it is holding an FS lock, then gets here,
+                * then kmalloc runs writeback which goes to the FS again
+                * and deadlocks. This was seen in practice.
+                */
+               mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS);
                if (mypage->byte == NULL) {
                        NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
                        return -1;
index fd7a8d5ba29a0d2c9bf626b1f21ddaf721ea7956..1c0e89f00e8dc0d98bc1882079874c2330d8c677 100644 (file)
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
+#ifdef CONFIG_40x
+#include <asm/ibm405.h>
+#else
 #include <asm/ibm44x.h>
+#endif
 
 struct ndfc_nand_mtd {
        struct mtd_info                 mtd;
@@ -230,7 +234,11 @@ static int ndfc_nand_probe(struct platform_device *pdev)
        struct ndfc_controller *ndfc = &ndfc_ctrl;
        unsigned long long phys = settings->ndfc_erpn | res->start;
 
+#ifndef CONFIG_PHYS_64BIT
+       ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
+#else
        ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
+#endif
        if (!ndfc->ndfcbase) {
                printk(KERN_ERR "NDFC: ioremap failed\n");
                return -EIO;
index 5fac4c421a20be16cad4397a08d3f0e48a84ce91..b79a9cf2d162bfe775e02262de401a9429a786ce 100644 (file)
@@ -60,8 +60,8 @@
 
 #include <asm/io.h>
 
-#include <asm/arch/regs-nand.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/regs-nand.h>
+#include <asm/plat-s3c/nand.h>
 
 #ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int hardware_ecc = 1;
index c257d397d08a35d1ca6c6845d51cfce08ee55acf..cb41cbca64f7e63394f352820eb90cc610bac6f8 100644 (file)
@@ -40,4 +40,27 @@ config MTD_ONENAND_OTP
 
          OTP block is fully-guaranteed to be a valid block.
 
+config MTD_ONENAND_2X_PROGRAM
+       bool "OneNAND 2X program support"
+       help
+         The 2X Program is an extension of Program Operation.
+         Since the device is equipped with two DataRAMs, and two-plane NAND
+         Flash memory array, these two component enables simultaneous program
+         of 4KiB. Plane1 has only even blocks such as block0, block2, block4
+         while Plane2 has only odd blocks such as block1, block3, block5.
+         So MTD regards it as 4KiB page size and 256KiB block size
+
+         Now the following chips support it. (KFXXX16Q2M)
+           Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M,
+           Mux:   KFM2G16Q2M, KFN4G16Q2M,
+
+         And more recent chips
+
+config MTD_ONENAND_SIM
+       tristate "OneNAND simulator support"
+       depends on MTD_PARTITIONS
+       help
+         The simulator may simulate various OneNAND flash chips for the
+         OneNAND MTD layer.
+
 endif # MTD_ONENAND
index 269cfe46734503b9f423eeec46fb696f0e7bf1e5..4d2eacfd7e11a761c3cec319f34c735d0fc0222b 100644 (file)
@@ -8,4 +8,7 @@ obj-$(CONFIG_MTD_ONENAND)               += onenand.o
 # Board specific.
 obj-$(CONFIG_MTD_ONENAND_GENERIC)      += generic.o
 
+# Simulator
+obj-$(CONFIG_MTD_ONENAND_SIM)          += onenand_sim.o
+
 onenand-objs = onenand_base.o onenand_bbt.o
index 0537fac8de74fd703a6c50d9116213626b010f75..dd2835569092f5d403b7522271b950e146cbba71 100644 (file)
@@ -206,6 +206,15 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
        default:
                block = (int) (addr >> this->erase_shift);
                page = (int) (addr >> this->page_shift);
+
+               if (ONENAND_IS_2PLANE(this)) {
+                       /* Make the even block number */
+                       block &= ~1;
+                       /* Is it the odd plane? */
+                       if (addr & this->writesize)
+                               block++;
+                       page >>= 1;
+               }
                page &= this->page_mask;
                break;
        }
@@ -216,8 +225,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                value = onenand_bufferram_address(this, block);
                this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
 
-               /* Switch to the next data buffer */
-               ONENAND_SET_NEXT_BUFFERRAM(this);
+               if (ONENAND_IS_2PLANE(this))
+                       /* It is always BufferRAM0 */
+                       ONENAND_SET_BUFFERRAM0(this);
+               else
+                       /* Switch to the next data buffer */
+                       ONENAND_SET_NEXT_BUFFERRAM(this);
 
                return 0;
        }
@@ -247,6 +260,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                        break;
 
                default:
+                       if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
+                               cmd = ONENAND_CMD_2X_PROG;
                        dataram = ONENAND_CURRENT_BUFFERRAM(this);
                        break;
                }
@@ -312,18 +327,20 @@ static int onenand_wait(struct mtd_info *mtd, int state)
                printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
                if (ctrl & ONENAND_CTRL_LOCK)
                        printk(KERN_ERR "onenand_wait: it's locked error.\n");
-               return ctrl;
+               return -EIO;
        }
 
        if (interrupt & ONENAND_INT_READ) {
                int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
                if (ecc) {
-                       printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
                        if (ecc & ONENAND_ECC_2BIT_ALL) {
+                               printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
                                mtd->ecc_stats.failed++;
-                               return ecc;
-                       } else if (ecc & ONENAND_ECC_1BIT_ALL)
+                               return -EBADMSG;
+                       } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+                               printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc);
                                mtd->ecc_stats.corrected++;
+                       }
                }
        } else if (state == FL_READING) {
                printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
@@ -445,8 +462,9 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
        struct onenand_chip *this = mtd->priv;
 
        if (ONENAND_CURRENT_BUFFERRAM(this)) {
+               /* Note: the 'this->writesize' is a real page size */
                if (area == ONENAND_DATARAM)
-                       return mtd->writesize;
+                       return this->writesize;
                if (area == ONENAND_SPARERAM)
                        return mtd->oobsize;
        }
@@ -571,6 +589,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
        return 0;
 }
 
+/**
+ * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
+ * @param mtd          MTD data structure
+ * @param addr         address to check
+ * @return             blockpage address
+ *
+ * Get blockpage address at 2x program mode
+ */
+static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
+{
+       struct onenand_chip *this = mtd->priv;
+       int blockpage, block, page;
+
+       /* Calculate the even block number */
+       block = (int) (addr >> this->erase_shift) & ~1;
+       /* Is it the odd plane? */
+       if (addr & this->writesize)
+               block++;
+       page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
+       blockpage = (block << 7) | page;
+
+       return blockpage;
+}
+
 /**
  * onenand_check_bufferram - [GENERIC] Check BufferRAM information
  * @param mtd          MTD data structure
@@ -585,7 +627,10 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
        int blockpage, found = 0;
        unsigned int i;
 
-       blockpage = (int) (addr >> this->page_shift);
+       if (ONENAND_IS_2PLANE(this))
+               blockpage = onenand_get_2x_blockpage(mtd, addr);
+       else
+               blockpage = (int) (addr >> this->page_shift);
 
        /* Is there valid data? */
        i = ONENAND_CURRENT_BUFFERRAM(this);
@@ -625,7 +670,10 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
        int blockpage;
        unsigned int i;
 
-       blockpage = (int) (addr >> this->page_shift);
+       if (ONENAND_IS_2PLANE(this))
+               blockpage = onenand_get_2x_blockpage(mtd, addr);
+       else
+               blockpage = (int) (addr >> this->page_shift);
 
        /* Invalidate another BufferRAM */
        i = ONENAND_NEXT_BUFFERRAM(this);
@@ -717,36 +765,86 @@ static void onenand_release_device(struct mtd_info *mtd)
 }
 
 /**
- * onenand_read - [MTD Interface] Read data from flash
+ * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd          MTD device structure
+ * @param buf          destination address
+ * @param column       oob offset to read from
+ * @param thislen      oob length to read
+ */
+static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
+                               int thislen)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct nand_oobfree *free;
+       int readcol = column;
+       int readend = column + thislen;
+       int lastgap = 0;
+       unsigned int i;
+       uint8_t *oob_buf = this->oob_buf;
+
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               if (readcol >= lastgap)
+                       readcol += free->offset - lastgap;
+               if (readend >= lastgap)
+                       readend += free->offset - lastgap;
+               lastgap = free->offset + free->length;
+       }
+       this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               int free_end = free->offset + free->length;
+               if (free->offset < readend && free_end > readcol) {
+                       int st = max_t(int,free->offset,readcol);
+                       int ed = min_t(int,free_end,readend);
+                       int n = ed - st;
+                       memcpy(buf, oob_buf + st, n);
+                       buf += n;
+               } else if (column == 0)
+                       break;
+       }
+       return 0;
+}
+
+/**
+ * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
  * @param mtd          MTD device structure
  * @param from         offset to read from
- * @param len          number of bytes to read
- * @param retlen       pointer to variable to store the number of read bytes
- * @param buf          the databuffer to put data
+ * @param ops:         oob operation description structure
  *
- * Read with ecc
-*/
-static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char *buf)
+ * OneNAND read main and/or out-of-band data
+ */
+static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
+                               struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
        struct mtd_ecc_stats stats;
-       int read = 0, column;
-       int thislen;
+       size_t len = ops->len;
+       size_t ooblen = ops->ooblen;
+       u_char *buf = ops->datbuf;
+       u_char *oobbuf = ops->oobbuf;
+       int read = 0, column, thislen;
+       int oobread = 0, oobcolumn, thisooblen, oobsize;
        int ret = 0, boundary = 0;
+       int writesize = this->writesize;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+       if (ops->mode == MTD_OOB_AUTO)
+               oobsize = this->ecclayout->oobavail;
+       else
+               oobsize = mtd->oobsize;
+
+       oobcolumn = from & (mtd->oobsize - 1);
 
        /* Do not allow reads past end of device */
        if ((from + len) > mtd->size) {
-               printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n");
-               *retlen = 0;
+               printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
+               ops->retlen = 0;
+               ops->oobretlen = 0;
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_READING);
-
        stats = mtd->ecc_stats;
 
        /* Read-while-load method */
@@ -754,22 +852,22 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
        /* Do first load to bufferRAM */
        if (read < len) {
                if (!onenand_check_bufferram(mtd, from)) {
-                       this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+                       this->command(mtd, ONENAND_CMD_READ, from, writesize);
                        ret = this->wait(mtd, FL_READING);
                        onenand_update_bufferram(mtd, from, !ret);
                }
        }
 
-       thislen = min_t(int, mtd->writesize, len - read);
-       column = from & (mtd->writesize - 1);
-       if (column + thislen > mtd->writesize)
-               thislen = mtd->writesize - column;
+       thislen = min_t(int, writesize, len - read);
+       column = from & (writesize - 1);
+       if (column + thislen > writesize)
+               thislen = writesize - column;
 
        while (!ret) {
                /* If there is more to load then start next load */
                from += thislen;
                if (read + thislen < len) {
-                       this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+                       this->command(mtd, ONENAND_CMD_READ, from, writesize);
                        /*
                         * Chip boundary handling in DDP
                         * Now we issued chip 1 read and pointed chip 1
@@ -785,6 +883,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                }
                /* While load is going, read from last bufferRAM */
                this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+
+               /* Read oob area if needed */
+               if (oobbuf) {
+                       thisooblen = oobsize - oobcolumn;
+                       thisooblen = min_t(int, thisooblen, ooblen - oobread);
+
+                       if (ops->mode == MTD_OOB_AUTO)
+                               onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
+                       else
+                               this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
+                       oobread += thisooblen;
+                       oobbuf += thisooblen;
+                       oobcolumn = 0;
+               }
+
                /* See if we are done */
                read += thislen;
                if (read == len)
@@ -794,7 +907,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                        this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
                ONENAND_SET_NEXT_BUFFERRAM(this);
                buf += thislen;
-               thislen = min_t(int, mtd->writesize, len - read);
+               thislen = min_t(int, writesize, len - read);
                column = 0;
                cond_resched();
                /* Now wait for load */
@@ -802,15 +915,13 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
                onenand_update_bufferram(mtd, from, !ret);
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
-
        /*
         * Return success, if no ECC failures, else -EBADMSG
         * fs driver will take care of that, because
         * retlen == desired len and result == -EBADMSG
         */
-       *retlen = read;
+       ops->retlen = read;
+       ops->oobretlen = oobread;
 
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
@@ -822,69 +933,29 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
 }
 
 /**
- * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
- * @param mtd          MTD device structure
- * @param buf          destination address
- * @param column       oob offset to read from
- * @param thislen      oob length to read
- */
-static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
-                               int thislen)
-{
-       struct onenand_chip *this = mtd->priv;
-       struct nand_oobfree *free;
-       int readcol = column;
-       int readend = column + thislen;
-       int lastgap = 0;
-       unsigned int i;
-       uint8_t *oob_buf = this->oob_buf;
-
-       free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-               if (readcol >= lastgap)
-                       readcol += free->offset - lastgap;
-               if (readend >= lastgap)
-                       readend += free->offset - lastgap;
-               lastgap = free->offset + free->length;
-       }
-       this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
-       free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-               int free_end = free->offset + free->length;
-               if (free->offset < readend && free_end > readcol) {
-                       int st = max_t(int,free->offset,readcol);
-                       int ed = min_t(int,free_end,readend);
-                       int n = ed - st;
-                       memcpy(buf, oob_buf + st, n);
-                       buf += n;
-               } else if (column == 0)
-                       break;
-       }
-       return 0;
-}
-
-/**
- * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
+ * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
  * @param mtd          MTD device structure
  * @param from         offset to read from
- * @param len          number of bytes to read
- * @param retlen       pointer to variable to store the number of read bytes
- * @param buf          the databuffer to put data
- * @param mode         operation mode
+ * @param ops:         oob operation description structure
  *
  * OneNAND read out-of-band data from the spare area
  */
-static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
+static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
+                       struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
        int read = 0, thislen, column, oobsize;
+       size_t len = ops->ooblen;
+       mtd_oob_mode_t mode = ops->mode;
+       u_char *buf = ops->oobbuf;
        int ret = 0;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+       from += ops->ooboffs;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
        /* Initialize return length value */
-       *retlen = 0;
+       ops->oobretlen = 0;
 
        if (mode == MTD_OOB_AUTO)
                oobsize = this->ecclayout->oobavail;
@@ -894,7 +965,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
        column = from & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n");
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
                return -EINVAL;
        }
 
@@ -902,13 +973,10 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
        if (unlikely(from >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (from >> this->page_shift)) * oobsize)) {
-               printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n");
+               printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_READING);
-
        while (read < len) {
                cond_resched();
 
@@ -928,7 +996,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
                        this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
 
                if (ret) {
-                       printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret);
+                       printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
                        break;
                }
 
@@ -947,22 +1015,52 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
                }
        }
 
-       /* Deselect and wake up anyone waiting on the device */
+       ops->oobretlen = read;
+       return ret;
+}
+
+/**
+ * onenand_read - [MTD Interface] Read data from flash
+ * @param mtd          MTD device structure
+ * @param from         offset to read from
+ * @param len          number of bytes to read
+ * @param retlen       pointer to variable to store the number of read bytes
+ * @param buf          the databuffer to put data
+ *
+ * Read with ecc
+*/
+static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
+       size_t *retlen, u_char *buf)
+{
+       struct mtd_oob_ops ops = {
+               .len    = len,
+               .ooblen = 0,
+               .datbuf = buf,
+               .oobbuf = NULL,
+       };
+       int ret;
+
+       onenand_get_device(mtd, FL_READING);
+       ret = onenand_read_ops_nolock(mtd, from, &ops);
        onenand_release_device(mtd);
 
-       *retlen = read;
+       *retlen = ops.retlen;
        return ret;
 }
 
 /**
- * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
+ * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
  * @param mtd:         MTD device structure
  * @param from:                offset to read from
  * @param ops:         oob operation description structure
+
+ * Read main and/or out-of-band
  */
 static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
                            struct mtd_oob_ops *ops)
 {
+       int ret;
+
        switch (ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
@@ -972,8 +1070,15 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
        default:
                return -EINVAL;
        }
-       return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen,
-                                  &ops->oobretlen, ops->oobbuf, ops->mode);
+
+       onenand_get_device(mtd, FL_READING);
+       if (ops->datbuf)
+               ret = onenand_read_ops_nolock(mtd, from, ops);
+       else
+               ret = onenand_read_oob_nolock(mtd, from, ops);
+       onenand_release_device(mtd);
+
+       return ret;
 }
 
 /**
@@ -1079,7 +1184,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
                /* Read more? */
                if (read < len) {
                        /* Update Page size */
-                       from += mtd->writesize;
+                       from += this->writesize;
                        column = 0;
                }
        }
@@ -1097,7 +1202,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
  * @param mtd          MTD device structure
  * @param buf          the databuffer to verify
  * @param to           offset to read from
- *
  */
 static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
 {
@@ -1125,7 +1229,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
  * @param buf          the databuffer to verify
  * @param addr         offset to read from
  * @param len          number of bytes to read and compare
- *
  */
 static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
 {
@@ -1135,12 +1238,12 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
        int thislen, column;
 
        while (len != 0) {
-               thislen = min_t(int, mtd->writesize, len);
-               column = addr & (mtd->writesize - 1);
-               if (column + thislen > mtd->writesize)
-                       thislen = mtd->writesize - column;
+               thislen = min_t(int, this->writesize, len);
+               column = addr & (this->writesize - 1);
+               if (column + thislen > this->writesize)
+                       thislen = this->writesize - column;
 
-               this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
+               this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
 
                onenand_update_bufferram(mtd, addr, 0);
 
@@ -1171,50 +1274,101 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
 #define NOTALIGNED(x)  ((x & (this->subpagesize - 1)) != 0)
 
 /**
- * onenand_write - [MTD Interface] write buffer to FLASH
+ * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd          MTD device structure
+ * @param oob_buf      oob buffer
+ * @param buf          source address
+ * @param column       oob offset to write to
+ * @param thislen      oob length to write
+ */
+static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
+                                 const u_char *buf, int column, int thislen)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct nand_oobfree *free;
+       int writecol = column;
+       int writeend = column + thislen;
+       int lastgap = 0;
+       unsigned int i;
+
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               if (writecol >= lastgap)
+                       writecol += free->offset - lastgap;
+               if (writeend >= lastgap)
+                       writeend += free->offset - lastgap;
+               lastgap = free->offset + free->length;
+       }
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+               int free_end = free->offset + free->length;
+               if (free->offset < writeend && free_end > writecol) {
+                       int st = max_t(int,free->offset,writecol);
+                       int ed = min_t(int,free_end,writeend);
+                       int n = ed - st;
+                       memcpy(oob_buf + st, buf, n);
+                       buf += n;
+               } else if (column == 0)
+                       break;
+       }
+       return 0;
+}
+
+/**
+ * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
  * @param mtd          MTD device structure
  * @param to           offset to write to
- * @param len          number of bytes to write
- * @param retlen       pointer to variable to store the number of written bytes
- * @param buf          the data to write
+ * @param ops          oob operation description structure
  *
- * Write with ECC
+ * Write main and/or oob with ECC
  */
-static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
-       size_t *retlen, const u_char *buf)
+static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
+                               struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
-       int written = 0;
+       int written = 0, column, thislen, subpage;
+       int oobwritten = 0, oobcolumn, thisooblen, oobsize;
+       size_t len = ops->len;
+       size_t ooblen = ops->ooblen;
+       const u_char *buf = ops->datbuf;
+       const u_char *oob = ops->oobbuf;
+       u_char *oobbuf;
        int ret = 0;
-       int column, subpage;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
-       *retlen = 0;
+       ops->retlen = 0;
+       ops->oobretlen = 0;
 
        /* Do not allow writes past end of device */
        if (unlikely((to + len) > mtd->size)) {
-               printk(KERN_ERR "onenand_write: Attempt write to past end of device\n");
+               printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
                return -EINVAL;
        }
 
        /* Reject writes, which are not page aligned */
         if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
-                printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n");
+                printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
                 return -EINVAL;
         }
 
-       column = to & (mtd->writesize - 1);
+       if (ops->mode == MTD_OOB_AUTO)
+               oobsize = this->ecclayout->oobavail;
+       else
+               oobsize = mtd->oobsize;
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
+       oobcolumn = to & (mtd->oobsize - 1);
+
+       column = to & (mtd->writesize - 1);
 
        /* Loop until all data write */
        while (written < len) {
-               int thislen = min_t(int, mtd->writesize - column, len - written);
                u_char *wbuf = (u_char *) buf;
 
+               thislen = min_t(int, mtd->writesize - column, len - written);
+               thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
+
                cond_resched();
 
                this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
@@ -1228,7 +1382,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
                }
 
                this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
-               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+               if (oob) {
+                       oobbuf = this->oob_buf;
+
+                       /* We send data to spare ram with oobsize
+                        * to prevent byte access */
+                       memset(oobbuf, 0xff, mtd->oobsize);
+                       if (ops->mode == MTD_OOB_AUTO)
+                               onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
+                       else
+                               memcpy(oobbuf + oobcolumn, oob, thisooblen);
+
+                       oobwritten += thisooblen;
+                       oob += thisooblen;
+                       oobcolumn = 0;
+               } else
+                       oobbuf = (u_char *) ffchars;
+
+               this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
 
                this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
 
@@ -1236,16 +1408,20 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
 
                /* In partial page write we don't update bufferram */
                onenand_update_bufferram(mtd, to, !ret && !subpage);
+               if (ONENAND_IS_2PLANE(this)) {
+                       ONENAND_SET_BUFFERRAM1(this);
+                       onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
+               }
 
                if (ret) {
-                       printk(KERN_ERR "onenand_write: write filaed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
                        break;
                }
 
                /* Only check verify write turn on */
                ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
                if (ret) {
-                       printk(KERN_ERR "onenand_write: verify failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
                        break;
                }
 
@@ -1262,54 +1438,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
        /* Deselect and wake up anyone waiting on the device */
        onenand_release_device(mtd);
 
-       *retlen = written;
+       ops->retlen = written;
 
        return ret;
 }
 
-/**
- * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
- * @param mtd          MTD device structure
- * @param oob_buf      oob buffer
- * @param buf          source address
- * @param column       oob offset to write to
- * @param thislen      oob length to write
- */
-static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
-                                 const u_char *buf, int column, int thislen)
-{
-       struct onenand_chip *this = mtd->priv;
-       struct nand_oobfree *free;
-       int writecol = column;
-       int writeend = column + thislen;
-       int lastgap = 0;
-       unsigned int i;
-
-       free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-               if (writecol >= lastgap)
-                       writecol += free->offset - lastgap;
-               if (writeend >= lastgap)
-                       writeend += free->offset - lastgap;
-               lastgap = free->offset + free->length;
-       }
-       free = this->ecclayout->oobfree;
-       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
-               int free_end = free->offset + free->length;
-               if (free->offset < writeend && free_end > writecol) {
-                       int st = max_t(int,free->offset,writecol);
-                       int ed = min_t(int,free_end,writeend);
-                       int n = ed - st;
-                       memcpy(oob_buf + st, buf, n);
-                       buf += n;
-               } else if (column == 0)
-                       break;
-       }
-       return 0;
-}
 
 /**
- * onenand_do_write_oob - [Internal] OneNAND write out-of-band
+ * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
  * @param mtd          MTD device structure
  * @param to           offset to write to
  * @param len          number of bytes to write
@@ -1319,18 +1455,23 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
  *
  * OneNAND write out-of-band
  */
-static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
-                               size_t *retlen, const u_char *buf, mtd_oob_mode_t mode)
+static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
+                                   struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
        int column, ret = 0, oobsize;
        int written = 0;
        u_char *oobbuf;
+       size_t len = ops->ooblen;
+       const u_char *buf = ops->oobbuf;
+       mtd_oob_mode_t mode = ops->mode;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+       to += ops->ooboffs;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
        /* Initialize retlen, in case of early exit */
-       *retlen = 0;
+       ops->oobretlen = 0;
 
        if (mode == MTD_OOB_AUTO)
                oobsize = this->ecclayout->oobavail;
@@ -1340,13 +1481,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
        column = to & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n");
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
                return -EINVAL;
        }
 
        /* For compatibility with NAND: Do not allow write past end of page */
        if (unlikely(column + len > oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: "
+               printk(KERN_ERR "onenand_write_oob_nolock: "
                      "Attempt to write past end of page\n");
                return -EINVAL;
        }
@@ -1355,13 +1496,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
        if (unlikely(to >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (to >> this->page_shift)) * oobsize)) {
-               printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n");
+               printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
                return -EINVAL;
        }
 
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_WRITING);
-
        oobbuf = this->oob_buf;
 
        /* Loop until all data write */
@@ -1384,16 +1522,20 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
                this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
 
                onenand_update_bufferram(mtd, to, 0);
+               if (ONENAND_IS_2PLANE(this)) {
+                       ONENAND_SET_BUFFERRAM1(this);
+                       onenand_update_bufferram(mtd, to + this->writesize, 0);
+               }
 
                ret = this->wait(mtd, FL_WRITING);
                if (ret) {
-                       printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
                        break;
                }
 
                ret = onenand_verify_oob(mtd, oobbuf, to);
                if (ret) {
-                       printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
                        break;
                }
 
@@ -1406,11 +1548,37 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
                column = 0;
        }
 
-       /* Deselect and wake up anyone waiting on the device */
-       onenand_release_device(mtd);
+       ops->oobretlen = written;
 
-       *retlen = written;
+       return ret;
+}
 
+/**
+ * onenand_write - [MTD Interface] write buffer to FLASH
+ * @param mtd          MTD device structure
+ * @param to           offset to write to
+ * @param len          number of bytes to write
+ * @param retlen       pointer to variable to store the number of written bytes
+ * @param buf          the data to write
+ *
+ * Write with ECC
+ */
+static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf)
+{
+       struct mtd_oob_ops ops = {
+               .len    = len,
+               .ooblen = 0,
+               .datbuf = (u_char *) buf,
+               .oobbuf = NULL,
+       };
+       int ret;
+
+       onenand_get_device(mtd, FL_WRITING);
+       ret = onenand_write_ops_nolock(mtd, to, &ops);
+       onenand_release_device(mtd);
+
+       *retlen = ops.retlen;
        return ret;
 }
 
@@ -1423,6 +1591,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
 static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops)
 {
+       int ret;
+
        switch (ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
@@ -1432,21 +1602,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
        default:
                return -EINVAL;
        }
-       return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen,
-                                   &ops->oobretlen, ops->oobbuf, ops->mode);
+
+       onenand_get_device(mtd, FL_WRITING);
+       if (ops->datbuf)
+               ret = onenand_write_ops_nolock(mtd, to, ops);
+       else
+               ret = onenand_write_oob_nolock(mtd, to, ops);
+       onenand_release_device(mtd);
+
+       return ret;
 }
 
 /**
- * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
  * @param mtd          MTD device structure
  * @param ofs          offset from device start
- * @param getchip      0, if the chip is already selected
  * @param allowbbt     1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
  */
-static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
+static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
        struct onenand_chip *this = mtd->priv;
        struct bbm_info *bbm = this->bbm;
@@ -1507,7 +1683,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                cond_resched();
 
                /* Check if we have a bad block, we do not erase bad blocks */
-               if (onenand_block_checkbad(mtd, addr, 0, 0)) {
+               if (onenand_block_isbad_nolock(mtd, addr, 0)) {
                        printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr);
                        instr->state = MTD_ERASE_FAILED;
                        goto erase_exit;
@@ -1535,13 +1711,14 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
 erase_exit:
 
        ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
-       /* Do call back function */
-       if (!ret)
-               mtd_erase_callback(instr);
 
        /* Deselect and wake up anyone waiting on the device */
        onenand_release_device(mtd);
 
+       /* Do call back function */
+       if (!ret)
+               mtd_erase_callback(instr);
+
        return ret;
 }
 
@@ -1571,11 +1748,16 @@ static void onenand_sync(struct mtd_info *mtd)
  */
 static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
 {
+       int ret;
+
        /* Check for invalid offset */
        if (ofs > mtd->size)
                return -EINVAL;
 
-       return onenand_block_checkbad(mtd, ofs, 1, 0);
+       onenand_get_device(mtd, FL_READING);
+       ret = onenand_block_isbad_nolock(mtd, ofs, 0);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1591,7 +1773,12 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        struct onenand_chip *this = mtd->priv;
        struct bbm_info *bbm = this->bbm;
        u_char buf[2] = {0, 0};
-       size_t retlen;
+       struct mtd_oob_ops ops = {
+               .mode = MTD_OOB_PLACE,
+               .ooblen = 2,
+               .oobbuf = buf,
+               .ooboffs = 0,
+       };
        int block;
 
        /* Get block number */
@@ -1601,7 +1788,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 
         /* We write two bytes, so we dont have to mess with 16 bit access */
         ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
-        return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE);
+        return onenand_write_oob_nolock(mtd, ofs, &ops);
 }
 
 /**
@@ -1624,7 +1811,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
                return ret;
        }
 
-       return this->block_markbad(mtd, ofs);
+       onenand_get_device(mtd, FL_WRITING);
+       ret = this->block_markbad(mtd, ofs);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1715,7 +1905,12 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
  */
 static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
-       return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+       int ret;
+
+       onenand_get_device(mtd, FL_LOCKING);
+       ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1728,7 +1923,12 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
  */
 static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
-       return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+       int ret;
+
+       onenand_get_device(mtd, FL_LOCKING);
+       ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+       onenand_release_device(mtd);
+       return ret;
 }
 
 /**
@@ -1790,7 +1990,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
                        loff_t ofs = this->chipsize >> 1;
                        size_t len = mtd->erasesize;
 
-                       onenand_unlock(mtd, ofs, len);
+                       onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
                }
 
                onenand_check_lock_status(this);
@@ -1798,7 +1998,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
                return 0;
        }
 
-       onenand_unlock(mtd, 0x0, this->chipsize);
+       onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK);
 
        return 0;
 }
@@ -1823,13 +2023,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
+       struct mtd_oob_ops ops = {
+               .len    = len,
+               .ooblen = 0,
+               .datbuf = buf,
+               .oobbuf = NULL,
+       };
        int ret;
 
        /* Enter OTP access mode */
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = mtd->read(mtd, from, len, retlen, buf);
+       ret = onenand_read_ops_nolock(mtd, from, &ops);
 
        /* Exit OTP access mode */
        this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1841,19 +2047,20 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
 /**
  * do_otp_write - [DEFAULT] Write OTP block area
  * @param mtd          MTD device structure
- * @param from         The offset to write
+ * @param to           The offset to write
  * @param len          number of bytes to write
  * @param retlen       pointer to variable to store the number of write bytes
  * @param buf          the databuffer to put/get data
  *
  * Write OTP block area.
  */
-static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
+static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
        unsigned char *pbuf = buf;
        int ret;
+       struct mtd_oob_ops ops;
 
        /* Force buffer page aligned */
        if (len < mtd->writesize) {
@@ -1867,7 +2074,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = mtd->write(mtd, from, len, retlen, pbuf);
+       ops.len = len;
+       ops.ooblen = 0;
+       ops.datbuf = pbuf;
+       ops.oobbuf = NULL;
+       ret = onenand_write_ops_nolock(mtd, to, &ops);
+       *retlen = ops.retlen;
 
        /* Exit OTP access mode */
        this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1890,13 +2102,21 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct onenand_chip *this = mtd->priv;
+       struct mtd_oob_ops ops = {
+               .mode = MTD_OOB_PLACE,
+               .ooblen = len,
+               .oobbuf = buf,
+               .ooboffs = 0,
+       };
        int ret;
 
        /* Enter OTP access mode */
        this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
        this->wait(mtd, FL_OTPING);
 
-       ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE);
+       ret = onenand_write_oob_nolock(mtd, from, &ops);
+
+       *retlen = ops.oobretlen;
 
        /* Exit OTP access mode */
        this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1943,13 +2163,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
        if (((mtd->writesize * otp_pages) - (from + len)) < 0)
                return 0;
 
+       onenand_get_device(mtd, FL_OTPING);
        while (len > 0 && otp_pages > 0) {
                if (!action) {  /* OTP Info functions */
                        struct otp_info *otpinfo;
 
                        len -= sizeof(struct otp_info);
-                       if (len <= 0)
-                               return -ENOSPC;
+                       if (len <= 0) {
+                               ret = -ENOSPC;
+                               break;
+                       }
 
                        otpinfo = (struct otp_info *) buf;
                        otpinfo->start = from;
@@ -1969,13 +2192,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
                        len -= size;
                        *retlen += size;
 
-                       if (ret < 0)
-                               return ret;
+                       if (ret)
+                               break;
                }
                otp_pages--;
        }
+       onenand_release_device(mtd);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -2107,6 +2331,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
  *
  * Check and set OneNAND features
  * - lock scheme
+ * - two plane
  */
 static void onenand_check_features(struct mtd_info *mtd)
 {
@@ -2118,19 +2343,35 @@ static void onenand_check_features(struct mtd_info *mtd)
        process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
 
        /* Lock scheme */
-       if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
+       switch (density) {
+       case ONENAND_DEVICE_DENSITY_4Gb:
+               this->options |= ONENAND_HAS_2PLANE;
+
+       case ONENAND_DEVICE_DENSITY_2Gb:
+               /* 2Gb DDP don't have 2 plane */
+               if (!ONENAND_IS_DDP(this))
+                       this->options |= ONENAND_HAS_2PLANE;
+               this->options |= ONENAND_HAS_UNLOCK_ALL;
+
+       case ONENAND_DEVICE_DENSITY_1Gb:
                /* A-Die has all block unlock */
-               if (process) {
-                       printk(KERN_DEBUG "Chip support all block unlock\n");
+               if (process)
                        this->options |= ONENAND_HAS_UNLOCK_ALL;
-               }
-       } else {
-               /* Some OneNAND has continues lock scheme */
-               if (!process) {
-                       printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
+               break;
+
+       default:
+               /* Some OneNAND has continuous lock scheme */
+               if (!process)
                        this->options |= ONENAND_HAS_CONT_LOCK;
-               }
+               break;
        }
+
+       if (this->options & ONENAND_HAS_CONT_LOCK)
+               printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
+       if (this->options & ONENAND_HAS_UNLOCK_ALL)
+               printk(KERN_DEBUG "Chip support all block unlock\n");
+       if (this->options & ONENAND_HAS_2PLANE)
+               printk(KERN_DEBUG "Chip has 2 plane\n");
 }
 
 /**
@@ -2154,7 +2395,7 @@ static void onenand_print_device_info(int device, int version)
                 (16 << density),
                 vcc ? "2.65/3.3" : "1.8",
                 device);
-       printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
+       printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
 }
 
 static const struct onenand_manufacturers onenand_manuf_ids[] = {
@@ -2257,6 +2498,8 @@ static int onenand_probe(struct mtd_info *mtd)
        this->erase_shift = ffs(mtd->erasesize) - 1;
        this->page_shift = ffs(mtd->writesize) - 1;
        this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
+       /* It's real page size */
+       this->writesize = mtd->writesize;
 
        /* REVIST: Multichip handling */
 
@@ -2265,6 +2508,17 @@ static int onenand_probe(struct mtd_info *mtd)
        /* Check OneNAND features */
        onenand_check_features(mtd);
 
+       /*
+        * We emulate the 4KiB page and 256KiB erase block size
+        * But oobsize is still 64 bytes.
+        * It is only valid if you turn on 2X program support,
+        * Otherwise it will be ignored by compiler.
+        */
+       if (ONENAND_IS_2PLANE(this)) {
+               mtd->writesize <<= 1;
+               mtd->erasesize <<= 1;
+       }
+
        return 0;
 }
 
diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c
new file mode 100644 (file)
index 0000000..0d89ad5
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ *  linux/drivers/mtd/onenand/onenand_sim.c
+ *
+ *  The OneNAND simulator
+ *
+ *  Copyright Â© 2005-2007 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
+
+#include <linux/io.h>
+
+#ifndef CONFIG_ONENAND_SIM_MANUFACTURER
+#define CONFIG_ONENAND_SIM_MANUFACTURER         0xec
+#endif
+#ifndef CONFIG_ONENAND_SIM_DEVICE_ID
+#define CONFIG_ONENAND_SIM_DEVICE_ID            0x04
+#endif
+#ifndef CONFIG_ONENAND_SIM_VERSION_ID
+#define CONFIG_ONENAND_SIM_VERSION_ID           0x1e
+#endif
+
+static int manuf_id    = CONFIG_ONENAND_SIM_MANUFACTURER;
+static int device_id   = CONFIG_ONENAND_SIM_DEVICE_ID;
+static int version_id  = CONFIG_ONENAND_SIM_VERSION_ID;
+
+struct onenand_flash {
+       void __iomem *base;
+       void __iomem *data;
+};
+
+#define ONENAND_CORE(flash)            (flash->data)
+#define ONENAND_CORE_SPARE(flash, this, offset)                                \
+       ((flash->data) + (this->chipsize) + (offset >> 5))
+
+#define ONENAND_MAIN_AREA(this, offset)                                        \
+       (this->base + ONENAND_DATARAM + offset)
+
+#define ONENAND_SPARE_AREA(this, offset)                               \
+       (this->base + ONENAND_SPARERAM + offset)
+
+#define ONENAND_GET_WP_STATUS(this)                                    \
+       (readw(this->base + ONENAND_REG_WP_STATUS))
+
+#define ONENAND_SET_WP_STATUS(v, this)                                 \
+       (writew(v, this->base + ONENAND_REG_WP_STATUS))
+
+/* It has all 0xff chars */
+#define MAX_ONENAND_PAGESIZE           (2048 + 64)
+static unsigned char *ffchars;
+
+static struct mtd_partition os_partitions[] = {
+       {
+               .name           = "OneNAND simulator partition",
+               .offset         = 0,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+/*
+ * OneNAND simulator mtd
+ */
+struct onenand_info {
+       struct mtd_info         mtd;
+       struct mtd_partition    *parts;
+       struct onenand_chip     onenand;
+       struct onenand_flash    flash;
+};
+
+static struct onenand_info *info;
+
+#define DPRINTK(format, args...)                                       \
+do {                                                                   \
+       printk(KERN_DEBUG "%s[%d]: " format "\n", __func__,             \
+                          __LINE__, ##args);                           \
+} while (0)
+
+/**
+ * onenand_lock_handle - Handle Lock scheme
+ * @param this         OneNAND device structure
+ * @param cmd          The command to be sent
+ *
+ * Send lock command to OneNAND device.
+ * The lock scheme is depends on chip type.
+ */
+static void onenand_lock_handle(struct onenand_chip *this, int cmd)
+{
+       int block_lock_scheme;
+       int status;
+
+       status = ONENAND_GET_WP_STATUS(this);
+       block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK);
+
+       switch (cmd) {
+       case ONENAND_CMD_UNLOCK:
+               if (block_lock_scheme)
+                       ONENAND_SET_WP_STATUS(ONENAND_WP_US, this);
+               else
+                       ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this);
+               break;
+
+       case ONENAND_CMD_LOCK:
+               if (block_lock_scheme)
+                       ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this);
+               else
+                       ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this);
+               break;
+
+       case ONENAND_CMD_LOCK_TIGHT:
+               if (block_lock_scheme)
+                       ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this);
+               else
+                       ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/**
+ * onenand_bootram_handle - Handle BootRAM area
+ * @param this         OneNAND device structure
+ * @param cmd          The command to be sent
+ *
+ * Emulate BootRAM area. It is possible to do basic operation using BootRAM.
+ */
+static void onenand_bootram_handle(struct onenand_chip *this, int cmd)
+{
+       switch (cmd) {
+       case ONENAND_CMD_READID:
+               writew(manuf_id, this->base);
+               writew(device_id, this->base + 2);
+               writew(version_id, this->base + 4);
+               break;
+
+       default:
+               /* REVIST: Handle other commands */
+               break;
+       }
+}
+
+/**
+ * onenand_update_interrupt - Set interrupt register
+ * @param this         OneNAND device structure
+ * @param cmd          The command to be sent
+ *
+ * Update interrupt register. The status is depends on command.
+ */
+static void onenand_update_interrupt(struct onenand_chip *this, int cmd)
+{
+       int interrupt = ONENAND_INT_MASTER;
+
+       switch (cmd) {
+       case ONENAND_CMD_READ:
+       case ONENAND_CMD_READOOB:
+               interrupt |= ONENAND_INT_READ;
+               break;
+
+       case ONENAND_CMD_PROG:
+       case ONENAND_CMD_PROGOOB:
+               interrupt |= ONENAND_INT_WRITE;
+               break;
+
+       case ONENAND_CMD_ERASE:
+               interrupt |= ONENAND_INT_ERASE;
+               break;
+
+       case ONENAND_CMD_RESET:
+               interrupt |= ONENAND_INT_RESET;
+               break;
+
+       default:
+               break;
+       }
+
+       writew(interrupt, this->base + ONENAND_REG_INTERRUPT);
+}
+
+/**
+ * onenand_check_overwrite - Check over-write if happend
+ * @param dest         The destination pointer
+ * @param src          The source pointer
+ * @param count                The length to be check
+ * @return             0 on same, otherwise 1
+ *
+ * Compare the source with destination
+ */
+static int onenand_check_overwrite(void *dest, void *src, size_t count)
+{
+       unsigned int *s = (unsigned int *) src;
+       unsigned int *d = (unsigned int *) dest;
+       int i;
+
+       count >>= 2;
+       for (i = 0; i < count; i++)
+               if ((*s++ ^ *d++) != 0)
+                       return 1;
+
+       return 0;
+}
+
+/**
+ * onenand_data_handle - Handle OneNAND Core and DataRAM
+ * @param this         OneNAND device structure
+ * @param cmd          The command to be sent
+ * @param dataram      Which dataram used
+ * @param offset       The offset to OneNAND Core
+ *
+ * Copy data from OneNAND Core to DataRAM (read)
+ * Copy data from DataRAM to OneNAND Core (write)
+ * Erase the OneNAND Core (erase)
+ */
+static void onenand_data_handle(struct onenand_chip *this, int cmd,
+                               int dataram, unsigned int offset)
+{
+       struct mtd_info *mtd = &info->mtd;
+       struct onenand_flash *flash = this->priv;
+       int main_offset, spare_offset;
+       void __iomem *src;
+       void __iomem *dest;
+       unsigned int i;
+
+       if (dataram) {
+               main_offset = mtd->writesize;
+               spare_offset = mtd->oobsize;
+       } else {
+               main_offset = 0;
+               spare_offset = 0;
+       }
+
+       switch (cmd) {
+       case ONENAND_CMD_READ:
+               src = ONENAND_CORE(flash) + offset;
+               dest = ONENAND_MAIN_AREA(this, main_offset);
+               memcpy(dest, src, mtd->writesize);
+               /* Fall through */
+
+       case ONENAND_CMD_READOOB:
+               src = ONENAND_CORE_SPARE(flash, this, offset);
+               dest = ONENAND_SPARE_AREA(this, spare_offset);
+               memcpy(dest, src, mtd->oobsize);
+               break;
+
+       case ONENAND_CMD_PROG:
+               src = ONENAND_MAIN_AREA(this, main_offset);
+               dest = ONENAND_CORE(flash) + offset;
+               /* To handle partial write */
+               for (i = 0; i < (1 << mtd->subpage_sft); i++) {
+                       int off = i * this->subpagesize;
+                       if (!memcmp(src + off, ffchars, this->subpagesize))
+                               continue;
+                       if (memcmp(dest + off, ffchars, this->subpagesize) &&
+                           onenand_check_overwrite(dest + off, src + off, this->subpagesize))
+                               printk(KERN_ERR "over-write happend at 0x%08x\n", offset);
+                       memcpy(dest + off, src + off, this->subpagesize);
+               }
+               /* Fall through */
+
+       case ONENAND_CMD_PROGOOB:
+               src = ONENAND_SPARE_AREA(this, spare_offset);
+               /* Check all data is 0xff chars */
+               if (!memcmp(src, ffchars, mtd->oobsize))
+                       break;
+
+               dest = ONENAND_CORE_SPARE(flash, this, offset);
+               if (memcmp(dest, ffchars, mtd->oobsize) &&
+                   onenand_check_overwrite(dest, src, mtd->oobsize))
+                       printk(KERN_ERR "OOB: over-write happend at 0x%08x\n",
+                              offset);
+               memcpy(dest, src, mtd->oobsize);
+               break;
+
+       case ONENAND_CMD_ERASE:
+               memset(ONENAND_CORE(flash) + offset, 0xff, mtd->erasesize);
+               memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff,
+                      (mtd->erasesize >> 5));
+               break;
+
+       default:
+               break;
+       }
+}
+
+/**
+ * onenand_command_handle - Handle command
+ * @param this         OneNAND device structure
+ * @param cmd          The command to be sent
+ *
+ * Emulate OneNAND command.
+ */
+static void onenand_command_handle(struct onenand_chip *this, int cmd)
+{
+       unsigned long offset = 0;
+       int block = -1, page = -1, bufferram = -1;
+       int dataram = 0;
+
+       switch (cmd) {
+       case ONENAND_CMD_UNLOCK:
+       case ONENAND_CMD_LOCK:
+       case ONENAND_CMD_LOCK_TIGHT:
+       case ONENAND_CMD_UNLOCK_ALL:
+               onenand_lock_handle(this, cmd);
+               break;
+
+       case ONENAND_CMD_BUFFERRAM:
+               /* Do nothing */
+               return;
+
+       default:
+               block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1);
+               if (block & (1 << ONENAND_DDP_SHIFT)) {
+                       block &= ~(1 << ONENAND_DDP_SHIFT);
+                       /* The half of chip block */
+                       block += this->chipsize >> (this->erase_shift + 1);
+               }
+               if (cmd == ONENAND_CMD_ERASE)
+                       break;
+
+               page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8);
+               page = (page >> ONENAND_FPA_SHIFT);
+               bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER);
+               bufferram >>= ONENAND_BSA_SHIFT;
+               bufferram &= ONENAND_BSA_DATARAM1;
+               dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0;
+               break;
+       }
+
+       if (block != -1)
+               offset += block << this->erase_shift;
+
+       if (page != -1)
+               offset += page << this->page_shift;
+
+       onenand_data_handle(this, cmd, dataram, offset);
+
+       onenand_update_interrupt(this, cmd);
+}
+
+/**
+ * onenand_writew - [OneNAND Interface] Emulate write operation
+ * @param value                value to write
+ * @param addr         address to write
+ *
+ * Write OneNAND register with value
+ */
+static void onenand_writew(unsigned short value, void __iomem * addr)
+{
+       struct onenand_chip *this = info->mtd.priv;
+
+       /* BootRAM handling */
+       if (addr < this->base + ONENAND_DATARAM) {
+               onenand_bootram_handle(this, value);
+               return;
+       }
+       /* Command handling */
+       if (addr == this->base + ONENAND_REG_COMMAND)
+               onenand_command_handle(this, value);
+
+       writew(value, addr);
+}
+
+/**
+ * flash_init - Initialize OneNAND simulator
+ * @param flash                OneNAND simulaotr data strucutres
+ *
+ * Initialize OneNAND simulator.
+ */
+static int __init flash_init(struct onenand_flash *flash)
+{
+       int density, size;
+       int buffer_size;
+
+       flash->base = kzalloc(131072, GFP_KERNEL);
+       if (!flash->base) {
+               printk(KERN_ERR "Unable to allocate base address.\n");
+               return -ENOMEM;
+       }
+
+       density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       size = ((16 << 20) << density);
+
+       ONENAND_CORE(flash) = vmalloc(size + (size >> 5));
+       if (!ONENAND_CORE(flash)) {
+               printk(KERN_ERR "Unable to allocate nand core address.\n");
+               kfree(flash->base);
+               return -ENOMEM;
+       }
+
+       memset(ONENAND_CORE(flash), 0xff, size + (size >> 5));
+
+       /* Setup registers */
+       writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID);
+       writew(device_id, flash->base + ONENAND_REG_DEVICE_ID);
+       writew(version_id, flash->base + ONENAND_REG_VERSION_ID);
+
+       if (density < 2)
+               buffer_size = 0x0400;   /* 1KiB page */
+       else
+               buffer_size = 0x0800;   /* 2KiB page */
+       writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE);
+
+       return 0;
+}
+
+/**
+ * flash_exit - Clean up OneNAND simulator
+ * @param flash                OneNAND simulaotr data strucutres
+ *
+ * Clean up OneNAND simulator.
+ */
+static void flash_exit(struct onenand_flash *flash)
+{
+       vfree(ONENAND_CORE(flash));
+       kfree(flash->base);
+       kfree(flash);
+}
+
+static int __init onenand_sim_init(void)
+{
+       /* Allocate all 0xff chars pointer */
+       ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL);
+       if (!ffchars) {
+               printk(KERN_ERR "Unable to allocate ff chars.\n");
+               return -ENOMEM;
+       }
+       memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE);
+
+       /* Allocate OneNAND simulator mtd pointer */
+       info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
+       if (!info) {
+               printk(KERN_ERR "Unable to allocate core structures.\n");
+               kfree(ffchars);
+               return -ENOMEM;
+       }
+
+       /* Override write_word function */
+       info->onenand.write_word = onenand_writew;
+
+       if (flash_init(&info->flash)) {
+               printk(KERN_ERR "Unable to allocat flash.\n");
+               kfree(ffchars);
+               kfree(info);
+               return -ENOMEM;
+       }
+
+       info->parts = os_partitions;
+
+       info->onenand.base = info->flash.base;
+       info->onenand.priv = &info->flash;
+
+       info->mtd.name = "OneNAND simulator";
+       info->mtd.priv = &info->onenand;
+       info->mtd.owner = THIS_MODULE;
+
+       if (onenand_scan(&info->mtd, 1)) {
+               flash_exit(&info->flash);
+               kfree(ffchars);
+               kfree(info);
+               return -ENXIO;
+       }
+
+       add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions));
+
+       return 0;
+}
+
+static void __exit onenand_sim_exit(void)
+{
+       struct onenand_chip *this = info->mtd.priv;
+       struct onenand_flash *flash = this->priv;
+
+       onenand_release(&info->mtd);
+       flash_exit(flash);
+       kfree(ffchars);
+       kfree(info);
+}
+
+module_init(onenand_sim_init);
+module_exit(onenand_sim_exit);
+
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("The OneNAND flash simulator");
+MODULE_LICENSE("GPL");
index 006c03aacb55d1241fc99cae8420c7b8383dda3d..823fba4e6d2fa99c5c5ea2049edd820c9fda1c5c 100644 (file)
@@ -779,10 +779,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        else {
                if (!mtd->erasesize) {
                        printk(KERN_WARNING PREFIX "please provide block_size");
-                       kfree(part);
-                       return;
-               }
-               else
+                       goto out;
+               } else
                        part->block_size = mtd->erasesize;
        }
 
@@ -804,7 +802,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
                if (!add_mtd_blktrans_dev((void*)part))
                        return;
        }
-
+out:
        kfree(part);
 }
 
index 1cb22bfae75066f31ee73ef9385b801f36e6b01d..023653977a1ad762ecf1bc371d6b68fc328211fe 100644 (file)
@@ -565,7 +565,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
                }
 
        ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
-                                                     GFP_KERNEL);
+                                                    GFP_KERNEL);
        if (!ubi) {
                err = -ENOMEM;
                goto out_mtd;
@@ -583,6 +583,22 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
        if (err)
                goto out_free;
 
+       mutex_init(&ubi->buf_mutex);
+       ubi->peb_buf1 = vmalloc(ubi->peb_size);
+       if (!ubi->peb_buf1)
+               goto out_free;
+
+       ubi->peb_buf2 = vmalloc(ubi->peb_size);
+       if (!ubi->peb_buf2)
+                goto out_free;
+
+#ifdef CONFIG_MTD_UBI_DEBUG
+       mutex_init(&ubi->dbg_buf_mutex);
+       ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
+       if (!ubi->dbg_peb_buf)
+                goto out_free;
+#endif
+
        err = attach_by_scanning(ubi);
        if (err) {
                dbg_err("failed to attach by scanning, error %d", err);
@@ -630,6 +646,11 @@ out_detach:
        ubi_wl_close(ubi);
        vfree(ubi->vtbl);
 out_free:
+       vfree(ubi->peb_buf1);
+       vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+       vfree(ubi->dbg_peb_buf);
+#endif
        kfree(ubi);
 out_mtd:
        put_mtd_device(mtd);
@@ -651,6 +672,11 @@ static void detach_mtd_dev(struct ubi_device *ubi)
        ubi_wl_close(ubi);
        vfree(ubi->vtbl);
        put_mtd_device(ubi->mtd);
+       vfree(ubi->peb_buf1);
+       vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+       vfree(ubi->dbg_peb_buf);
+#endif
        kfree(ubi_devices[ubi_num]);
        ubi_devices[ubi_num] = NULL;
        ubi_devices_cnt -= 1;
index 310341e5cd43065b8e5e3df1a7afefd56a161a67..56956ec2845ff70bf4139f08ba56184487005816 100644 (file)
@@ -42,7 +42,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
        dbg_msg("data_offset    %d",    be32_to_cpu(ec_hdr->data_offset));
        dbg_msg("hdr_crc        %#08x", be32_to_cpu(ec_hdr->hdr_crc));
        dbg_msg("erase counter header hexdump:");
-       ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
+       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+                      ec_hdr, UBI_EC_HDR_SIZE, 1);
 }
 
 /**
@@ -187,38 +188,4 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
        dbg_msg("the 1st 16 characters of the name: %s", nm);
 }
 
-#define BYTES_PER_LINE 32
-
-/**
- * ubi_dbg_hexdump - dump a buffer.
- * @ptr: the buffer to dump
- * @size: buffer size which must be multiple of 4 bytes
- */
-void ubi_dbg_hexdump(const void *ptr, int size)
-{
-       int i, k = 0, rows, columns;
-       const uint8_t *p = ptr;
-
-       size = ALIGN(size, 4);
-       rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE;
-       for (i = 0; i < rows; i++) {
-               int j;
-
-               cond_resched();
-               columns = min(size - k, BYTES_PER_LINE) / 4;
-               if (columns == 0)
-                       break;
-               printk(KERN_DEBUG "%5d:  ", i * BYTES_PER_LINE);
-               for (j = 0; j < columns; j++) {
-                       int n, N;
-
-                       N = size - k > 4 ? 4 : size - k;
-                       for (n = 0; n < N; n++)
-                               printk("%02x", p[k++]);
-                       printk(" ");
-               }
-               printk("\n");
-       }
-}
-
 #endif /* CONFIG_MTD_UBI_DEBUG_MSG */
index ff8f39548cd80aaf58cb979d291e609f4d80f214..467722eb618b20a384320e4bee15be409f2f5e77 100644 (file)
@@ -59,7 +59,6 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
 void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
 void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
 void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
-void ubi_dbg_hexdump(const void *buf, int size);
 
 #else
 
@@ -72,7 +71,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
 #define ubi_dbg_dump_sv(sv)              ({})
 #define ubi_dbg_dump_seb(seb, type)      ({})
 #define ubi_dbg_dump_mkvol_req(req)      ({})
-#define ubi_dbg_hexdump(buf, size)       ({})
 
 #endif /* CONFIG_MTD_UBI_DEBUG_MSG */
 
index 7c5e29eaf1180737341e49be803515a8f41c3c33..1297732f4db95c4275e9f3f78b81345d48787572 100644 (file)
@@ -46,6 +46,9 @@
 #include <linux/err.h>
 #include "ubi.h"
 
+/* Number of physical eraseblocks reserved for atomic LEB change operation */
+#define EBA_RESERVED_PEBS 1
+
 /**
  * struct ltree_entry - an entry in the lock tree.
  * @rb: links RB-tree nodes
@@ -157,7 +160,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
 {
        struct ltree_entry *le, *le1, *le_free;
 
-       le = kmem_cache_alloc(ltree_slab, GFP_KERNEL);
+       le = kmem_cache_alloc(ltree_slab, GFP_NOFS);
        if (!le)
                return ERR_PTR(-ENOMEM);
 
@@ -397,7 +400,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
 
 retry:
        if (check) {
-               vid_hdr = ubi_zalloc_vid_hdr(ubi);
+               vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
                if (!vid_hdr) {
                        err = -ENOMEM;
                        goto out_unlock;
@@ -495,16 +498,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
        int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
        struct ubi_volume *vol = ubi->volumes[idx];
        struct ubi_vid_hdr *vid_hdr;
-       unsigned char *new_buf;
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi);
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr) {
                return -ENOMEM;
        }
 
+       mutex_lock(&ubi->buf_mutex);
+
 retry:
        new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
        if (new_pnum < 0) {
+               mutex_unlock(&ubi->buf_mutex);
                ubi_free_vid_hdr(ubi, vid_hdr);
                return new_pnum;
        }
@@ -524,31 +529,22 @@ retry:
                goto write_error;
 
        data_size = offset + len;
-       new_buf = vmalloc(data_size);
-       if (!new_buf) {
-               err = -ENOMEM;
-               goto out_put;
-       }
-       memset(new_buf + offset, 0xFF, len);
+       memset(ubi->peb_buf1 + offset, 0xFF, len);
 
        /* Read everything before the area where the write failure happened */
        if (offset > 0) {
-               err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
-               if (err && err != UBI_IO_BITFLIPS) {
-                       vfree(new_buf);
+               err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
+               if (err && err != UBI_IO_BITFLIPS)
                        goto out_put;
-               }
        }
 
-       memcpy(new_buf + offset, buf, len);
+       memcpy(ubi->peb_buf1 + offset, buf, len);
 
-       err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
-       if (err) {
-               vfree(new_buf);
+       err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
+       if (err)
                goto write_error;
-       }
 
-       vfree(new_buf);
+       mutex_unlock(&ubi->buf_mutex);
        ubi_free_vid_hdr(ubi, vid_hdr);
 
        vol->eba_tbl[lnum] = new_pnum;
@@ -558,6 +554,7 @@ retry:
        return 0;
 
 out_put:
+       mutex_unlock(&ubi->buf_mutex);
        ubi_wl_put_peb(ubi, new_pnum, 1);
        ubi_free_vid_hdr(ubi, vid_hdr);
        return err;
@@ -570,6 +567,7 @@ write_error:
        ubi_warn("failed to write to PEB %d", new_pnum);
        ubi_wl_put_peb(ubi, new_pnum, 1);
        if (++tries > UBI_IO_RETRIES) {
+               mutex_unlock(&ubi->buf_mutex);
                ubi_free_vid_hdr(ubi, vid_hdr);
                return err;
        }
@@ -627,7 +625,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
         * The logical eraseblock is not mapped. We have to get a free physical
         * eraseblock and write the volume identifier header there first.
         */
-       vid_hdr = ubi_zalloc_vid_hdr(ubi);
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr) {
                leb_write_unlock(ubi, vol_id, lnum);
                return -ENOMEM;
@@ -738,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
        else
                ubi_assert(len % ubi->min_io_size == 0);
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi);
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
                return -ENOMEM;
 
@@ -832,6 +830,9 @@ write_error:
  * data, which has to be aligned. This function guarantees that in case of an
  * unclean reboot the old contents is preserved. Returns zero in case of
  * success and a negative error code in case of failure.
+ *
+ * UBI reserves one LEB for the "atomic LEB change" operation, so only one
+ * LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
  */
 int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
                              const void *buf, int len, int dtype)
@@ -844,15 +845,14 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
        if (ubi->ro_mode)
                return -EROFS;
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi);
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
                return -ENOMEM;
 
+       mutex_lock(&ubi->alc_mutex);
        err = leb_write_lock(ubi, vol_id, lnum);
-       if (err) {
-               ubi_free_vid_hdr(ubi, vid_hdr);
-               return err;
-       }
+       if (err)
+               goto out_mutex;
 
        vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        vid_hdr->vol_id = cpu_to_be32(vol_id);
@@ -869,9 +869,8 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
 retry:
        pnum = ubi_wl_get_peb(ubi, dtype);
        if (pnum < 0) {
-               ubi_free_vid_hdr(ubi, vid_hdr);
-               leb_write_unlock(ubi, vol_id, lnum);
-               return pnum;
+               err = pnum;
+               goto out_leb_unlock;
        }
 
        dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
@@ -893,17 +892,18 @@ retry:
 
        if (vol->eba_tbl[lnum] >= 0) {
                err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
-               if (err) {
-                       ubi_free_vid_hdr(ubi, vid_hdr);
-                       leb_write_unlock(ubi, vol_id, lnum);
-                       return err;
-               }
+               if (err)
+                       goto out_leb_unlock;
        }
 
        vol->eba_tbl[lnum] = pnum;
+
+out_leb_unlock:
        leb_write_unlock(ubi, vol_id, lnum);
+out_mutex:
+       mutex_unlock(&ubi->alc_mutex);
        ubi_free_vid_hdr(ubi, vid_hdr);
-       return 0;
+       return err;
 
 write_error:
        if (err != -EIO || !ubi->bad_allowed) {
@@ -913,17 +913,13 @@ write_error:
                 * mode just in case.
                 */
                ubi_ro_mode(ubi);
-               leb_write_unlock(ubi, vol_id, lnum);
-               ubi_free_vid_hdr(ubi, vid_hdr);
-               return err;
+               goto out_leb_unlock;
        }
 
        err = ubi_wl_put_peb(ubi, pnum, 1);
        if (err || ++tries > UBI_IO_RETRIES) {
                ubi_ro_mode(ubi);
-               leb_write_unlock(ubi, vol_id, lnum);
-               ubi_free_vid_hdr(ubi, vid_hdr);
-               return err;
+               goto out_leb_unlock;
        }
 
        vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
@@ -965,7 +961,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        int err, vol_id, lnum, data_size, aldata_size, pnum, idx;
        struct ubi_volume *vol;
        uint32_t crc;
-       void *buf, *buf1 = NULL;
 
        vol_id = be32_to_cpu(vid_hdr->vol_id);
        lnum = be32_to_cpu(vid_hdr->lnum);
@@ -979,19 +974,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                data_size = aldata_size =
                            ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
 
-       buf = vmalloc(aldata_size);
-       if (!buf)
-               return -ENOMEM;
-
        /*
         * We do not want anybody to write to this logical eraseblock while we
         * are moving it, so we lock it.
         */
        err = leb_write_lock(ubi, vol_id, lnum);
-       if (err) {
-               vfree(buf);
+       if (err)
                return err;
-       }
+
+       mutex_lock(&ubi->buf_mutex);
 
        /*
         * But the logical eraseblock might have been put by this time.
@@ -1023,7 +1014,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        /* OK, now the LEB is locked and we can safely start moving it */
 
        dbg_eba("read %d bytes of data", aldata_size);
-       err = ubi_io_read_data(ubi, buf, from, 0, aldata_size);
+       err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
        if (err && err != UBI_IO_BITFLIPS) {
                ubi_warn("error %d while reading data from PEB %d",
                         err, from);
@@ -1042,10 +1033,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         */
        if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
                aldata_size = data_size =
-                               ubi_calc_data_len(ubi, buf, data_size);
+                       ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
 
        cond_resched();
-       crc = crc32(UBI_CRC32_INIT, buf, data_size);
+       crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
        cond_resched();
 
        /*
@@ -1076,23 +1067,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        }
 
        if (data_size > 0) {
-               err = ubi_io_write_data(ubi, buf, to, 0, aldata_size);
+               err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
                if (err)
                        goto out_unlock;
 
+               cond_resched();
+
                /*
                 * We've written the data and are going to read it back to make
                 * sure it was written correctly.
                 */
-               buf1 = vmalloc(aldata_size);
-               if (!buf1) {
-                       err = -ENOMEM;
-                       goto out_unlock;
-               }
-
-               cond_resched();
 
-               err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size);
+               err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
                if (err) {
                        if (err != UBI_IO_BITFLIPS)
                                ubi_warn("cannot read data back from PEB %d",
@@ -1102,7 +1088,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 
                cond_resched();
 
-               if (memcmp(buf, buf1, aldata_size)) {
+               if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
                        ubi_warn("read data back from PEB %d - it is different",
                                 to);
                        goto out_unlock;
@@ -1112,16 +1098,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        ubi_assert(vol->eba_tbl[lnum] == from);
        vol->eba_tbl[lnum] = to;
 
-       leb_write_unlock(ubi, vol_id, lnum);
-       vfree(buf);
-       vfree(buf1);
-
-       return 0;
-
 out_unlock:
+       mutex_unlock(&ubi->buf_mutex);
        leb_write_unlock(ubi, vol_id, lnum);
-       vfree(buf);
-       vfree(buf1);
        return err;
 }
 
@@ -1144,6 +1123,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        dbg_eba("initialize EBA unit");
 
        spin_lock_init(&ubi->ltree_lock);
+       mutex_init(&ubi->alc_mutex);
        ubi->ltree = RB_ROOT;
 
        if (ubi_devices_cnt == 0) {
@@ -1205,6 +1185,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                ubi->rsvd_pebs  += ubi->beb_rsvd_pebs;
        }
 
+       if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
+               ubi_err("no enough physical eraseblocks (%d, need %d)",
+                       ubi->avail_pebs, EBA_RESERVED_PEBS);
+               err = -ENOSPC;
+               goto out_free;
+       }
+       ubi->avail_pebs -= EBA_RESERVED_PEBS;
+       ubi->rsvd_pebs += EBA_RESERVED_PEBS;
+
        dbg_eba("EBA unit is initialized");
        return 0;
 
index b0d8f4cede97ebdca9eeafd5f8808ecb8835b55b..7c304eec78b59ba8142a411a96ab4d925760052f 100644 (file)
@@ -98,8 +98,8 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
 static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
 static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
                                  const struct ubi_vid_hdr *vid_hdr);
-static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
-                                int offset, int len);
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+                                int len);
 #else
 #define paranoid_check_not_bad(ubi, pnum) 0
 #define paranoid_check_peb_ec_hdr(ubi, pnum)  0
@@ -202,8 +202,8 @@ retry:
  * Note, in case of an error, it is possible that something was still written
  * to the flash media, but may be some garbage.
  */
-int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
-                int offset, int len)
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+                int len)
 {
        int err;
        size_t written;
@@ -285,7 +285,7 @@ static void erase_callback(struct erase_info *ei)
  * zero in case of success and a negative error code in case of failure. If
  * %-EIO is returned, the physical eraseblock most probably went bad.
  */
-static int do_sync_erase(const struct ubi_device *ubi, int pnum)
+static int do_sync_erase(struct ubi_device *ubi, int pnum)
 {
        int err, retries = 0;
        struct erase_info ei;
@@ -377,29 +377,25 @@ static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
  * test, a positive number of erase operations done if the test was
  * successfully passed, and other negative error codes in case of other errors.
  */
-static int torture_peb(const struct ubi_device *ubi, int pnum)
+static int torture_peb(struct ubi_device *ubi, int pnum)
 {
-       void *buf;
        int err, i, patt_count;
 
-       buf = vmalloc(ubi->peb_size);
-       if (!buf)
-               return -ENOMEM;
-
        patt_count = ARRAY_SIZE(patterns);
        ubi_assert(patt_count > 0);
 
+       mutex_lock(&ubi->buf_mutex);
        for (i = 0; i < patt_count; i++) {
                err = do_sync_erase(ubi, pnum);
                if (err)
                        goto out;
 
                /* Make sure the PEB contains only 0xFF bytes */
-               err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+               err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
                if (err)
                        goto out;
 
-               err = check_pattern(buf, 0xFF, ubi->peb_size);
+               err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
                if (err == 0) {
                        ubi_err("erased PEB %d, but a non-0xFF byte found",
                                pnum);
@@ -408,17 +404,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
                }
 
                /* Write a pattern and check it */
-               memset(buf, patterns[i], ubi->peb_size);
-               err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size);
+               memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
+               err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
                if (err)
                        goto out;
 
-               memset(buf, ~patterns[i], ubi->peb_size);
-               err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+               memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
+               err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
                if (err)
                        goto out;
 
-               err = check_pattern(buf, patterns[i], ubi->peb_size);
+               err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size);
                if (err == 0) {
                        ubi_err("pattern %x checking failed for PEB %d",
                                patterns[i], pnum);
@@ -430,14 +426,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
        err = patt_count;
 
 out:
-       if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+       mutex_unlock(&ubi->buf_mutex);
+       if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
                /*
                 * If a bit-flip or data integrity error was detected, the test
                 * has not passed because it happened on a freshly erased
                 * physical eraseblock which means something is wrong with it.
                 */
+               ubi_err("read problems on freshly erased PEB %d, must be bad",
+                       pnum);
                err = -EIO;
-       vfree(buf);
+       }
        return err;
 }
 
@@ -457,7 +456,7 @@ out:
  * codes in case of other errors. Note, %-EIO means that the physical
  * eraseblock is bad.
  */
-int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture)
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
 {
        int err, ret = 0;
 
@@ -614,7 +613,7 @@ bad:
  * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
  * o a negative error code in case of failure.
  */
-int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                       struct ubi_ec_hdr *ec_hdr, int verbose)
 {
        int err, read_err = 0;
@@ -720,7 +719,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
  * case of failure. If %-EIO is returned, the physical eraseblock most probably
  * went bad.
  */
-int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
                        struct ubi_ec_hdr *ec_hdr)
 {
        int err;
@@ -886,7 +885,7 @@ bad:
  *   header there);
  * o a negative error code in case of failure.
  */
-int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                        struct ubi_vid_hdr *vid_hdr, int verbose)
 {
        int err, read_err = 0;
@@ -993,7 +992,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
  * case of failure. If %-EIO is returned, the physical eraseblock probably went
  * bad.
  */
-int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
                         struct ubi_vid_hdr *vid_hdr)
 {
        int err;
@@ -1096,7 +1095,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
        uint32_t crc, hdr_crc;
        struct ubi_ec_hdr *ec_hdr;
 
-       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
        if (!ec_hdr)
                return -ENOMEM;
 
@@ -1176,7 +1175,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
        struct ubi_vid_hdr *vid_hdr;
        void *p;
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi);
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
                return -ENOMEM;
 
@@ -1216,44 +1215,40 @@ exit:
  * @offset of the physical eraseblock @pnum, %1 if not, and a negative error
  * code if an error occurred.
  */
-static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
-                                int offset, int len)
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+                                int len)
 {
        size_t read;
        int err;
-       void *buf;
        loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-       buf = vmalloc(len);
-       if (!buf)
-               return -ENOMEM;
-       memset(buf, 0, len);
-
-       err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+       mutex_lock(&ubi->dbg_buf_mutex);
+       err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
        if (err && err != -EUCLEAN) {
                ubi_err("error %d while reading %d bytes from PEB %d:%d, "
                        "read %zd bytes", err, len, pnum, offset, read);
                goto error;
        }
 
-       err = check_pattern(buf, 0xFF, len);
+       err = check_pattern(ubi->dbg_peb_buf, 0xFF, len);
        if (err == 0) {
                ubi_err("flash region at PEB %d:%d, length %d does not "
                        "contain all 0xFF bytes", pnum, offset, len);
                goto fail;
        }
+       mutex_unlock(&ubi->dbg_buf_mutex);
 
-       vfree(buf);
        return 0;
 
 fail:
        ubi_err("paranoid check failed for PEB %d", pnum);
        dbg_msg("hex dump of the %d-%d region", offset, offset + len);
-       ubi_dbg_hexdump(buf, len);
+       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+                      ubi->dbg_peb_buf, len, 1);
        err = 1;
 error:
        ubi_dbg_dump_stack();
-       vfree(buf);
+       mutex_unlock(&ubi->dbg_buf_mutex);
        return err;
 }
 
index 4a458e83e4e90ccb1fac426203919c7af2e58b77..03c774f41549c8b2b56cfe5d9f125e00ceea8dd1 100644 (file)
@@ -99,16 +99,21 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
 {
        int err;
        struct ubi_volume_desc *desc;
-       struct ubi_device *ubi = ubi_devices[ubi_num];
+       struct ubi_device *ubi;
        struct ubi_volume *vol;
 
        dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
 
        err = -ENODEV;
+       if (ubi_num < 0)
+               return ERR_PTR(err);
+
+       ubi = ubi_devices[ubi_num];
+
        if (!try_module_get(THIS_MODULE))
                return ERR_PTR(err);
 
-       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi)
+       if (ubi_num >= UBI_MAX_DEVICES || !ubi)
                goto out_put;
 
        err = -EINVAL;
index 94ee549344118987e2e2a73ded2c13fc00a1f2f0..c7b0afc9d2808e13b64ce2fae7d6755b2c99041e 100644 (file)
@@ -45,8 +45,7 @@
 #include "ubi.h"
 
 #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
-static int paranoid_check_si(const struct ubi_device *ubi,
-                            struct ubi_scan_info *si);
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
 #else
 #define paranoid_check_si(ubi, si) 0
 #endif
@@ -259,14 +258,13 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
  *     o bit 2 is cleared: the older LEB is not corrupted;
  *     o bit 2 is set: the older LEB is corrupted.
  */
-static int compare_lebs(const struct ubi_device *ubi,
-                       const struct ubi_scan_leb *seb, int pnum,
-                       const struct ubi_vid_hdr *vid_hdr)
+static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
+                       int pnum, const struct ubi_vid_hdr *vid_hdr)
 {
        void *buf;
        int len, err, second_is_newer, bitflips = 0, corrupted = 0;
        uint32_t data_crc, crc;
-       struct ubi_vid_hdr *vidh = NULL;
+       struct ubi_vid_hdr *vh = NULL;
        unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
 
        if (seb->sqnum == 0 && sqnum2 == 0) {
@@ -323,11 +321,11 @@ static int compare_lebs(const struct ubi_device *ubi,
        } else {
                pnum = seb->pnum;
 
-               vidh = ubi_zalloc_vid_hdr(ubi);
-               if (!vidh)
+               vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+               if (!vh)
                        return -ENOMEM;
 
-               err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
+               err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
                if (err) {
                        if (err == UBI_IO_BITFLIPS)
                                bitflips = 1;
@@ -341,7 +339,7 @@ static int compare_lebs(const struct ubi_device *ubi,
                        }
                }
 
-               if (!vidh->copy_flag) {
+               if (!vh->copy_flag) {
                        /* It is not a copy, so it is newer */
                        dbg_bld("first PEB %d is newer, copy_flag is unset",
                                pnum);
@@ -349,7 +347,7 @@ static int compare_lebs(const struct ubi_device *ubi,
                        goto out_free_vidh;
                }
 
-               vid_hdr = vidh;
+               vid_hdr = vh;
        }
 
        /* Read the data of the copy and check the CRC */
@@ -379,7 +377,7 @@ static int compare_lebs(const struct ubi_device *ubi,
        }
 
        vfree(buf);
-       ubi_free_vid_hdr(ubi, vidh);
+       ubi_free_vid_hdr(ubi, vh);
 
        if (second_is_newer)
                dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
@@ -391,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
 out_free_buf:
        vfree(buf);
 out_free_vidh:
-       ubi_free_vid_hdr(ubi, vidh);
+       ubi_free_vid_hdr(ubi, vh);
        ubi_assert(err < 0);
        return err;
 }
@@ -413,7 +411,7 @@ out_free_vidh:
  * to be picked, while the older one has to be dropped. This function returns
  * zero in case of success and a negative error code in case of failure.
  */
-int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
                      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
                      int bitflips)
 {
@@ -667,16 +665,12 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
  * function returns zero in case of success and a negative error code in case
  * of failure.
  */
-int ubi_scan_erase_peb(const struct ubi_device *ubi,
-                      const struct ubi_scan_info *si, int pnum, int ec)
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+                      int pnum, int ec)
 {
        int err;
        struct ubi_ec_hdr *ec_hdr;
 
-       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
-       if (!ec_hdr)
-               return -ENOMEM;
-
        if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
                /*
                 * Erase counter overflow. Upgrade UBI and use 64-bit
@@ -686,6 +680,10 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
                return -EINVAL;
        }
 
+       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+       if (!ec_hdr)
+               return -ENOMEM;
+
        ec_hdr->ec = cpu_to_be64(ec);
 
        err = ubi_io_sync_erase(ubi, pnum, 0);
@@ -712,7 +710,7 @@ out_free:
  * This function returns scanning physical eraseblock information in case of
  * success and an error code in case of failure.
  */
-struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
                                           struct ubi_scan_info *si)
 {
        int err = 0, i;
@@ -948,7 +946,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
        if (!ech)
                goto out_si;
 
-       vidh = ubi_zalloc_vid_hdr(ubi);
+       vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
        if (!vidh)
                goto out_ech;
 
@@ -1110,8 +1108,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
  * This function returns zero if the scanning information is all right, %1 if
  * not and a negative error code if an error occurred.
  */
-static int paranoid_check_si(const struct ubi_device *ubi,
-                            struct ubi_scan_info *si)
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
 {
        int pnum, err, vols_found = 0;
        struct rb_node *rb1, *rb2;
@@ -1314,11 +1311,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
         * Make sure that all the physical eraseblocks are in one of the lists
         * or trees.
         */
-       buf = kmalloc(ubi->peb_count, GFP_KERNEL);
+       buf = kzalloc(ubi->peb_count, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       memset(buf, 1, ubi->peb_count);
        for (pnum = 0; pnum < ubi->peb_count; pnum++) {
                err = ubi_io_is_bad(ubi, pnum);
                if (err < 0) {
@@ -1326,28 +1322,28 @@ static int paranoid_check_si(const struct ubi_device *ubi,
                        return err;
                }
                else if (err)
-                       buf[pnum] = 0;
+                       buf[pnum] = 1;
        }
 
        ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
                ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
-                       buf[seb->pnum] = 0;
+                       buf[seb->pnum] = 1;
 
        list_for_each_entry(seb, &si->free, u.list)
-               buf[seb->pnum] = 0;
+               buf[seb->pnum] = 1;
 
        list_for_each_entry(seb, &si->corr, u.list)
-               buf[seb->pnum] = 0;
+               buf[seb->pnum] = 1;
 
        list_for_each_entry(seb, &si->erase, u.list)
-               buf[seb->pnum] = 0;
+               buf[seb->pnum] = 1;
 
        list_for_each_entry(seb, &si->alien, u.list)
-               buf[seb->pnum] = 0;
+               buf[seb->pnum] = 1;
 
        err = 0;
        for (pnum = 0; pnum < ubi->peb_count; pnum++)
-               if (buf[pnum]) {
+               if (!buf[pnum]) {
                        ubi_err("PEB %d is not referred", pnum);
                        err = 1;
                }
index 140e82e265349e7dafc7e6da4ec1e41706d41a1f..46d444af471a24a094fc3c0aa54d76e91dda94bd 100644 (file)
@@ -147,7 +147,7 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
                list_add_tail(&seb->u.list, list);
 }
 
-int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
                      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
                      int bitflips);
 struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
@@ -155,10 +155,10 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
 struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
                                       int lnum);
 void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
-struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
                                           struct ubi_scan_info *si);
-int ubi_scan_erase_peb(const struct ubi_device *ubi,
-                      const struct ubi_scan_info *si, int pnum, int ec);
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+                      int pnum, int ec);
 struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
 void ubi_scan_destroy_si(struct ubi_scan_info *si);
 
index 5959f91be240655b3219a6d6359a060d732aeaf7..5e941a6330303bc36271286a7861c4fdd5f63788 100644 (file)
@@ -221,14 +221,15 @@ struct ubi_wl_entry;
  * @vtbl_slots: how many slots are available in the volume table
  * @vtbl_size: size of the volume table in bytes
  * @vtbl: in-RAM volume table copy
+ * @vtbl_mutex: protects on-flash volume table
  *
  * @max_ec: current highest erase counter value
  * @mean_ec: current mean erase counter value
  *
- * global_sqnum: global sequence number
+ * @global_sqnum: global sequence number
  * @ltree_lock: protects the lock tree and @global_sqnum
  * @ltree: the lock tree
- * @vtbl_mutex: protects on-flash volume table
+ * @alc_mutex: serializes "atomic LEB change" operations
  *
  * @used: RB-tree of used physical eraseblocks
  * @free: RB-tree of free physical eraseblocks
@@ -274,6 +275,12 @@ struct ubi_wl_entry;
  * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
  * not
  * @mtd: MTD device descriptor
+ *
+ * @peb_buf1: a buffer of PEB size used for different purposes
+ * @peb_buf2: another buffer of PEB size used for different purposes
+ * @buf_mutex: proptects @peb_buf1 and @peb_buf2
+ * @dbg_peb_buf:  buffer of PEB size used for debugging
+ * @dbg_buf_mutex: proptects @dbg_peb_buf
  */
 struct ubi_device {
        struct cdev cdev;
@@ -302,6 +309,7 @@ struct ubi_device {
        unsigned long long global_sqnum;
        spinlock_t ltree_lock;
        struct rb_root ltree;
+       struct mutex alc_mutex;
 
        /* Wear-leveling unit's stuff */
        struct rb_root used;
@@ -343,6 +351,14 @@ struct ubi_device {
        int vid_hdr_shift;
        int bad_allowed;
        struct mtd_info *mtd;
+
+       void *peb_buf1;
+       void *peb_buf2;
+       struct mutex buf_mutex;
+#ifdef CONFIG_MTD_UBI_DEBUG
+       void *dbg_peb_buf;
+       struct mutex dbg_buf_mutex;
+#endif
 };
 
 extern struct file_operations ubi_cdev_operations;
@@ -409,18 +425,18 @@ void ubi_wl_close(struct ubi_device *ubi);
 /* io.c */
 int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
                int len);
-int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
-                int offset, int len);
-int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture);
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+                int len);
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
 int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
 int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
-int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                       struct ubi_ec_hdr *ec_hdr, int verbose);
-int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
                        struct ubi_ec_hdr *ec_hdr);
-int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                        struct ubi_vid_hdr *vid_hdr, int verbose);
-int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
                         struct ubi_vid_hdr *vid_hdr);
 
 /*
@@ -439,16 +455,18 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
 /**
  * ubi_zalloc_vid_hdr - allocate a volume identifier header object.
  * @ubi: UBI device description object
+ * @gfp_flags: GFP flags to allocate with
  *
  * This function returns a pointer to the newly allocated and zero-filled
  * volume identifier header object in case of success and %NULL in case of
  * failure.
  */
-static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi)
+static inline struct ubi_vid_hdr *
+ubi_zalloc_vid_hdr(const struct ubi_device *ubi, gfp_t gfp_flags)
 {
        void *vid_hdr;
 
-       vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL);
+       vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags);
        if (!vid_hdr)
                return NULL;
 
@@ -492,7 +510,7 @@ static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf,
  * the beginning of the logical eraseblock, not to the beginning of the
  * physical eraseblock.
  */
-static inline int ubi_io_write_data(const struct ubi_device *ubi, const void *buf,
+static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf,
                                    int pnum, int offset, int len)
 {
        ubi_assert(offset >= 0);
index ea0d5c825ab41034b5dd4b91cfba6ce587680fbe..88629a320c2b191823035fab474f552b79328a75 100644 (file)
@@ -37,21 +37,21 @@ static ssize_t vol_attribute_show(struct device *dev,
                                  struct device_attribute *attr, char *buf);
 
 /* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
-static struct device_attribute vol_reserved_ebs =
+static struct device_attribute attr_vol_reserved_ebs =
        __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_type =
+static struct device_attribute attr_vol_type =
        __ATTR(type, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_name =
+static struct device_attribute attr_vol_name =
        __ATTR(name, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_corrupted =
+static struct device_attribute attr_vol_corrupted =
        __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_alignment =
+static struct device_attribute attr_vol_alignment =
        __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_usable_eb_size =
+static struct device_attribute attr_vol_usable_eb_size =
        __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_data_bytes =
+static struct device_attribute attr_vol_data_bytes =
        __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_upd_marker =
+static struct device_attribute attr_vol_upd_marker =
        __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
 
 /*
@@ -78,23 +78,27 @@ static ssize_t vol_attribute_show(struct device *dev,
                spin_unlock(&vol->ubi->volumes_lock);
                return -ENODEV;
        }
-       if (attr == &vol_reserved_ebs)
+       if (attr == &attr_vol_reserved_ebs)
                ret = sprintf(buf, "%d\n", vol->reserved_pebs);
-       else if (attr == &vol_type) {
+       else if (attr == &attr_vol_type) {
                const char *tp;
-               tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static";
+
+               if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+                       tp = "dynamic";
+               else
+                       tp = "static";
                ret = sprintf(buf, "%s\n", tp);
-       } else if (attr == &vol_name)
+       } else if (attr == &attr_vol_name)
                ret = sprintf(buf, "%s\n", vol->name);
-       else if (attr == &vol_corrupted)
+       else if (attr == &attr_vol_corrupted)
                ret = sprintf(buf, "%d\n", vol->corrupted);
-       else if (attr == &vol_alignment)
+       else if (attr == &attr_vol_alignment)
                ret = sprintf(buf, "%d\n", vol->alignment);
-       else if (attr == &vol_usable_eb_size) {
+       else if (attr == &attr_vol_usable_eb_size) {
                ret = sprintf(buf, "%d\n", vol->usable_leb_size);
-       } else if (attr == &vol_data_bytes)
+       } else if (attr == &attr_vol_data_bytes)
                ret = sprintf(buf, "%lld\n", vol->used_bytes);
-       else if (attr == &vol_upd_marker)
+       else if (attr == &attr_vol_upd_marker)
                ret = sprintf(buf, "%d\n", vol->upd_marker);
        else
                BUG();
@@ -126,28 +130,28 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
 {
        int err;
 
-       err = device_create_file(&vol->dev, &vol_reserved_ebs);
+       err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
        if (err)
                return err;
-       err = device_create_file(&vol->dev, &vol_type);
+       err = device_create_file(&vol->dev, &attr_vol_type);
        if (err)
                return err;
-       err = device_create_file(&vol->dev, &vol_name);
+       err = device_create_file(&vol->dev, &attr_vol_name);
        if (err)
                return err;
-       err = device_create_file(&vol->dev, &vol_corrupted);
+       err = device_create_file(&vol->dev, &attr_vol_corrupted);
        if (err)
                return err;
-       err = device_create_file(&vol->dev, &vol_alignment);
+       err = device_create_file(&vol->dev, &attr_vol_alignment);
        if (err)
                return err;
-       err = device_create_file(&vol->dev, &vol_usable_eb_size);
+       err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
        if (err)
                return err;
-       err = device_create_file(&vol->dev, &vol_data_bytes);
+       err = device_create_file(&vol->dev, &attr_vol_data_bytes);
        if (err)
                return err;
-       err = device_create_file(&vol->dev, &vol_upd_marker);
+       err = device_create_file(&vol->dev, &attr_vol_upd_marker);
        if (err)
                return err;
        return 0;
@@ -159,14 +163,14 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
  */
 static void volume_sysfs_close(struct ubi_volume *vol)
 {
-       device_remove_file(&vol->dev, &vol_upd_marker);
-       device_remove_file(&vol->dev, &vol_data_bytes);
-       device_remove_file(&vol->dev, &vol_usable_eb_size);
-       device_remove_file(&vol->dev, &vol_alignment);
-       device_remove_file(&vol->dev, &vol_corrupted);
-       device_remove_file(&vol->dev, &vol_name);
-       device_remove_file(&vol->dev, &vol_type);
-       device_remove_file(&vol->dev, &vol_reserved_ebs);
+       device_remove_file(&vol->dev, &attr_vol_upd_marker);
+       device_remove_file(&vol->dev, &attr_vol_data_bytes);
+       device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
+       device_remove_file(&vol->dev, &attr_vol_alignment);
+       device_remove_file(&vol->dev, &attr_vol_corrupted);
+       device_remove_file(&vol->dev, &attr_vol_name);
+       device_remove_file(&vol->dev, &attr_vol_type);
+       device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
        device_unregister(&vol->dev);
 }
 
index bc5df50813d67cc2cbd8bd635dbd8e11657cbb8c..25b3bd61c7ecfde59c0912d914ae92fbcdfc60b7 100644 (file)
@@ -254,7 +254,7 @@ bad:
  * This function returns zero in case of success and a negative error code in
  * case of failure.
  */
-static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
+static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
                       int copy, void *vtbl)
 {
        int err, tries = 0;
@@ -264,7 +264,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
 
        ubi_msg("create volume table (copy #%d)", copy + 1);
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi);
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
        if (!vid_hdr)
                return -ENOMEM;
 
@@ -339,7 +339,7 @@ out_free:
  * not corrupted, and recovering from corruptions if needed. Returns volume
  * table in case of success and a negative error code in case of failure.
  */
-static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
+static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
                                            struct ubi_scan_info *si,
                                            struct ubi_scan_volume *sv)
 {
@@ -453,7 +453,7 @@ out_free:
  * This function returns volume table contents in case of success and a
  * negative error code in case of failure.
  */
-static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
+static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
                                                 struct ubi_scan_info *si)
 {
        int i;
index a5a9b8d873025ad5e1ac39fe8c38d377487e5619..a4f1bf33164a1426eb92ea59df1093d856986633 100644 (file)
@@ -208,7 +208,7 @@ struct ubi_work {
 };
 
 #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
-static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec);
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
 static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
                                     struct rb_root *root);
 #else
@@ -219,17 +219,6 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
 /* Slab cache for wear-leveling entries */
 static struct kmem_cache *wl_entries_slab;
 
-/**
- * tree_empty - a helper function to check if an RB-tree is empty.
- * @root: the root of the tree
- *
- * This function returns non-zero if the RB-tree is empty and zero if not.
- */
-static inline int tree_empty(struct rb_root *root)
-{
-       return root->rb_node == NULL;
-}
-
 /**
  * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
  * @e: the wear-leveling entry to add
@@ -266,45 +255,6 @@ static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root)
        rb_insert_color(&e->rb, root);
 }
 
-
-/*
- * Helper functions to add and delete wear-leveling entries from different
- * trees.
- */
-
-static void free_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
-{
-       wl_tree_add(e, &ubi->free);
-}
-static inline void used_tree_add(struct ubi_device *ubi,
-                                struct ubi_wl_entry *e)
-{
-       wl_tree_add(e, &ubi->used);
-}
-static inline void scrub_tree_add(struct ubi_device *ubi,
-                                 struct ubi_wl_entry *e)
-{
-       wl_tree_add(e, &ubi->scrub);
-}
-static inline void free_tree_del(struct ubi_device *ubi,
-                                struct ubi_wl_entry *e)
-{
-       paranoid_check_in_wl_tree(e, &ubi->free);
-       rb_erase(&e->rb, &ubi->free);
-}
-static inline void used_tree_del(struct ubi_device *ubi,
-                                struct ubi_wl_entry *e)
-{
-       paranoid_check_in_wl_tree(e, &ubi->used);
-       rb_erase(&e->rb, &ubi->used);
-}
-static inline void scrub_tree_del(struct ubi_device *ubi,
-                                 struct ubi_wl_entry *e)
-{
-       paranoid_check_in_wl_tree(e, &ubi->scrub);
-       rb_erase(&e->rb, &ubi->scrub);
-}
-
 /**
  * do_work - do one pending work.
  * @ubi: UBI device description object
@@ -358,7 +308,7 @@ static int produce_free_peb(struct ubi_device *ubi)
        int err;
 
        spin_lock(&ubi->wl_lock);
-       while (tree_empty(&ubi->free)) {
+       while (!ubi->free.rb_node) {
                spin_unlock(&ubi->wl_lock);
 
                dbg_wl("do one work synchronously");
@@ -508,13 +458,13 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
        ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
                   dtype == UBI_UNKNOWN);
 
-       pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_KERNEL);
+       pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS);
        if (!pe)
                return -ENOMEM;
 
 retry:
        spin_lock(&ubi->wl_lock);
-       if (tree_empty(&ubi->free)) {
+       if (!ubi->free.rb_node) {
                if (ubi->works_count == 0) {
                        ubi_assert(list_empty(&ubi->works));
                        ubi_err("no free eraseblocks");
@@ -585,7 +535,8 @@ retry:
         * Move the physical eraseblock to the protection trees where it will
         * be protected from being moved for some time.
         */
-       free_tree_del(ubi, e);
+       paranoid_check_in_wl_tree(e, &ubi->free);
+       rb_erase(&e->rb, &ubi->free);
        prot_tree_add(ubi, e, pe, protect);
 
        dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect);
@@ -645,7 +596,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
        if (err > 0)
                return -EINVAL;
 
-       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
        if (!ec_hdr)
                return -ENOMEM;
 
@@ -704,7 +655,7 @@ static void check_protection_over(struct ubi_device *ubi)
         */
        while (1) {
                spin_lock(&ubi->wl_lock);
-               if (tree_empty(&ubi->prot.aec)) {
+               if (!ubi->prot.aec.rb_node) {
                        spin_unlock(&ubi->wl_lock);
                        break;
                }
@@ -721,7 +672,7 @@ static void check_protection_over(struct ubi_device *ubi)
                       pe->e->pnum, ubi->abs_ec, pe->abs_ec);
                rb_erase(&pe->rb_aec, &ubi->prot.aec);
                rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
-               used_tree_add(ubi, pe->e);
+               wl_tree_add(pe->e, &ubi->used);
                spin_unlock(&ubi->wl_lock);
 
                kfree(pe);
@@ -768,7 +719,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
        dbg_wl("schedule erasure of PEB %d, EC %d, torture %d",
               e->pnum, e->ec, torture);
 
-       wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+       wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
        if (!wl_wrk)
                return -ENOMEM;
 
@@ -802,7 +753,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
        if (cancel)
                return 0;
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi);
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
                return -ENOMEM;
 
@@ -812,8 +763,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
         * Only one WL worker at a time is supported at this implementation, so
         * make sure a PEB is not being moved already.
         */
-       if (ubi->move_to || tree_empty(&ubi->free) ||
-           (tree_empty(&ubi->used) && tree_empty(&ubi->scrub))) {
+       if (ubi->move_to || !ubi->free.rb_node ||
+           (!ubi->used.rb_node && !ubi->scrub.rb_node)) {
                /*
                 * Only one WL worker at a time is supported at this
                 * implementation, so if a LEB is already being moved, cancel.
@@ -828,14 +779,14 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                 * triggered again.
                 */
                dbg_wl("cancel WL, a list is empty: free %d, used %d",
-                      tree_empty(&ubi->free), tree_empty(&ubi->used));
+                      !ubi->free.rb_node, !ubi->used.rb_node);
                ubi->wl_scheduled = 0;
                spin_unlock(&ubi->wl_lock);
                ubi_free_vid_hdr(ubi, vid_hdr);
                return 0;
        }
 
-       if (tree_empty(&ubi->scrub)) {
+       if (!ubi->scrub.rb_node) {
                /*
                 * Now pick the least worn-out used physical eraseblock and a
                 * highly worn-out free physical eraseblock. If the erase
@@ -852,17 +803,20 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                        ubi_free_vid_hdr(ubi, vid_hdr);
                        return 0;
                }
-               used_tree_del(ubi, e1);
+               paranoid_check_in_wl_tree(e1, &ubi->used);
+               rb_erase(&e1->rb, &ubi->used);
                dbg_wl("move PEB %d EC %d to PEB %d EC %d",
                       e1->pnum, e1->ec, e2->pnum, e2->ec);
        } else {
                e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb);
                e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
-               scrub_tree_del(ubi, e1);
+               paranoid_check_in_wl_tree(e1, &ubi->scrub);
+       rb_erase(&e1->rb, &ubi->scrub);
                dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
        }
 
-       free_tree_del(ubi, e2);
+       paranoid_check_in_wl_tree(e2, &ubi->free);
+       rb_erase(&e2->rb, &ubi->free);
        ubi_assert(!ubi->move_from && !ubi->move_to);
        ubi_assert(!ubi->move_to_put && !ubi->move_from_put);
        ubi->move_from = e1;
@@ -908,7 +862,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
        ubi_free_vid_hdr(ubi, vid_hdr);
        spin_lock(&ubi->wl_lock);
        if (!ubi->move_to_put)
-               used_tree_add(ubi, e2);
+               wl_tree_add(e2, &ubi->used);
        else
                put = 1;
        ubi->move_from = ubi->move_to = NULL;
@@ -953,7 +907,7 @@ error:
        if (ubi->move_from_put)
                put = 1;
        else
-               used_tree_add(ubi, e1);
+               wl_tree_add(e1, &ubi->used);
        ubi->move_from = ubi->move_to = NULL;
        ubi->move_from_put = ubi->move_to_put = 0;
        spin_unlock(&ubi->wl_lock);
@@ -1005,8 +959,8 @@ static int ensure_wear_leveling(struct ubi_device *ubi)
         * If the ubi->scrub tree is not empty, scrubbing is needed, and the
         * the WL worker has to be scheduled anyway.
         */
-       if (tree_empty(&ubi->scrub)) {
-               if (tree_empty(&ubi->used) || tree_empty(&ubi->free))
+       if (!ubi->scrub.rb_node) {
+               if (!ubi->used.rb_node || !ubi->free.rb_node)
                        /* No physical eraseblocks - no deal */
                        goto out_unlock;
 
@@ -1028,7 +982,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi)
        ubi->wl_scheduled = 1;
        spin_unlock(&ubi->wl_lock);
 
-       wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+       wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
        if (!wrk) {
                err = -ENOMEM;
                goto out_cancel;
@@ -1079,7 +1033,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
 
                spin_lock(&ubi->wl_lock);
                ubi->abs_ec += 1;
-               free_tree_add(ubi, e);
+               wl_tree_add(e, &ubi->free);
                spin_unlock(&ubi->wl_lock);
 
                /*
@@ -1093,6 +1047,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
                return err;
        }
 
+       ubi_err("failed to erase PEB %d, error %d", pnum, err);
        kfree(wl_wrk);
        kmem_cache_free(wl_entries_slab, e);
 
@@ -1211,11 +1166,13 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
                spin_unlock(&ubi->wl_lock);
                return 0;
        } else {
-               if (in_wl_tree(e, &ubi->used))
-                       used_tree_del(ubi, e);
-               else if (in_wl_tree(e, &ubi->scrub))
-                       scrub_tree_del(ubi, e);
-               else
+               if (in_wl_tree(e, &ubi->used)) {
+                       paranoid_check_in_wl_tree(e, &ubi->used);
+                       rb_erase(&e->rb, &ubi->used);
+               } else if (in_wl_tree(e, &ubi->scrub)) {
+                       paranoid_check_in_wl_tree(e, &ubi->scrub);
+                       rb_erase(&e->rb, &ubi->scrub);
+               } else
                        prot_tree_del(ubi, e->pnum);
        }
        spin_unlock(&ubi->wl_lock);
@@ -1223,7 +1180,7 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
        err = schedule_erase(ubi, e, torture);
        if (err) {
                spin_lock(&ubi->wl_lock);
-               used_tree_add(ubi, e);
+               wl_tree_add(e, &ubi->used);
                spin_unlock(&ubi->wl_lock);
        }
 
@@ -1267,12 +1224,13 @@ retry:
                goto retry;
        }
 
-       if (in_wl_tree(e, &ubi->used))
-               used_tree_del(ubi, e);
-       else
+       if (in_wl_tree(e, &ubi->used)) {
+               paranoid_check_in_wl_tree(e, &ubi->used);
+               rb_erase(&e->rb, &ubi->used);
+       } else
                prot_tree_del(ubi, pnum);
 
-       scrub_tree_add(ubi, e);
+       wl_tree_add(e, &ubi->scrub);
        spin_unlock(&ubi->wl_lock);
 
        /*
@@ -1488,7 +1446,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                e->pnum = seb->pnum;
                e->ec = seb->ec;
                ubi_assert(e->ec >= 0);
-               free_tree_add(ubi, e);
+               wl_tree_add(e, &ubi->free);
                ubi->lookuptbl[e->pnum] = e;
        }
 
@@ -1522,16 +1480,16 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                        if (!seb->scrub) {
                                dbg_wl("add PEB %d EC %d to the used tree",
                                       e->pnum, e->ec);
-                               used_tree_add(ubi, e);
+                               wl_tree_add(e, &ubi->used);
                        } else {
                                dbg_wl("add PEB %d EC %d to the scrub tree",
                                       e->pnum, e->ec);
-                               scrub_tree_add(ubi, e);
+                               wl_tree_add(e, &ubi->scrub);
                        }
                }
        }
 
-       if (WL_RESERVED_PEBS > ubi->avail_pebs) {
+       if (ubi->avail_pebs < WL_RESERVED_PEBS) {
                ubi_err("no enough physical eraseblocks (%d, need %d)",
                        ubi->avail_pebs, WL_RESERVED_PEBS);
                goto out_free;
@@ -1624,13 +1582,13 @@ void ubi_wl_close(struct ubi_device *ubi)
  * is equivalent to @ec, %1 if not, and a negative error code if an error
  * occurred.
  */
-static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
 {
        int err;
        long long read_ec;
        struct ubi_ec_hdr *ec_hdr;
 
-       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
        if (!ec_hdr)
                return -ENOMEM;
 
index 9c635a237a9d4c937bd97bc724ec9714389c2f4b..8f99a062661608d39c59eb8dc9d3afb1c21c71c2 100644 (file)
@@ -1780,6 +1780,15 @@ config SC92031
          To compile this driver as a module, choose M here: the module
          will be called sc92031.  This is recommended.
 
+config CPMAC
+       tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
+       depends on NET_ETHERNET && EXPERIMENTAL && AR7
+       select PHYLIB
+       select FIXED_PHY
+       select FIXED_MII_100_FDX
+       help
+         TI AR7 CPMAC Ethernet support
+
 config NET_POCKET
        bool "Pocket and portable adapters"
        depends on PARPORT
index d2e0f35da42e0e6f9f2b184876d2a5cd45f03c13..22f78cbd126b185963e180e08893fa4c30995e67 100644 (file)
@@ -159,6 +159,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o
 obj-$(CONFIG_8139TOO) += 8139too.o
 obj-$(CONFIG_ZNET) += znet.o
 obj-$(CONFIG_LAN_SAA9730) += saa9730.o
+obj-$(CONFIG_CPMAC) += cpmac.o
 obj-$(CONFIG_DEPCA) += depca.o
 obj-$(CONFIG_EWRK3) += ewrk3.o
 obj-$(CONFIG_ATP) += atp.o
index ebf1a3a88e156aeed5491da8105d55ba9f21fba8..b74dbeef805018f2d64f246130239f147fce8191 100644 (file)
@@ -1023,7 +1023,7 @@ static int lance_rx( struct net_device *dev )
                                        DECLARE_MAC_BUF(mac);
                                        DECLARE_MAC_BUF(mac2);
 
-                                       printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ",
+                                       printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s "
                                                   "data %02x %02x %02x %02x %02x %02x %02x %02x "
                                                   "len %d\n",
                                                   dev->name, ((u_short *)data)[6],
index b46c5d8a77bdca845398d26a90d97d02f8ee60d6..185f98e3964c49b6a1615dc72c09f28ca227419f 100644 (file)
 #include <linux/delay.h>
 #include <linux/crc32.h>
 #include <linux/phy.h>
+
+#include <asm/cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/cpu.h>
+#include <au1000.h>
+#include <prom.h>
+
 #include "au1000_eth.h"
 
 #ifdef AU1000_ETH_DEBUG
@@ -96,11 +99,6 @@ static void mdio_write(struct net_device *, int, int, u16);
 static void au1000_adjust_link(struct net_device *);
 static void enable_mac(struct net_device *, int);
 
-// externs
-extern int get_ethernet_addr(char *ethernet_addr);
-extern void str2eaddr(unsigned char *ea, unsigned char *str);
-extern char * prom_getcmdline(void);
-
 /*
  * Theory of operation
  *
@@ -619,7 +617,6 @@ static struct net_device * au1000_probe(int port_num)
        struct au1000_private *aup = NULL;
        struct net_device *dev = NULL;
        db_dest_t *pDB, *pDBfree;
-       char *pmac, *argptr;
        char ethaddr[6];
        int irq, i, err;
        u32 base, macen;
@@ -677,21 +674,12 @@ static struct net_device * au1000_probe(int port_num)
        au_macs[port_num] = aup;
 
        if (port_num == 0) {
-               /* Check the environment variables first */
-               if (get_ethernet_addr(ethaddr) == 0)
+               if (prom_get_ethernet_addr(ethaddr) == 0)
                        memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
                else {
-                       /* Check command line */
-                       argptr = prom_getcmdline();
-                       if ((pmac = strstr(argptr, "ethaddr=")) == NULL)
-                               printk(KERN_INFO "%s: No MAC address found\n",
-                                                dev->name);
+                       printk(KERN_INFO "%s: No MAC address found\n",
+                                        dev->name);
                                /* Use the hard coded MAC addresses */
-                       else {
-                               str2eaddr(ethaddr, pmac + strlen("ethaddr="));
-                               memcpy(au1000_mac_addr, ethaddr,
-                                      sizeof(au1000_mac_addr));
-                       }
                }
 
                setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
index 64bfec32e2a6e99ffd5c8225ba1992e2625d0dc2..db80f243dd37e9d6f968cc3ab58b652e69f35c2b 100644 (file)
@@ -98,6 +98,7 @@ static char *xmit_hash_policy = NULL;
 static int arp_interval = BOND_LINK_ARP_INTERV;
 static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
 static char *arp_validate = NULL;
+static int fail_over_mac = 0;
 struct bond_params bonding_defaults;
 
 module_param(max_bonds, int, 0);
@@ -131,6 +132,8 @@ module_param_array(arp_ip_target, charp, NULL, 0);
 MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
 module_param(arp_validate, charp, 0);
 MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
+module_param(fail_over_mac, int, 0);
+MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC.  0 of off (default), 1 for on.");
 
 /*----------------------------- Global variables ----------------------------*/
 
@@ -1096,7 +1099,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                if (new_active) {
                        bond_set_slave_active_flags(new_active);
                }
-               bond_send_gratuitous_arp(bond);
+
+               /* when bonding does not set the slave MAC address, the bond MAC
+                * address is the one of the active slave.
+                */
+               if (new_active && bond->params.fail_over_mac)
+                       memcpy(bond->dev->dev_addr,  new_active->dev->dev_addr,
+                               new_active->dev->addr_len);
+               if (bond->curr_active_slave &&
+                       test_bit(__LINK_STATE_LINKWATCH_PENDING,
+                                       &bond->curr_active_slave->dev->state)) {
+                       dprintk("delaying gratuitous arp on %s\n",
+                               bond->curr_active_slave->dev->name);
+                       bond->send_grat_arp = 1;
+               } else
+                       bond_send_gratuitous_arp(bond);
        }
 }
 
@@ -1217,7 +1234,8 @@ static int bond_compute_features(struct bonding *bond)
        struct slave *slave;
        struct net_device *bond_dev = bond->dev;
        unsigned long features = bond_dev->features;
-       unsigned short max_hard_header_len = ETH_HLEN;
+       unsigned short max_hard_header_len = max((u16)ETH_HLEN,
+                                               bond_dev->hard_header_len);
        int i;
 
        features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
@@ -1238,6 +1256,23 @@ static int bond_compute_features(struct bonding *bond)
        return 0;
 }
 
+
+static void bond_setup_by_slave(struct net_device *bond_dev,
+                               struct net_device *slave_dev)
+{
+       struct bonding *bond = bond_dev->priv;
+
+       bond_dev->neigh_setup           = slave_dev->neigh_setup;
+
+       bond_dev->type              = slave_dev->type;
+       bond_dev->hard_header_len   = slave_dev->hard_header_len;
+       bond_dev->addr_len          = slave_dev->addr_len;
+
+       memcpy(bond_dev->broadcast, slave_dev->broadcast,
+               slave_dev->addr_len);
+       bond->setup_by_slave = 1;
+}
+
 /* enslave device <slave> to bond device <master> */
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 {
@@ -1258,8 +1293,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* bond must be initialized by bond_open() before enslaving */
        if (!(bond_dev->flags & IFF_UP)) {
-               dprintk("Error, master_dev is not up\n");
-               return -EPERM;
+               printk(KERN_WARNING DRV_NAME
+                       " %s: master_dev is not up in bond_enslave\n",
+                       bond_dev->name);
        }
 
        /* already enslaved */
@@ -1312,14 +1348,42 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                goto err_undo_flags;
        }
 
+       /* set bonding device ether type by slave - bonding netdevices are
+        * created with ether_setup, so when the slave type is not ARPHRD_ETHER
+        * there is a need to override some of the type dependent attribs/funcs.
+        *
+        * bond ether type mutual exclusion - don't allow slaves of dissimilar
+        * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
+        */
+       if (bond->slave_cnt == 0) {
+               if (slave_dev->type != ARPHRD_ETHER)
+                       bond_setup_by_slave(bond_dev, slave_dev);
+       } else if (bond_dev->type != slave_dev->type) {
+               printk(KERN_ERR DRV_NAME ": %s ether type (%d) is different "
+                       "from other slaves (%d), can not enslave it.\n",
+                       slave_dev->name,
+                       slave_dev->type, bond_dev->type);
+                       res = -EINVAL;
+                       goto err_undo_flags;
+       }
+
        if (slave_dev->set_mac_address == NULL) {
-               printk(KERN_ERR DRV_NAME
-                       ": %s: Error: The slave device you specified does "
-                       "not support setting the MAC address. "
-                       "Your kernel likely does not support slave "
-                       "devices.\n", bond_dev->name);
-               res = -EOPNOTSUPP;
-               goto err_undo_flags;
+               if (bond->slave_cnt == 0) {
+                       printk(KERN_WARNING DRV_NAME
+                              ": %s: Warning: The first slave device "
+                              "specified does not support setting the MAC "
+                              "address. Enabling the fail_over_mac option.",
+                              bond_dev->name);
+                       bond->params.fail_over_mac = 1;
+               } else if (!bond->params.fail_over_mac) {
+                       printk(KERN_ERR DRV_NAME
+                               ": %s: Error: The slave device specified "
+                               "does not support setting the MAC address, "
+                               "but fail_over_mac is not enabled.\n"
+                               , bond_dev->name);
+                       res = -EOPNOTSUPP;
+                       goto err_undo_flags;
+               }
        }
 
        new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1340,16 +1404,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         */
        memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
 
-       /*
-        * Set slave to master's mac address.  The application already
-        * set the master's mac address to that of the first slave
-        */
-       memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
-       addr.sa_family = slave_dev->type;
-       res = dev_set_mac_address(slave_dev, &addr);
-       if (res) {
-               dprintk("Error %d calling set_mac_address\n", res);
-               goto err_free;
+       if (!bond->params.fail_over_mac) {
+               /*
+                * Set slave to master's mac address.  The application already
+                * set the master's mac address to that of the first slave
+                */
+               memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
+               addr.sa_family = slave_dev->type;
+               res = dev_set_mac_address(slave_dev, &addr);
+               if (res) {
+                       dprintk("Error %d calling set_mac_address\n", res);
+                       goto err_free;
+               }
        }
 
        res = netdev_set_master(slave_dev, bond_dev);
@@ -1574,9 +1640,11 @@ err_close:
        dev_close(slave_dev);
 
 err_restore_mac:
-       memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
-       addr.sa_family = slave_dev->type;
-       dev_set_mac_address(slave_dev, &addr);
+       if (!bond->params.fail_over_mac) {
+               memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
+               addr.sa_family = slave_dev->type;
+               dev_set_mac_address(slave_dev, &addr);
+       }
 
 err_free:
        kfree(new_slave);
@@ -1749,10 +1817,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        /* close slave before restoring its mac address */
        dev_close(slave_dev);
 
-       /* restore original ("permanent") mac address */
-       memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
-       addr.sa_family = slave_dev->type;
-       dev_set_mac_address(slave_dev, &addr);
+       if (!bond->params.fail_over_mac) {
+               /* restore original ("permanent") mac address */
+               memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+               addr.sa_family = slave_dev->type;
+               dev_set_mac_address(slave_dev, &addr);
+       }
 
        slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
                                   IFF_SLAVE_INACTIVE | IFF_BONDING |
@@ -1763,6 +1833,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        return 0;  /* deletion OK */
 }
 
+/*
+* Destroy a bonding device.
+* Must be under rtnl_lock when this function is called.
+*/
+void bond_destroy(struct bonding *bond)
+{
+       bond_deinit(bond->dev);
+       bond_destroy_sysfs_entry(bond);
+       unregister_netdevice(bond->dev);
+}
+
+/*
+* First release a slave and than destroy the bond if no more slaves iare left.
+* Must be under rtnl_lock when this function is called.
+*/
+int  bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev)
+{
+       struct bonding *bond = bond_dev->priv;
+       int ret;
+
+       ret = bond_release(bond_dev, slave_dev);
+       if ((ret == 0) && (bond->slave_cnt == 0)) {
+               printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n",
+                      bond_dev->name, bond_dev->name);
+               bond_destroy(bond);
+       }
+       return ret;
+}
+
 /*
  * This function releases all slaves.
  */
@@ -1839,10 +1938,12 @@ static int bond_release_all(struct net_device *bond_dev)
                /* close slave before restoring its mac address */
                dev_close(slave_dev);
 
-               /* restore original ("permanent") mac address*/
-               memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
-               addr.sa_family = slave_dev->type;
-               dev_set_mac_address(slave_dev, &addr);
+               if (!bond->params.fail_over_mac) {
+                       /* restore original ("permanent") mac address*/
+                       memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+                       addr.sa_family = slave_dev->type;
+                       dev_set_mac_address(slave_dev, &addr);
+               }
 
                slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
                                           IFF_SLAVE_INACTIVE);
@@ -2013,6 +2114,17 @@ void bond_mii_monitor(struct net_device *bond_dev)
         * program could monitor the link itself if needed.
         */
 
+       if (bond->send_grat_arp) {
+               if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
+                               &bond->curr_active_slave->dev->state))
+                       dprintk("Needs to send gratuitous arp but not yet\n");
+               else {
+                       dprintk("sending delayed gratuitous arp on on %s\n",
+                               bond->curr_active_slave->dev->name);
+                       bond_send_gratuitous_arp(bond);
+                       bond->send_grat_arp = 0;
+               }
+       }
        read_lock(&bond->curr_slave_lock);
        oldcurrent = bond->curr_active_slave;
        read_unlock(&bond->curr_slave_lock);
@@ -2414,7 +2526,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
 
        if (bond->master_ip) {
                bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
-                                 bond->master_ip, 0);
+                               bond->master_ip, 0);
        }
 
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
@@ -2951,9 +3063,15 @@ static void bond_info_show_master(struct seq_file *seq)
        curr = bond->curr_active_slave;
        read_unlock(&bond->curr_slave_lock);
 
-       seq_printf(seq, "Bonding Mode: %s\n",
+       seq_printf(seq, "Bonding Mode: %s",
                   bond_mode_name(bond->params.mode));
 
+       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
+           bond->params.fail_over_mac)
+               seq_printf(seq, " (fail_over_mac)");
+
+       seq_printf(seq, "\n");
+
        if (bond->params.mode == BOND_MODE_XOR ||
                bond->params.mode == BOND_MODE_8023AD) {
                seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
@@ -3248,6 +3366,11 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
                 * ... Or is it this?
                 */
                break;
+       case NETDEV_GOING_DOWN:
+               dprintk("slave %s is going down\n", slave_dev->name);
+               if (bond->setup_by_slave)
+                       bond_release_and_destroy(bond_dev, slave_dev);
+               break;
        case NETDEV_CHANGEMTU:
                /*
                 * TODO: Should slaves be allowed to
@@ -3880,6 +4003,13 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 
        dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
 
+       /*
+        * If fail_over_mac is enabled, do nothing and return success.
+        * Returning an error causes ifenslave to fail.
+        */
+       if (bond->params.fail_over_mac)
+               return 0;
+
        if (!is_valid_ether_addr(sa->sa_data)) {
                return -EADDRNOTAVAIL;
        }
@@ -4217,6 +4347,8 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
        bond->current_arp_slave = NULL;
        bond->primary_slave = NULL;
        bond->dev = bond_dev;
+       bond->send_grat_arp = 0;
+       bond->setup_by_slave = 0;
        INIT_LIST_HEAD(&bond->vlan_list);
 
        /* Initialize the device entry points */
@@ -4265,7 +4397,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
 #ifdef CONFIG_PROC_FS
        bond_create_proc_entry(bond);
 #endif
-
        list_add_tail(&bond->bond_list, &bond_dev_list);
 
        return 0;
@@ -4599,6 +4730,11 @@ static int bond_check_params(struct bond_params *params)
                primary = NULL;
        }
 
+       if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP))
+               printk(KERN_WARNING DRV_NAME
+                      ": Warning: fail_over_mac only affects "
+                      "active-backup mode.\n");
+
        /* fill params struct with the proper values */
        params->mode = bond_mode;
        params->xmit_policy = xmit_hashtype;
@@ -4610,6 +4746,7 @@ static int bond_check_params(struct bond_params *params)
        params->use_carrier = use_carrier;
        params->lacp_fast = lacp_fast;
        params->primary[0] = 0;
+       params->fail_over_mac = fail_over_mac;
 
        if (primary) {
                strncpy(params->primary, primary, IFNAMSIZ);
index 6f49ca7e9b6686aa9841fe78e61bf3e56c841bb5..80c0c8c415ed527c470dd371a27a4669cd3afcc0 100644 (file)
@@ -164,9 +164,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
                                printk(KERN_INFO DRV_NAME
                                        ": %s is being deleted...\n",
                                        bond->dev->name);
-                               bond_deinit(bond->dev);
-                               bond_destroy_sysfs_entry(bond);
-                               unregister_netdevice(bond->dev);
+                               bond_destroy(bond);
                                rtnl_unlock();
                                goto out;
                        }
@@ -260,17 +258,16 @@ static ssize_t bonding_store_slaves(struct device *d,
        char command[IFNAMSIZ + 1] = { 0, };
        char *ifname;
        int i, res, found, ret = count;
+       u32 original_mtu;
        struct slave *slave;
        struct net_device *dev = NULL;
        struct bonding *bond = to_bond(d);
 
        /* Quick sanity check -- is the bond interface up? */
        if (!(bond->dev->flags & IFF_UP)) {
-               printk(KERN_ERR DRV_NAME
-                      ": %s: Unable to update slaves because interface is down.\n",
+               printk(KERN_WARNING DRV_NAME
+                      ": %s: doing slave updates when interface is down.\n",
                       bond->dev->name);
-               ret = -EPERM;
-               goto out;
        }
 
        /* Note:  We can't hold bond->lock here, as bond_create grabs it. */
@@ -327,6 +324,7 @@ static ssize_t bonding_store_slaves(struct device *d,
                }
 
                /* Set the slave's MTU to match the bond */
+               original_mtu = dev->mtu;
                if (dev->mtu != bond->dev->mtu) {
                        if (dev->change_mtu) {
                                res = dev->change_mtu(dev,
@@ -341,6 +339,9 @@ static ssize_t bonding_store_slaves(struct device *d,
                }
                rtnl_lock();
                res = bond_enslave(bond->dev, dev);
+               bond_for_each_slave(bond, slave, i)
+                       if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
+                               slave->original_mtu = original_mtu;
                rtnl_unlock();
                if (res) {
                        ret = res;
@@ -353,13 +354,17 @@ static ssize_t bonding_store_slaves(struct device *d,
                bond_for_each_slave(bond, slave, i)
                        if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
                                dev = slave->dev;
+                               original_mtu = slave->original_mtu;
                                break;
                        }
                if (dev) {
                        printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
                                bond->dev->name, dev->name);
                        rtnl_lock();
-                       res = bond_release(bond->dev, dev);
+                       if (bond->setup_by_slave)
+                               res = bond_release_and_destroy(bond->dev, dev);
+                       else
+                               res = bond_release(bond->dev, dev);
                        rtnl_unlock();
                        if (res) {
                                ret = res;
@@ -367,9 +372,9 @@ static ssize_t bonding_store_slaves(struct device *d,
                        }
                        /* set the slave MTU to the default */
                        if (dev->change_mtu) {
-                               dev->change_mtu(dev, 1500);
+                               dev->change_mtu(dev, original_mtu);
                        } else {
-                               dev->mtu = 1500;
+                               dev->mtu = original_mtu;
                        }
                }
                else {
@@ -562,6 +567,54 @@ static ssize_t bonding_store_arp_validate(struct device *d,
 
 static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
 
+/*
+ * Show and store fail_over_mac.  User only allowed to change the
+ * value when there are no slaves.
+ */
+static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attribute *attr, char *buf)
+{
+       struct bonding *bond = to_bond(d);
+
+       return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1;
+}
+
+static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count)
+{
+       int new_value;
+       int ret = count;
+       struct bonding *bond = to_bond(d);
+
+       if (bond->slave_cnt != 0) {
+               printk(KERN_ERR DRV_NAME
+                      ": %s: Can't alter fail_over_mac with slaves in bond.\n",
+                      bond->dev->name);
+               ret = -EPERM;
+               goto out;
+       }
+
+       if (sscanf(buf, "%d", &new_value) != 1) {
+               printk(KERN_ERR DRV_NAME
+                      ": %s: no fail_over_mac value specified.\n",
+                      bond->dev->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if ((new_value == 0) || (new_value == 1)) {
+               bond->params.fail_over_mac = new_value;
+               printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n",
+                      bond->dev->name, new_value);
+       } else {
+               printk(KERN_INFO DRV_NAME
+                      ": %s: Ignoring invalid fail_over_mac value %d.\n",
+                      bond->dev->name, new_value);
+       }
+out:
+       return ret;
+}
+
+static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac);
+
 /*
  * Show and set the arp timer interval.  There are two tricky bits
  * here.  First, if ARP monitoring is activated, then we must disable
@@ -1383,6 +1436,7 @@ static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
 static struct attribute *per_bond_attrs[] = {
        &dev_attr_slaves.attr,
        &dev_attr_mode.attr,
+       &dev_attr_fail_over_mac.attr,
        &dev_attr_arp_validate.attr,
        &dev_attr_arp_interval.attr,
        &dev_attr_arp_ip_target.attr,
index 2a6af7d23728357c1d60f091b6a6864bb26593be..a8bbd563265cbdde92ae0e0f89a96d0e7a6e0409 100644 (file)
@@ -22,8 +22,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION    "3.1.3"
-#define DRV_RELDATE    "June 13, 2007"
+#define DRV_VERSION    "3.2.0"
+#define DRV_RELDATE    "September 13, 2007"
 #define DRV_NAME       "bonding"
 #define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
 
@@ -128,6 +128,7 @@ struct bond_params {
        int arp_interval;
        int arp_validate;
        int use_carrier;
+       int fail_over_mac;
        int updelay;
        int downdelay;
        int lacp_fast;
@@ -156,6 +157,7 @@ struct slave {
        s8     link;    /* one of BOND_LINK_XXXX */
        s8     state;   /* one of BOND_STATE_XXXX */
        u32    original_flags;
+       u32    original_mtu;
        u32    link_failure_count;
        u16    speed;
        u8     duplex;
@@ -185,6 +187,8 @@ struct bonding {
        struct   timer_list mii_timer;
        struct   timer_list arp_timer;
        s8       kill_timers;
+       s8       send_grat_arp;
+       s8       setup_by_slave;
        struct   net_device_stats stats;
 #ifdef CONFIG_PROC_FS
        struct   proc_dir_entry *proc_entry;
@@ -292,6 +296,8 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond)
 struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
 int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
 int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
+void bond_destroy(struct bonding *bond);
+int  bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
 void bond_deinit(struct net_device *bond_dev);
 int bond_create_sysfs(void);
 void bond_destroy_sysfs(void);
index 563bf5f6fa2aa40c324129291ed9bacf6efde8a3..7df31b5561cc02000cbc44d1ea2048bd016f4e58 100644 (file)
@@ -4443,7 +4443,7 @@ static struct {
        {REG_MAC_COLL_EXCESS},
        {REG_MAC_COLL_LATE}
 };
-#define CAS_REG_LEN    (sizeof(ethtool_register_table)/sizeof(int))
+#define CAS_REG_LEN    ARRAY_SIZE(ethtool_register_table)
 #define CAS_MAX_REGS   (sizeof (u32)*CAS_REG_LEN)
 
 static void cas_read_regs(struct cas *cp, u8 *ptr, int len)
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
new file mode 100644 (file)
index 0000000..ed53aaa
--- /dev/null
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (C) 2006, 2007 Eugene Konev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/gpio.h>
+
+MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>");
+MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)");
+MODULE_LICENSE("GPL");
+
+static int debug_level = 8;
+static int dumb_switch;
+
+/* Next 2 are only used in cpmac_probe, so it's pointless to change them */
+module_param(debug_level, int, 0444);
+module_param(dumb_switch, int, 0444);
+
+MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable");
+MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus");
+
+#define CPMAC_VERSION "0.5.0"
+/* stolen from net/ieee80211.h */
+#ifndef MAC_FMT
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
+                  ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
+#endif
+/* frame size + 802.1q tag */
+#define CPMAC_SKB_SIZE         (ETH_FRAME_LEN + 4)
+#define CPMAC_QUEUES   8
+
+/* Ethernet registers */
+#define CPMAC_TX_CONTROL               0x0004
+#define CPMAC_TX_TEARDOWN              0x0008
+#define CPMAC_RX_CONTROL               0x0014
+#define CPMAC_RX_TEARDOWN              0x0018
+#define CPMAC_MBP                      0x0100
+# define MBP_RXPASSCRC                 0x40000000
+# define MBP_RXQOS                     0x20000000
+# define MBP_RXNOCHAIN                 0x10000000
+# define MBP_RXCMF                     0x01000000
+# define MBP_RXSHORT                   0x00800000
+# define MBP_RXCEF                     0x00400000
+# define MBP_RXPROMISC                 0x00200000
+# define MBP_PROMISCCHAN(channel)      (((channel) & 0x7) << 16)
+# define MBP_RXBCAST                   0x00002000
+# define MBP_BCASTCHAN(channel)                (((channel) & 0x7) << 8)
+# define MBP_RXMCAST                   0x00000020
+# define MBP_MCASTCHAN(channel)                ((channel) & 0x7)
+#define CPMAC_UNICAST_ENABLE           0x0104
+#define CPMAC_UNICAST_CLEAR            0x0108
+#define CPMAC_MAX_LENGTH               0x010c
+#define CPMAC_BUFFER_OFFSET            0x0110
+#define CPMAC_MAC_CONTROL              0x0160
+# define MAC_TXPTYPE                   0x00000200
+# define MAC_TXPACE                    0x00000040
+# define MAC_MII                       0x00000020
+# define MAC_TXFLOW                    0x00000010
+# define MAC_RXFLOW                    0x00000008
+# define MAC_MTEST                     0x00000004
+# define MAC_LOOPBACK                  0x00000002
+# define MAC_FDX                       0x00000001
+#define CPMAC_MAC_STATUS               0x0164
+# define MAC_STATUS_QOS                        0x00000004
+# define MAC_STATUS_RXFLOW             0x00000002
+# define MAC_STATUS_TXFLOW             0x00000001
+#define CPMAC_TX_INT_ENABLE            0x0178
+#define CPMAC_TX_INT_CLEAR             0x017c
+#define CPMAC_MAC_INT_VECTOR           0x0180
+# define MAC_INT_STATUS                        0x00080000
+# define MAC_INT_HOST                  0x00040000
+# define MAC_INT_RX                    0x00020000
+# define MAC_INT_TX                    0x00010000
+#define CPMAC_MAC_EOI_VECTOR           0x0184
+#define CPMAC_RX_INT_ENABLE            0x0198
+#define CPMAC_RX_INT_CLEAR             0x019c
+#define CPMAC_MAC_INT_ENABLE           0x01a8
+#define CPMAC_MAC_INT_CLEAR            0x01ac
+#define CPMAC_MAC_ADDR_LO(channel)     (0x01b0 + (channel) * 4)
+#define CPMAC_MAC_ADDR_MID             0x01d0
+#define CPMAC_MAC_ADDR_HI              0x01d4
+#define CPMAC_MAC_HASH_LO              0x01d8
+#define CPMAC_MAC_HASH_HI              0x01dc
+#define CPMAC_TX_PTR(channel)          (0x0600 + (channel) * 4)
+#define CPMAC_RX_PTR(channel)          (0x0620 + (channel) * 4)
+#define CPMAC_TX_ACK(channel)          (0x0640 + (channel) * 4)
+#define CPMAC_RX_ACK(channel)          (0x0660 + (channel) * 4)
+#define CPMAC_REG_END                  0x0680
+/*
+ * Rx/Tx statistics
+ * TODO: use some of them to fill stats in cpmac_stats()
+ */
+#define CPMAC_STATS_RX_GOOD            0x0200
+#define CPMAC_STATS_RX_BCAST           0x0204
+#define CPMAC_STATS_RX_MCAST           0x0208
+#define CPMAC_STATS_RX_PAUSE           0x020c
+#define CPMAC_STATS_RX_CRC             0x0210
+#define CPMAC_STATS_RX_ALIGN           0x0214
+#define CPMAC_STATS_RX_OVER            0x0218
+#define CPMAC_STATS_RX_JABBER          0x021c
+#define CPMAC_STATS_RX_UNDER           0x0220
+#define CPMAC_STATS_RX_FRAG            0x0224
+#define CPMAC_STATS_RX_FILTER          0x0228
+#define CPMAC_STATS_RX_QOSFILTER       0x022c
+#define CPMAC_STATS_RX_OCTETS          0x0230
+
+#define CPMAC_STATS_TX_GOOD            0x0234
+#define CPMAC_STATS_TX_BCAST           0x0238
+#define CPMAC_STATS_TX_MCAST           0x023c
+#define CPMAC_STATS_TX_PAUSE           0x0240
+#define CPMAC_STATS_TX_DEFER           0x0244
+#define CPMAC_STATS_TX_COLLISION       0x0248
+#define CPMAC_STATS_TX_SINGLECOLL      0x024c
+#define CPMAC_STATS_TX_MULTICOLL       0x0250
+#define CPMAC_STATS_TX_EXCESSCOLL      0x0254
+#define CPMAC_STATS_TX_LATECOLL                0x0258
+#define CPMAC_STATS_TX_UNDERRUN                0x025c
+#define CPMAC_STATS_TX_CARRIERSENSE    0x0260
+#define CPMAC_STATS_TX_OCTETS          0x0264
+
+#define cpmac_read(base, reg)          (readl((void __iomem *)(base) + (reg)))
+#define cpmac_write(base, reg, val)    (writel(val, (void __iomem *)(base) + \
+                                               (reg)))
+
+/* MDIO bus */
+#define CPMAC_MDIO_VERSION             0x0000
+#define CPMAC_MDIO_CONTROL             0x0004
+# define MDIOC_IDLE                    0x80000000
+# define MDIOC_ENABLE                  0x40000000
+# define MDIOC_PREAMBLE                        0x00100000
+# define MDIOC_FAULT                   0x00080000
+# define MDIOC_FAULTDETECT             0x00040000
+# define MDIOC_INTTEST                 0x00020000
+# define MDIOC_CLKDIV(div)             ((div) & 0xff)
+#define CPMAC_MDIO_ALIVE               0x0008
+#define CPMAC_MDIO_LINK                        0x000c
+#define CPMAC_MDIO_ACCESS(channel)     (0x0080 + (channel) * 8)
+# define MDIO_BUSY                     0x80000000
+# define MDIO_WRITE                    0x40000000
+# define MDIO_REG(reg)                 (((reg) & 0x1f) << 21)
+# define MDIO_PHY(phy)                 (((phy) & 0x1f) << 16)
+# define MDIO_DATA(data)               ((data) & 0xffff)
+#define CPMAC_MDIO_PHYSEL(channel)     (0x0084 + (channel) * 8)
+# define PHYSEL_LINKSEL                        0x00000040
+# define PHYSEL_LINKINT                        0x00000020
+
+struct cpmac_desc {
+       u32 hw_next;
+       u32 hw_data;
+       u16 buflen;
+       u16 bufflags;
+       u16 datalen;
+       u16 dataflags;
+#define CPMAC_SOP                      0x8000
+#define CPMAC_EOP                      0x4000
+#define CPMAC_OWN                      0x2000
+#define CPMAC_EOQ                      0x1000
+       struct sk_buff *skb;
+       struct cpmac_desc *next;
+       dma_addr_t mapping;
+       dma_addr_t data_mapping;
+};
+
+struct cpmac_priv {
+       spinlock_t lock;
+       spinlock_t rx_lock;
+       struct cpmac_desc *rx_head;
+       int ring_size;
+       struct cpmac_desc *desc_ring;
+       dma_addr_t dma_ring;
+       void __iomem *regs;
+       struct mii_bus *mii_bus;
+       struct phy_device *phy;
+       char phy_name[BUS_ID_SIZE];
+       int oldlink, oldspeed, oldduplex;
+       u32 msg_enable;
+       struct net_device *dev;
+       struct work_struct reset_work;
+       struct platform_device *pdev;
+};
+
+static irqreturn_t cpmac_irq(int, void *);
+static void cpmac_hw_start(struct net_device *dev);
+static void cpmac_hw_stop(struct net_device *dev);
+static int cpmac_stop(struct net_device *dev);
+static int cpmac_open(struct net_device *dev);
+
+static void cpmac_dump_regs(struct net_device *dev)
+{
+       int i;
+       struct cpmac_priv *priv = netdev_priv(dev);
+       for (i = 0; i < CPMAC_REG_END; i += 4) {
+               if (i % 16 == 0) {
+                       if (i)
+                               printk("\n");
+                       printk(KERN_DEBUG "%s: reg[%p]:", dev->name,
+                              priv->regs + i);
+               }
+               printk(" %08x", cpmac_read(priv->regs, i));
+       }
+       printk("\n");
+}
+
+static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc)
+{
+       int i;
+       printk(KERN_DEBUG "%s: desc[%p]:", dev->name, desc);
+       for (i = 0; i < sizeof(*desc) / 4; i++)
+               printk(" %08x", ((u32 *)desc)[i]);
+       printk("\n");
+}
+
+static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb)
+{
+       int i;
+       printk(KERN_DEBUG "%s: skb 0x%p, len=%d\n", dev->name, skb, skb->len);
+       for (i = 0; i < skb->len; i++) {
+               if (i % 16 == 0) {
+                       if (i)
+                               printk("\n");
+                       printk(KERN_DEBUG "%s: data[%p]:", dev->name,
+                              skb->data + i);
+               }
+               printk(" %02x", ((u8 *)skb->data)[i]);
+       }
+       printk("\n");
+}
+
+static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+       u32 val;
+
+       while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY)
+               cpu_relax();
+       cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_REG(reg) |
+                   MDIO_PHY(phy_id));
+       while ((val = cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0))) & MDIO_BUSY)
+               cpu_relax();
+       return MDIO_DATA(val);
+}
+
+static int cpmac_mdio_write(struct mii_bus *bus, int phy_id,
+                           int reg, u16 val)
+{
+       while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY)
+               cpu_relax();
+       cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_WRITE |
+                   MDIO_REG(reg) | MDIO_PHY(phy_id) | MDIO_DATA(val));
+       return 0;
+}
+
+static int cpmac_mdio_reset(struct mii_bus *bus)
+{
+       ar7_device_reset(AR7_RESET_BIT_MDIO);
+       cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE |
+                   MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1));
+       return 0;
+}
+
+static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };
+
+static struct mii_bus cpmac_mii = {
+       .name = "cpmac-mii",
+       .read = cpmac_mdio_read,
+       .write = cpmac_mdio_write,
+       .reset = cpmac_mdio_reset,
+       .irq = mii_irqs,
+};
+
+static int cpmac_config(struct net_device *dev, struct ifmap *map)
+{
+       if (dev->flags & IFF_UP)
+               return -EBUSY;
+
+       /* Don't allow changing the I/O address */
+       if (map->base_addr != dev->base_addr)
+               return -EOPNOTSUPP;
+
+       /* ignore other fields */
+       return 0;
+}
+
+static void cpmac_set_multicast_list(struct net_device *dev)
+{
+       struct dev_mc_list *iter;
+       int i;
+       u8 tmp;
+       u32 mbp, bit, hash[2] = { 0, };
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       mbp = cpmac_read(priv->regs, CPMAC_MBP);
+       if (dev->flags & IFF_PROMISC) {
+               cpmac_write(priv->regs, CPMAC_MBP, (mbp & ~MBP_PROMISCCHAN(0)) |
+                           MBP_RXPROMISC);
+       } else {
+               cpmac_write(priv->regs, CPMAC_MBP, mbp & ~MBP_RXPROMISC);
+               if (dev->flags & IFF_ALLMULTI) {
+                       /* enable all multicast mode */
+                       cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, 0xffffffff);
+                       cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, 0xffffffff);
+               } else {
+                       /*
+                        * cpmac uses some strange mac address hashing
+                        * (not crc32)
+                        */
+                       for (i = 0, iter = dev->mc_list; i < dev->mc_count;
+                            i++, iter = iter->next) {
+                               bit = 0;
+                               tmp = iter->dmi_addr[0];
+                               bit  ^= (tmp >> 2) ^ (tmp << 4);
+                               tmp = iter->dmi_addr[1];
+                               bit  ^= (tmp >> 4) ^ (tmp << 2);
+                               tmp = iter->dmi_addr[2];
+                               bit  ^= (tmp >> 6) ^ tmp;
+                               tmp = iter->dmi_addr[3];
+                               bit  ^= (tmp >> 2) ^ (tmp << 4);
+                               tmp = iter->dmi_addr[4];
+                               bit  ^= (tmp >> 4) ^ (tmp << 2);
+                               tmp = iter->dmi_addr[5];
+                               bit  ^= (tmp >> 6) ^ tmp;
+                               bit &= 0x3f;
+                               hash[bit / 32] |= 1 << (bit % 32);
+                       }
+
+                       cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, hash[0]);
+                       cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, hash[1]);
+               }
+       }
+}
+
+static struct sk_buff *cpmac_rx_one(struct net_device *dev,
+                                   struct cpmac_priv *priv,
+                                   struct cpmac_desc *desc)
+{
+       struct sk_buff *skb, *result = NULL;
+
+       if (unlikely(netif_msg_hw(priv)))
+               cpmac_dump_desc(dev, desc);
+       cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping);
+       if (unlikely(!desc->datalen)) {
+               if (netif_msg_rx_err(priv) && net_ratelimit())
+                       printk(KERN_WARNING "%s: rx: spurious interrupt\n",
+                              dev->name);
+               return NULL;
+       }
+
+       skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE);
+       if (likely(skb)) {
+               skb_reserve(skb, 2);
+               skb_put(desc->skb, desc->datalen);
+               desc->skb->protocol = eth_type_trans(desc->skb, dev);
+               desc->skb->ip_summed = CHECKSUM_NONE;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += desc->datalen;
+               result = desc->skb;
+               dma_unmap_single(&dev->dev, desc->data_mapping, CPMAC_SKB_SIZE,
+                                DMA_FROM_DEVICE);
+               desc->skb = skb;
+               desc->data_mapping = dma_map_single(&dev->dev, skb->data,
+                                                   CPMAC_SKB_SIZE,
+                                                   DMA_FROM_DEVICE);
+               desc->hw_data = (u32)desc->data_mapping;
+               if (unlikely(netif_msg_pktdata(priv))) {
+                       printk(KERN_DEBUG "%s: received packet:\n", dev->name);
+                       cpmac_dump_skb(dev, result);
+               }
+       } else {
+               if (netif_msg_rx_err(priv) && net_ratelimit())
+                       printk(KERN_WARNING
+                              "%s: low on skbs, dropping packet\n", dev->name);
+               dev->stats.rx_dropped++;
+       }
+
+       desc->buflen = CPMAC_SKB_SIZE;
+       desc->dataflags = CPMAC_OWN;
+
+       return result;
+}
+
+static int cpmac_poll(struct net_device *dev, int *budget)
+{
+       struct sk_buff *skb;
+       struct cpmac_desc *desc;
+       int received = 0, quota = min(dev->quota, *budget);
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       spin_lock(&priv->rx_lock);
+       if (unlikely(!priv->rx_head)) {
+               if (netif_msg_rx_err(priv) && net_ratelimit())
+                       printk(KERN_WARNING "%s: rx: polling, but no queue\n",
+                              dev->name);
+               netif_rx_complete(dev);
+               return 0;
+       }
+
+       desc = priv->rx_head;
+       while ((received < quota) && ((desc->dataflags & CPMAC_OWN) == 0)) {
+               skb = cpmac_rx_one(dev, priv, desc);
+               if (likely(skb)) {
+                       netif_receive_skb(skb);
+                       received++;
+               }
+               desc = desc->next;
+       }
+
+       priv->rx_head = desc;
+       spin_unlock(&priv->rx_lock);
+       *budget -= received;
+       dev->quota -= received;
+       if (unlikely(netif_msg_rx_status(priv)))
+               printk(KERN_DEBUG "%s: poll processed %d packets\n", dev->name,
+                      received);
+       if (desc->dataflags & CPMAC_OWN) {
+               netif_rx_complete(dev);
+               cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping);
+               cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       int queue, len;
+       struct cpmac_desc *desc;
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       if (unlikely(skb_padto(skb, ETH_ZLEN))) {
+               if (netif_msg_tx_err(priv) && net_ratelimit())
+                       printk(KERN_WARNING
+                              "%s: tx: padding failed, dropping\n", dev->name);
+               spin_lock(&priv->lock);
+               dev->stats.tx_dropped++;
+               spin_unlock(&priv->lock);
+               return -ENOMEM;
+       }
+
+       len = max(skb->len, ETH_ZLEN);
+       queue = skb->queue_mapping;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       netif_stop_subqueue(dev, queue);
+#else
+       netif_stop_queue(dev);
+#endif
+
+       desc = &priv->desc_ring[queue];
+       if (unlikely(desc->dataflags & CPMAC_OWN)) {
+               if (netif_msg_tx_err(priv) && net_ratelimit())
+                       printk(KERN_WARNING "%s: tx dma ring full, dropping\n",
+                              dev->name);
+               spin_lock(&priv->lock);
+               dev->stats.tx_dropped++;
+               spin_unlock(&priv->lock);
+               dev_kfree_skb_any(skb);
+               return -ENOMEM;
+       }
+
+       spin_lock(&priv->lock);
+       dev->trans_start = jiffies;
+       spin_unlock(&priv->lock);
+       desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN;
+       desc->skb = skb;
+       desc->data_mapping = dma_map_single(&dev->dev, skb->data, len,
+                                           DMA_TO_DEVICE);
+       desc->hw_data = (u32)desc->data_mapping;
+       desc->datalen = len;
+       desc->buflen = len;
+       if (unlikely(netif_msg_tx_queued(priv)))
+               printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb,
+                      skb->len);
+       if (unlikely(netif_msg_hw(priv)))
+               cpmac_dump_desc(dev, desc);
+       if (unlikely(netif_msg_pktdata(priv)))
+               cpmac_dump_skb(dev, skb);
+       cpmac_write(priv->regs, CPMAC_TX_PTR(queue), (u32)desc->mapping);
+
+       return 0;
+}
+
+static void cpmac_end_xmit(struct net_device *dev, int queue)
+{
+       struct cpmac_desc *desc;
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       desc = &priv->desc_ring[queue];
+       cpmac_write(priv->regs, CPMAC_TX_ACK(queue), (u32)desc->mapping);
+       if (likely(desc->skb)) {
+               spin_lock(&priv->lock);
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += desc->skb->len;
+               spin_unlock(&priv->lock);
+               dma_unmap_single(&dev->dev, desc->data_mapping, desc->skb->len,
+                                DMA_TO_DEVICE);
+
+               if (unlikely(netif_msg_tx_done(priv)))
+                       printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name,
+                              desc->skb, desc->skb->len);
+
+               dev_kfree_skb_irq(desc->skb);
+               desc->skb = NULL;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+               if (netif_subqueue_stopped(dev, queue))
+                       netif_wake_subqueue(dev, queue);
+#else
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+#endif
+       } else {
+               if (netif_msg_tx_err(priv) && net_ratelimit())
+                       printk(KERN_WARNING
+                              "%s: end_xmit: spurious interrupt\n", dev->name);
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+               if (netif_subqueue_stopped(dev, queue))
+                       netif_wake_subqueue(dev, queue);
+#else
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+#endif
+       }
+}
+
+static void cpmac_hw_stop(struct net_device *dev)
+{
+       int i;
+       struct cpmac_priv *priv = netdev_priv(dev);
+       struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;
+
+       ar7_device_reset(pdata->reset_bit);
+       cpmac_write(priv->regs, CPMAC_RX_CONTROL,
+                   cpmac_read(priv->regs, CPMAC_RX_CONTROL) & ~1);
+       cpmac_write(priv->regs, CPMAC_TX_CONTROL,
+                   cpmac_read(priv->regs, CPMAC_TX_CONTROL) & ~1);
+       for (i = 0; i < 8; i++) {
+               cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+               cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);
+       }
+       cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_MAC_CONTROL,
+                   cpmac_read(priv->regs, CPMAC_MAC_CONTROL) & ~MAC_MII);
+}
+
+static void cpmac_hw_start(struct net_device *dev)
+{
+       int i;
+       struct cpmac_priv *priv = netdev_priv(dev);
+       struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;
+
+       ar7_device_reset(pdata->reset_bit);
+       for (i = 0; i < 8; i++) {
+               cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+               cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);
+       }
+       cpmac_write(priv->regs, CPMAC_RX_PTR(0), priv->rx_head->mapping);
+
+       cpmac_write(priv->regs, CPMAC_MBP, MBP_RXSHORT | MBP_RXBCAST |
+                   MBP_RXMCAST);
+       cpmac_write(priv->regs, CPMAC_BUFFER_OFFSET, 0);
+       for (i = 0; i < 8; i++)
+               cpmac_write(priv->regs, CPMAC_MAC_ADDR_LO(i), dev->dev_addr[5]);
+       cpmac_write(priv->regs, CPMAC_MAC_ADDR_MID, dev->dev_addr[4]);
+       cpmac_write(priv->regs, CPMAC_MAC_ADDR_HI, dev->dev_addr[0] |
+                   (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) |
+                   (dev->dev_addr[3] << 24));
+       cpmac_write(priv->regs, CPMAC_MAX_LENGTH, CPMAC_SKB_SIZE);
+       cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);
+       cpmac_write(priv->regs, CPMAC_UNICAST_ENABLE, 1);
+       cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
+       cpmac_write(priv->regs, CPMAC_TX_INT_ENABLE, 0xff);
+       cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3);
+
+       cpmac_write(priv->regs, CPMAC_RX_CONTROL,
+                   cpmac_read(priv->regs, CPMAC_RX_CONTROL) | 1);
+       cpmac_write(priv->regs, CPMAC_TX_CONTROL,
+                   cpmac_read(priv->regs, CPMAC_TX_CONTROL) | 1);
+       cpmac_write(priv->regs, CPMAC_MAC_CONTROL,
+                   cpmac_read(priv->regs, CPMAC_MAC_CONTROL) | MAC_MII |
+                   MAC_FDX);
+}
+
+static void cpmac_clear_rx(struct net_device *dev)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+       struct cpmac_desc *desc;
+       int i;
+       if (unlikely(!priv->rx_head))
+               return;
+       desc = priv->rx_head;
+       for (i = 0; i < priv->ring_size; i++) {
+               if ((desc->dataflags & CPMAC_OWN) == 0) {
+                       if (netif_msg_rx_err(priv) && net_ratelimit())
+                               printk(KERN_WARNING "%s: packet dropped\n",
+                                      dev->name);
+                       if (unlikely(netif_msg_hw(priv)))
+                               cpmac_dump_desc(dev, desc);
+                       desc->dataflags = CPMAC_OWN;
+                       dev->stats.rx_dropped++;
+               }
+               desc = desc->next;
+       }
+}
+
+static void cpmac_clear_tx(struct net_device *dev)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+       int i;
+       if (unlikely(!priv->desc_ring))
+               return;
+       for (i = 0; i < CPMAC_QUEUES; i++)
+               if (priv->desc_ring[i].skb) {
+                       dev_kfree_skb_any(priv->desc_ring[i].skb);
+                       if (netif_subqueue_stopped(dev, i))
+                           netif_wake_subqueue(dev, i);
+               }
+}
+
+static void cpmac_hw_error(struct work_struct *work)
+{
+       struct cpmac_priv *priv =
+               container_of(work, struct cpmac_priv, reset_work);
+
+       spin_lock(&priv->rx_lock);
+       cpmac_clear_rx(priv->dev);
+       spin_unlock(&priv->rx_lock);
+       cpmac_clear_tx(priv->dev);
+       cpmac_hw_start(priv->dev);
+       netif_start_queue(priv->dev);
+}
+
+static irqreturn_t cpmac_irq(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct cpmac_priv *priv;
+       int queue;
+       u32 status;
+
+       if (!dev)
+               return IRQ_NONE;
+
+       priv = netdev_priv(dev);
+
+       status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR);
+
+       if (unlikely(netif_msg_intr(priv)))
+               printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name,
+                      status);
+
+       if (status & MAC_INT_TX)
+               cpmac_end_xmit(dev, (status & 7));
+
+       if (status & MAC_INT_RX) {
+               queue = (status >> 8) & 7;
+               netif_rx_schedule(dev);
+               cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue);
+       }
+
+       cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0);
+
+       if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) {
+               if (netif_msg_drv(priv) && net_ratelimit())
+                       printk(KERN_ERR "%s: hw error, resetting...\n",
+                              dev->name);
+               netif_stop_queue(dev);
+               cpmac_hw_stop(dev);
+               schedule_work(&priv->reset_work);
+               if (unlikely(netif_msg_hw(priv)))
+                       cpmac_dump_regs(dev);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void cpmac_tx_timeout(struct net_device *dev)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+       int i;
+
+       spin_lock(&priv->lock);
+       dev->stats.tx_errors++;
+       spin_unlock(&priv->lock);
+       if (netif_msg_tx_err(priv) && net_ratelimit())
+               printk(KERN_WARNING "%s: transmit timeout\n", dev->name);
+       /* 
+        * FIXME: waking up random queue is not the best thing to
+        * do... on the other hand why we got here at all?
+        */
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       for (i = 0; i < CPMAC_QUEUES; i++)
+               if (priv->desc_ring[i].skb) {
+                       dev_kfree_skb_any(priv->desc_ring[i].skb);
+                       netif_wake_subqueue(dev, i);
+                       break;
+               }
+#else
+       if (priv->desc_ring[0].skb)
+               dev_kfree_skb_any(priv->desc_ring[0].skb);
+       netif_wake_queue(dev);
+#endif
+}
+
+static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+       if (!(netif_running(dev)))
+               return -EINVAL;
+       if (!priv->phy)
+               return -EINVAL;
+       if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) ||
+           (cmd == SIOCSMIIREG))
+               return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd);
+
+       return -EOPNOTSUPP;
+}
+
+static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       if (priv->phy)
+               return phy_ethtool_gset(priv->phy, cmd);
+
+       return -EINVAL;
+}
+
+static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (priv->phy)
+               return phy_ethtool_sset(priv->phy, cmd);
+
+       return -EINVAL;
+}
+
+static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       ring->rx_max_pending = 1024;
+       ring->rx_mini_max_pending = 1;
+       ring->rx_jumbo_max_pending = 1;
+       ring->tx_max_pending = 1;
+
+       ring->rx_pending = priv->ring_size;
+       ring->rx_mini_pending = 1;
+       ring->rx_jumbo_pending = 1;
+       ring->tx_pending = 1;
+}
+
+static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+
+       if (dev->flags && IFF_UP)
+               return -EBUSY;
+       priv->ring_size = ring->rx_pending;
+       return 0;
+}
+
+static void cpmac_get_drvinfo(struct net_device *dev,
+                             struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, "cpmac");
+       strcpy(info->version, CPMAC_VERSION);
+       info->fw_version[0] = '\0';
+       sprintf(info->bus_info, "%s", "cpmac");
+       info->regdump_len = 0;
+}
+
+static const struct ethtool_ops cpmac_ethtool_ops = {
+       .get_settings = cpmac_get_settings,
+       .set_settings = cpmac_set_settings,
+       .get_drvinfo = cpmac_get_drvinfo,
+       .get_link = ethtool_op_get_link,
+       .get_ringparam = cpmac_get_ringparam,
+       .set_ringparam = cpmac_set_ringparam,
+};
+
+static void cpmac_adjust_link(struct net_device *dev)
+{
+       struct cpmac_priv *priv = netdev_priv(dev);
+       int new_state = 0;
+
+       spin_lock(&priv->lock);
+       if (priv->phy->link) {
+               netif_start_queue(dev);
+               if (priv->phy->duplex != priv->oldduplex) {
+                       new_state = 1;
+                       priv->oldduplex = priv->phy->duplex;
+               }
+
+               if (priv->phy->speed != priv->oldspeed) {
+                       new_state = 1;
+                       priv->oldspeed = priv->phy->speed;
+               }
+
+               if (!priv->oldlink) {
+                       new_state = 1;
+                       priv->oldlink = 1;
+                       netif_schedule(dev);
+               }
+       } else if (priv->oldlink) {
+               netif_stop_queue(dev);
+               new_state = 1;
+               priv->oldlink = 0;
+               priv->oldspeed = 0;
+               priv->oldduplex = -1;
+       }
+
+       if (new_state && netif_msg_link(priv) && net_ratelimit())
+               phy_print_status(priv->phy);
+
+       spin_unlock(&priv->lock);
+}
+
+static int cpmac_open(struct net_device *dev)
+{
+       int i, size, res;
+       struct cpmac_priv *priv = netdev_priv(dev);
+       struct resource *mem;
+       struct cpmac_desc *desc;
+       struct sk_buff *skb;
+
+       priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link,
+                               0, PHY_INTERFACE_MODE_MII);
+       if (IS_ERR(priv->phy)) {
+               if (netif_msg_drv(priv))
+                       printk(KERN_ERR "%s: Could not attach to PHY\n",
+                              dev->name);
+               return PTR_ERR(priv->phy);
+       }
+
+       mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
+       if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) {
+               if (netif_msg_drv(priv))
+                       printk(KERN_ERR "%s: failed to request registers\n",
+                              dev->name);
+               res = -ENXIO;
+               goto fail_reserve;
+       }
+
+       priv->regs = ioremap(mem->start, mem->end - mem->start);
+       if (!priv->regs) {
+               if (netif_msg_drv(priv))
+                       printk(KERN_ERR "%s: failed to remap registers\n",
+                              dev->name);
+               res = -ENXIO;
+               goto fail_remap;
+       }
+
+       size = priv->ring_size + CPMAC_QUEUES;
+       priv->desc_ring = dma_alloc_coherent(&dev->dev,
+                                            sizeof(struct cpmac_desc) * size,
+                                            &priv->dma_ring,
+                                            GFP_KERNEL);
+       if (!priv->desc_ring) {
+               res = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       for (i = 0; i < size; i++)
+               priv->desc_ring[i].mapping = priv->dma_ring + sizeof(*desc) * i;
+
+       priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
+       for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) {
+               skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE);
+               if (unlikely(!skb)) {
+                       res = -ENOMEM;
+                       goto fail_desc;
+               }
+               skb_reserve(skb, 2);
+               desc->skb = skb;
+               desc->data_mapping = dma_map_single(&dev->dev, skb->data,
+                                                   CPMAC_SKB_SIZE,
+                                                   DMA_FROM_DEVICE);
+               desc->hw_data = (u32)desc->data_mapping;
+               desc->buflen = CPMAC_SKB_SIZE;
+               desc->dataflags = CPMAC_OWN;
+               desc->next = &priv->rx_head[(i + 1) % priv->ring_size];
+               desc->hw_next = (u32)desc->next->mapping;
+       }
+
+       if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED,
+                              dev->name, dev))) {
+               if (netif_msg_drv(priv))
+                       printk(KERN_ERR "%s: failed to obtain irq\n",
+                              dev->name);
+               goto fail_irq;
+       }
+
+       INIT_WORK(&priv->reset_work, cpmac_hw_error);
+       cpmac_hw_start(dev);
+
+       priv->phy->state = PHY_CHANGELINK;
+       phy_start(priv->phy);
+
+       return 0;
+
+fail_irq:
+fail_desc:
+       for (i = 0; i < priv->ring_size; i++) {
+               if (priv->rx_head[i].skb) {
+                       dma_unmap_single(&dev->dev,
+                                        priv->rx_head[i].data_mapping,
+                                        CPMAC_SKB_SIZE,
+                                        DMA_FROM_DEVICE);
+                       kfree_skb(priv->rx_head[i].skb);
+               }
+       }
+fail_alloc:
+       kfree(priv->desc_ring);
+       iounmap(priv->regs);
+
+fail_remap:
+       release_mem_region(mem->start, mem->end - mem->start);
+
+fail_reserve:
+       phy_disconnect(priv->phy);
+
+       return res;
+}
+
+static int cpmac_stop(struct net_device *dev)
+{
+       int i;
+       struct cpmac_priv *priv = netdev_priv(dev);
+       struct resource *mem;
+
+       netif_stop_queue(dev);
+
+       cancel_work_sync(&priv->reset_work);
+       phy_stop(priv->phy);
+       phy_disconnect(priv->phy);
+       priv->phy = NULL;
+
+       cpmac_hw_stop(dev);
+
+       for (i = 0; i < 8; i++)
+               cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+       cpmac_write(priv->regs, CPMAC_RX_PTR(0), 0);
+       cpmac_write(priv->regs, CPMAC_MBP, 0);
+
+       free_irq(dev->irq, dev);
+       iounmap(priv->regs);
+       mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
+       release_mem_region(mem->start, mem->end - mem->start);
+       priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
+       for (i = 0; i < priv->ring_size; i++) {
+               if (priv->rx_head[i].skb) {
+                       dma_unmap_single(&dev->dev,
+                                        priv->rx_head[i].data_mapping,
+                                        CPMAC_SKB_SIZE,
+                                        DMA_FROM_DEVICE);
+                       kfree_skb(priv->rx_head[i].skb);
+               }
+       }
+
+       dma_free_coherent(&dev->dev, sizeof(struct cpmac_desc) *
+                         (CPMAC_QUEUES + priv->ring_size),
+                         priv->desc_ring, priv->dma_ring);
+       return 0;
+}
+
+static int external_switch;
+
+static int __devinit cpmac_probe(struct platform_device *pdev)
+{
+       int rc, phy_id;
+       struct resource *mem;
+       struct cpmac_priv *priv;
+       struct net_device *dev;
+       struct plat_cpmac_data *pdata;
+
+       pdata = pdev->dev.platform_data;
+
+       for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
+               if (!(pdata->phy_mask & (1 << phy_id)))
+                       continue;
+               if (!cpmac_mii.phy_map[phy_id])
+                       continue;
+               break;
+       }
+
+       if (phy_id == PHY_MAX_ADDR) {
+               if (external_switch || dumb_switch)
+                       phy_id = 0;
+               else {
+                       printk(KERN_ERR "cpmac: no PHY present\n");
+                       return -ENODEV;
+               }
+       }
+
+       dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES);
+
+       if (!dev) {
+               printk(KERN_ERR "cpmac: Unable to allocate net_device\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, dev);
+       priv = netdev_priv(dev);
+
+       priv->pdev = pdev;
+       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+       if (!mem) {
+               rc = -ENODEV;
+               goto fail;
+       }
+
+       dev->irq = platform_get_irq_byname(pdev, "irq");
+
+       dev->open               = cpmac_open;
+       dev->stop               = cpmac_stop;
+       dev->set_config         = cpmac_config;
+       dev->hard_start_xmit    = cpmac_start_xmit;
+       dev->do_ioctl           = cpmac_ioctl;
+       dev->set_multicast_list = cpmac_set_multicast_list;
+       dev->tx_timeout         = cpmac_tx_timeout;
+       dev->ethtool_ops        = &cpmac_ethtool_ops;
+       dev->poll = cpmac_poll;
+       dev->weight = 64;
+       dev->features |= NETIF_F_MULTI_QUEUE;
+
+       spin_lock_init(&priv->lock);
+       spin_lock_init(&priv->rx_lock);
+       priv->dev = dev;
+       priv->ring_size = 64;
+       priv->msg_enable = netif_msg_init(debug_level, 0xff);
+       memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
+       if (phy_id == 31) {
+               snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT,
+                        cpmac_mii.id, phy_id);
+       } else
+               snprintf(priv->phy_name, BUS_ID_SIZE, "fixed@%d:%d", 100, 1);
+
+       if ((rc = register_netdev(dev))) {
+               printk(KERN_ERR "cpmac: error %i registering device %s\n", rc,
+                      dev->name);
+               goto fail;
+       }
+
+       if (netif_msg_probe(priv)) {
+               printk(KERN_INFO
+                      "cpmac: device %s (regs: %p, irq: %d, phy: %s, mac: "
+                      MAC_FMT ")\n", dev->name, (void *)mem->start, dev->irq,
+                      priv->phy_name, MAC_ARG(dev->dev_addr));
+       }
+       return 0;
+
+fail:
+       free_netdev(dev);
+       return rc;
+}
+
+static int __devexit cpmac_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       unregister_netdev(dev);
+       free_netdev(dev);
+       return 0;
+}
+
+static struct platform_driver cpmac_driver = {
+       .driver.name = "cpmac",
+       .probe = cpmac_probe,
+       .remove = __devexit_p(cpmac_remove),
+};
+
+int __devinit cpmac_init(void)
+{
+       u32 mask;
+       int i, res;
+
+       cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256);
+
+       if (!cpmac_mii.priv) {
+               printk(KERN_ERR "Can't ioremap mdio registers\n");
+               return -ENXIO;
+       }
+
+#warning FIXME: unhardcode gpio&reset bits
+       ar7_gpio_disable(26);
+       ar7_gpio_disable(27);
+       ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);
+       ar7_device_reset(AR7_RESET_BIT_CPMAC_HI);
+       ar7_device_reset(AR7_RESET_BIT_EPHY);
+
+       cpmac_mii.reset(&cpmac_mii);
+
+       for (i = 0; i < 300000; i++)
+               if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE)))
+                       break;
+               else
+                       cpu_relax();
+
+       mask &= 0x7fffffff;
+       if (mask & (mask - 1)) {
+               external_switch = 1;
+               mask = 0;
+       }
+
+       cpmac_mii.phy_mask = ~(mask | 0x80000000);
+
+       res = mdiobus_register(&cpmac_mii);
+       if (res)
+               goto fail_mii;
+
+       res = platform_driver_register(&cpmac_driver);
+       if (res)
+               goto fail_cpmac;
+
+       return 0;
+
+fail_cpmac:
+       mdiobus_unregister(&cpmac_mii);
+
+fail_mii:
+       iounmap(cpmac_mii.priv);
+
+       return res;
+}
+
+void __devexit cpmac_exit(void)
+{
+       platform_driver_unregister(&cpmac_driver);
+       mdiobus_unregister(&cpmac_mii);
+       iounmap(cpmac_mii.priv);
+}
+
+module_init(cpmac_init);
+module_exit(cpmac_exit);
index 0db5e6fabe73146ddc1f29e4e3b220f3ce4fcfec..558440c15b6c47c183bc4d86bf6d87ef2984f5dd 100644 (file)
@@ -168,7 +168,6 @@ static int gfar_probe(struct platform_device *pdev)
        struct gfar_private *priv = NULL;
        struct gianfar_platform_data *einfo;
        struct resource *r;
-       int idx;
        int err = 0;
        DECLARE_MAC_BUF(mac);
 
@@ -261,7 +260,9 @@ static int gfar_probe(struct platform_device *pdev)
        dev->hard_start_xmit = gfar_start_xmit;
        dev->tx_timeout = gfar_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_GFAR_NAPI
        netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
+#endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = gfar_netpoll;
 #endif
@@ -931,9 +932,14 @@ tx_skb_fail:
 /* Returns 0 for success. */
 static int gfar_enet_open(struct net_device *dev)
 {
+#ifdef CONFIG_GFAR_NAPI
+       struct gfar_private *priv = netdev_priv(dev);
+#endif
        int err;
 
+#ifdef CONFIG_GFAR_NAPI
        napi_enable(&priv->napi);
+#endif
 
        /* Initialize a bunch of registers */
        init_registers(dev);
@@ -943,13 +949,17 @@ static int gfar_enet_open(struct net_device *dev)
        err = init_phy(dev);
 
        if(err) {
+#ifdef CONFIG_GFAR_NAPI
                napi_disable(&priv->napi);
+#endif
                return err;
        }
 
        err = startup_gfar(dev);
        if (err)
+#ifdef CONFIG_GFAR_NAPI
                napi_disable(&priv->napi);
+#endif
 
        netif_start_queue(dev);
 
@@ -1103,7 +1113,9 @@ static int gfar_close(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
+#ifdef CONFIG_GFAR_NAPI
        napi_disable(&priv->napi);
+#endif
 
        stop_gfar(dev);
 
index ecd156def0398b24864313843b712caa186fb9ca..ad9e327c3b0366a99cd670d8be71dbdc64af6b12 100644 (file)
@@ -292,7 +292,7 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev,
                     const void *saddr, unsigned len)
 {
 #ifdef CONFIG_INET
-       if (type != htons(ETH_P_AX25))
+       if (type != ETH_P_AX25)
                return ax25_hard_header(skb, dev, type, daddr, saddr, len);
 #endif
        return 0;
index 9e43c47691caa4c9d12a6015a1668277424c3b25..803a3bdea0af5f1e36d02055157f55107aff7c87 100644 (file)
@@ -583,7 +583,7 @@ static int ax_header(struct sk_buff *skb, struct net_device *dev,
                     const void *saddr, unsigned len)
 {
 #ifdef CONFIG_INET
-       if (type != htons(ETH_P_AX25))
+       if (type != ETH_P_AX25)
                return ax25_hard_header(skb, dev, type, daddr, saddr, len);
 #endif
        return 0;
index 4e49e8c4f8715306c3606dc1e7b67542d589c674..dcd8826fc749964b96e596895daebdc967a33f5a 100644 (file)
@@ -413,7 +413,10 @@ static int __init mal_probe(struct ocp_device *ocpdev)
                       ocpdev->def->index);
                return -ENOMEM;
        }
-       mal->dcrbase = maldata->dcr_base;
+
+       /* XXX This only works for native dcr for now */
+       mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0);
+
        mal->def = ocpdev->def;
 
        INIT_LIST_HEAD(&mal->poll_list);
index 8f54d621994d0c058f210f6f1f6a9e2070242460..b8adbe6d4b015e31145ece21a3470b73f2b818e8 100644 (file)
@@ -191,7 +191,6 @@ struct mal_commac {
 };
 
 struct ibm_ocp_mal {
-       int                     dcrbase;
        dcr_host_t              dcrhost;
 
        struct list_head        poll_list;
@@ -209,12 +208,12 @@ struct ibm_ocp_mal {
 
 static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
 {
-       return dcr_read(mal->dcrhost, mal->dcrbase + reg);
+       return dcr_read(mal->dcrhost, reg);
 }
 
 static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
 {
-       dcr_write(mal->dcrhost, mal->dcrbase + reg, val);
+       dcr_write(mal->dcrhost, reg, val);
 }
 
 /* Register MAL devices */
index 8ea500961871e79ce6e713199756e536797db441..0de3aa2a2e44172d99598556ee7d5b2e9c721997 100644 (file)
@@ -1534,7 +1534,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
                        dev_kfree_skb(dev->rx_sg_skb);
                        dev->rx_sg_skb = NULL;
                } else {
-                       cacheable_memcpy(dev->rx_sg_skb->tail,
+                       cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb),
                                         dev->rx_skb[slot]->data, len);
                        skb_put(dev->rx_sg_skb, len);
                        emac_recycle_rx_skb(dev, slot, len);
@@ -1950,7 +1950,7 @@ static u32 emac_ethtool_get_rx_csum(struct net_device *ndev)
 {
        struct emac_instance *dev = netdev_priv(ndev);
 
-       return dev->tah_dev != 0;
+       return dev->tah_dev != NULL;
 }
 
 static int emac_get_regs_len(struct emac_instance *dev)
index 58854117b1a9e9ff7049cd034c5e3b475f007e13..39f4cb6b0cf385f4aad928c99eb5984f79e2b8dc 100644 (file)
@@ -461,6 +461,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
        struct mal_instance *mal;
        int err = 0, i, bd_size;
        int index = mal_count++;
+       unsigned int dcr_base;
        const u32 *prop;
        u32 cfg;
 
@@ -497,14 +498,14 @@ static int __devinit mal_probe(struct of_device *ofdev,
        }
        mal->num_rx_chans = prop[0];
 
-       mal->dcr_base = dcr_resource_start(ofdev->node, 0);
-       if (mal->dcr_base == 0) {
+       dcr_base = dcr_resource_start(ofdev->node, 0);
+       if (dcr_base == 0) {
                printk(KERN_ERR
                       "mal%d: can't find DCR resource!\n", index);
                err = -ENODEV;
                goto fail;
        }
-        mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100);
+       mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100);
        if (!DCR_MAP_OK(mal->dcr_host)) {
                printk(KERN_ERR
                       "mal%d: failed to map DCRs !\n", index);
@@ -626,7 +627,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
  fail2:
        dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
  fail_unmap:
-       dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100);
+       dcr_unmap(mal->dcr_host, 0x100);
  fail:
        kfree(mal);
 
index cb1a16d589fe780f74df1077ebc486fba93fd22c..784edb8ea8220a285198e16e73c2bd1d67b73c32 100644 (file)
@@ -185,7 +185,6 @@ struct mal_commac {
 
 struct mal_instance {
        int                     version;
-       int                     dcr_base;
        dcr_host_t              dcr_host;
 
        int                     num_tx_chans;   /* Number of TX channels */
@@ -213,12 +212,12 @@ struct mal_instance {
 
 static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
 {
-       return dcr_read(mal->dcr_host, mal->dcr_base + reg);
+       return dcr_read(mal->dcr_host, reg);
 }
 
 static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
 {
-       dcr_write(mal->dcr_host, mal->dcr_base + reg, val);
+       dcr_write(mal->dcr_host, reg, val);
 }
 
 /* Register MAL devices */
index bcd7fc639c40a99411074fcd7bed0891c47be0f6..de416951a435287eaf86432baf45a6a021b4baf0 100644 (file)
@@ -84,7 +84,7 @@ static inline u32 rgmii_mode_mask(int mode, int input)
 int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
 {
        struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct rgmii_regs *p = dev->base;
+       struct rgmii_regs __iomem *p = dev->base;
 
        RGMII_DBG(dev, "attach(%d)" NL, input);
 
@@ -113,7 +113,7 @@ int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
 void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
 {
        struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct rgmii_regs *p = dev->base;
+       struct rgmii_regs __iomem *p = dev->base;
        u32 ssr;
 
        mutex_lock(&dev->lock);
@@ -135,7 +135,7 @@ void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
 void rgmii_get_mdio(struct of_device *ofdev, int input)
 {
        struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct rgmii_regs *p = dev->base;
+       struct rgmii_regs __iomem *p = dev->base;
        u32 fer;
 
        RGMII_DBG2(dev, "get_mdio(%d)" NL, input);
@@ -156,7 +156,7 @@ void rgmii_get_mdio(struct of_device *ofdev, int input)
 void rgmii_put_mdio(struct of_device *ofdev, int input)
 {
        struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct rgmii_regs *p = dev->base;
+       struct rgmii_regs __iomem *p = dev->base;
        u32 fer;
 
        RGMII_DBG2(dev, "put_mdio(%d)" NL, input);
@@ -177,7 +177,7 @@ void rgmii_put_mdio(struct of_device *ofdev, int input)
 void __devexit rgmii_detach(struct of_device *ofdev, int input)
 {
        struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct rgmii_regs *p = dev->base;
+       struct rgmii_regs __iomem *p = dev->base;
 
        mutex_lock(&dev->lock);
 
@@ -242,7 +242,7 @@ static int __devinit rgmii_probe(struct of_device *ofdev,
        }
 
        rc = -ENOMEM;
-       dev->base = (struct rgmii_regs *)ioremap(regs.start,
+       dev->base = (struct rgmii_regs __iomem *)ioremap(regs.start,
                                                 sizeof(struct rgmii_regs));
        if (dev->base == NULL) {
                printk(KERN_ERR "%s: Can't map device registers!\n",
@@ -251,7 +251,7 @@ static int __devinit rgmii_probe(struct of_device *ofdev,
        }
 
        /* Check for RGMII type */
-       if (device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
+       if (of_device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
                dev->type = RGMII_AXON;
        else
                dev->type = RGMII_STANDARD;
index e05c7e81efb60ff7aa5b9d8bff2703fc44493be1..f161fb100e8e671f1ec41a200fac023906eae058 100644 (file)
@@ -42,7 +42,7 @@ void __devexit tah_detach(struct of_device *ofdev, int channel)
 void tah_reset(struct of_device *ofdev)
 {
        struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct tah_regs *p = dev->base;
+       struct tah_regs __iomem *p = dev->base;
        int n;
 
        /* Reset TAH */
@@ -108,7 +108,7 @@ static int __devinit tah_probe(struct of_device *ofdev,
        }
 
        rc = -ENOMEM;
-       dev->base = (struct tah_regs *)ioremap(regs.start,
+       dev->base = (struct tah_regs __iomem *)ioremap(regs.start,
                                               sizeof(struct tah_regs));
        if (dev->base == NULL) {
                printk(KERN_ERR "%s: Can't map device registers!\n",
index d06312901848f75b8dcb0b00303e70fcfc9bf2a7..2219ec2740e056f37f12619613c94f49c4e6fcd0 100644 (file)
@@ -79,7 +79,7 @@ static inline u32 zmii_mode_mask(int mode, int input)
 int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode)
 {
        struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-       struct zmii_regs *p = dev->base;
+       struct zmii_regs __iomem *p = dev->base;
 
        ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
 
@@ -250,7 +250,7 @@ static int __devinit zmii_probe(struct of_device *ofdev,
        }
 
        rc = -ENOMEM;
-       dev->base = (struct zmii_regs *)ioremap(regs.start,
+       dev->base = (struct zmii_regs __iomem *)ioremap(regs.start,
                                                sizeof(struct zmii_regs));
        if (dev->base == NULL) {
                printk(KERN_ERR "%s: Can't map device registers!\n",
index 59898ce54dcf3170a7579d28aa12c0d4bce35bee..68887235d7e995f9b939ee8e11c9435d30cbf64b 100644 (file)
@@ -754,7 +754,7 @@ static int init_rfdlist(struct net_device *dev)
 
                if (sp->RxBuff[i]) {
                        pci_unmap_single(sp->pdev,
-                               le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+                               le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
                                sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
                        IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
                        sp->RxBuff[i] = NULL;
@@ -871,7 +871,7 @@ static void ipg_nic_txfree(struct net_device *dev)
                /* Free the transmit buffer. */
                if (skb) {
                        pci_unmap_single(sp->pdev,
-                               le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+                               le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
                                skb->len, PCI_DMA_TODEVICE);
 
                        IPG_DEV_KFREE_SKB(skb);
@@ -1413,10 +1413,10 @@ static int ipg_nic_rx(struct net_device *dev)
                        framelen = IPG_RXFRAG_SIZE;
                }
 
-               if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs &
+               if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
                       (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
                        IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
-                       IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) {
+                       IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) {
 
                        IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
                                      (unsigned long int) rxfd->rfs);
@@ -1425,27 +1425,27 @@ static int ipg_nic_rx(struct net_device *dev)
                        sp->stats.rx_errors++;
 
                        /* Increment detailed receive error statistics. */
-                       if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) {
+                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
                                IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
                                sp->stats.rx_fifo_errors++;
                        }
 
-                       if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) {
+                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
                                IPG_DEBUG_MSG("RX runt occured.\n");
                                sp->stats.rx_length_errors++;
                        }
 
-                       if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ;
+                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ;
                        /* Do nothing, error count handled by a IPG
                         * statistic register.
                         */
 
-                       if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) {
+                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
                                IPG_DEBUG_MSG("RX alignment error occured.\n");
                                sp->stats.rx_frame_errors++;
                        }
 
-                       if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ;
+                       if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ;
                        /* Do nothing, error count handled by a IPG
                         * statistic register.
                         */
@@ -1455,10 +1455,10 @@ static int ipg_nic_rx(struct net_device *dev)
                         * not pass it to higher layer processes.
                         */
                        if (skb) {
-                               u64 info = rxfd->frag_info;
+                               __le64 info = rxfd->frag_info;
 
                                pci_unmap_single(sp->pdev,
-                                       le64_to_cpu(info & ~IPG_RFI_FRAGLEN),
+                                       le64_to_cpu(info) & ~IPG_RFI_FRAGLEN,
                                        sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
                                IPG_DEV_KFREE_SKB(skb);
@@ -1532,9 +1532,9 @@ static int ipg_nic_rx(struct net_device *dev)
        if (!i)
                sp->EmptyRFDListCount++;
 #endif
-       while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) &&
-              !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) &&
-                (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) {
+       while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) &&
+              !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) &&
+                (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) {
                unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
 
                rxfd = sp->rxd + entry;
@@ -1552,7 +1552,7 @@ static int ipg_nic_rx(struct net_device *dev)
                 */
                if (sp->RxBuff[entry]) {
                        pci_unmap_single(sp->pdev,
-                               le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+                               le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
                                sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
                        IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
                }
@@ -1730,7 +1730,7 @@ static void ipg_rx_clear(struct ipg_nic_private *sp)
                        IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
                        sp->RxBuff[i] = NULL;
                        pci_unmap_single(sp->pdev,
-                               le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+                               le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
                                sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
                }
        }
@@ -1745,7 +1745,7 @@ static void ipg_tx_clear(struct ipg_nic_private *sp)
                        struct ipg_tx *txfd = sp->txd + i;
 
                        pci_unmap_single(sp->pdev,
-                               le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+                               le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
                                sp->TxBuff[i]->len, PCI_DMA_TODEVICE);
 
                        IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
index 1952d0dfd314b1c0375fa0d351a1b4a3b1f5a29d..e418b9035caceb3be77a4927896df424daf39245 100644 (file)
@@ -776,17 +776,17 @@ enum ipg_regs {
  * TFD field is 64 bits wide.
  */
 struct ipg_tx {
-       u64 next_desc;
-       u64 tfc;
-       u64 frag_info;
+       __le64 next_desc;
+       __le64 tfc;
+       __le64 frag_info;
 };
 
 /* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
  */
 struct ipg_rx {
-       u64 next_desc;
-       u64 rfs;
-       u64 frag_info;
+       __le64 next_desc;
+       __le64 rfs;
+       __le64 frag_info;
 };
 
 struct SJumbo {
index 3e5eca1aa98761ecf932f6d47d895dfda1e1a7a9..a82d8f98383d82160d6548549b9def1c7071472c 100644 (file)
@@ -840,7 +840,7 @@ toshoboe_probe (struct toshoboe_cb *self)
 
   /* test 1: SIR filter and back to back */
 
-  for (j = 0; j < (sizeof (bauds) / sizeof (int)); ++j)
+  for (j = 0; j < ARRAY_SIZE(bauds); ++j)
     {
       int fir = (j > 1);
       toshoboe_stopchip (self);
index d3825c8ee99493fc01cfb65a0e25bfe07a285bd3..5c154fe1385956d2797a8946000397b4558631a0 100644 (file)
@@ -208,7 +208,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev)
        struct sonic_local *lp;
        struct resource *res;
        int err = 0;
-       int i;
        DECLARE_MAC_BUF(mac);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 6589239b79ee55e4ecacc43b0997ab49ca164877..18770527df995920047ceaad093b023cfd9c1d4d 100644 (file)
@@ -538,8 +538,9 @@ static void mace_set_multicast(struct net_device *dev)
        local_irq_restore(flags);
 }
 
-static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+static void mace_handle_misc_intrs(struct net_device *dev, int intr)
 {
+       struct mace_data *mp = netdev_priv(dev);
        volatile struct mace *mb = mp->mace;
        static int mace_babbles, mace_jabbers;
 
@@ -571,7 +572,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
        local_irq_save(flags);
 
        intr = mb->ir; /* read interrupt register */
-       mace_handle_misc_intrs(mp, intr);
+       mace_handle_misc_intrs(dev, intr);
 
        if (intr & XMTINT) {
                fs = mb->xmtfs;
@@ -645,7 +646,6 @@ static void mace_tx_timeout(struct net_device *dev)
 
 static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
 {
-       struct mace_data *mp = netdev_priv(dev);
        struct sk_buff *skb;
        unsigned int frame_status = mf->rcvsts;
 
index b7c81c874f7a0a15e4bd65281aa9ceeb1e83b0cf..2e4bcd5654c4c0b62db0e795f87c96d73c176207 100644 (file)
@@ -178,7 +178,6 @@ static const struct header_ops macvlan_hard_header_ops = {
        .create         = macvlan_hard_header,
        .rebuild        = eth_rebuild_header,
        .parse          = eth_header_parse,
-       .rebuild        = eth_rebuild_header,
        .cache          = eth_header_cache,
        .cache_update   = eth_header_cache_update,
 };
index d593175ab6f02e413474f4e6c0cddebb93414898..37707a0c0498cd7f5b65269ba8150af5e4f9a651 100644 (file)
@@ -7,12 +7,12 @@
 #define DEBUG
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/platform_device.h>
-#include <asm/io.h>
 #include <asm/mips-boards/simint.h>
 
 #include "mipsnet.h"           /* actual device IO mapping */
@@ -33,9 +33,8 @@ static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
        if (available_len < len)
                return -EFAULT;
 
-       for (; len > 0; len--, kdata++) {
+       for (; len > 0; len--, kdata++)
                *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer));
-       }
 
        return inl(mipsnet_reg_address(dev, rxDataCount));
 }
@@ -47,16 +46,15 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
        char *buf_ptr = skb->data;
 
        pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n",
-                dev->name, __FUNCTION__, skb->len);
+                dev->name, __FUNCTION__, skb->len);
 
        outl(skb->len, mipsnet_reg_address(dev, txDataCount));
 
        pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n",
-                dev->name, __FUNCTION__, skb->len);
+                dev->name, __FUNCTION__, skb->len);
 
-       for (; count_to_go; buf_ptr++, count_to_go--) {
+       for (; count_to_go; buf_ptr++, count_to_go--)
                outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
-       }
 
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
@@ -67,7 +65,7 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
 static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        pr_debug("%s:%s(): transmitting %d bytes\n",
-                dev->name, __FUNCTION__, skb->len);
+                dev->name, __FUNCTION__, skb->len);
 
        /* Only one packet at a time. Once TXDONE interrupt is serviced, the
         * queue will be restarted.
@@ -83,7 +81,8 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
        struct sk_buff *skb;
        size_t len = count;
 
-       if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
+       skb = alloc_skb(len + 2, GFP_KERNEL);
+       if (!skb) {
                dev->stats.rx_dropped++;
                return -ENOMEM;
        }
@@ -96,7 +95,7 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
        pr_debug("%s:%s(): pushing RXed data to kernel\n",
-                dev->name, __FUNCTION__);
+                dev->name, __FUNCTION__);
        netif_rx(skb);
 
        dev->stats.rx_packets++;
@@ -114,42 +113,44 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
 
        if (irq == dev->irq) {
                pr_debug("%s:%s(): irq %d for device\n",
-                        dev->name, __FUNCTION__, irq);
+                        dev->name, __FUNCTION__, irq);
 
                retval = IRQ_HANDLED;
 
                interruptFlags =
                    inl(mipsnet_reg_address(dev, interruptControl));
                pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name,
-                        __FUNCTION__, interruptFlags);
+                        __FUNCTION__, interruptFlags);
 
                if (interruptFlags & MIPSNET_INTCTL_TXDONE) {
                        pr_debug("%s:%s(): got TXDone\n",
-                                dev->name, __FUNCTION__);
+                                dev->name, __FUNCTION__);
                        outl(MIPSNET_INTCTL_TXDONE,
                             mipsnet_reg_address(dev, interruptControl));
-                       // only one packet at a time, we are done.
+                       /* only one packet at a time, we are done. */
                        netif_wake_queue(dev);
                } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) {
                        pr_debug("%s:%s(): got RX data\n",
-                                dev->name, __FUNCTION__);
+                                dev->name, __FUNCTION__);
                        mipsnet_get_fromdev(dev,
-                                   inl(mipsnet_reg_address(dev, rxDataCount)));
+                                   inl(mipsnet_reg_address(dev, rxDataCount)));
                        pr_debug("%s:%s(): clearing RX int\n",
-                                dev->name, __FUNCTION__);
+                                dev->name, __FUNCTION__);
                        outl(MIPSNET_INTCTL_RXDONE,
                             mipsnet_reg_address(dev, interruptControl));
 
                } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) {
                        pr_debug("%s:%s(): got test interrupt\n",
-                                dev->name, __FUNCTION__);
-                       // TESTBIT is cleared on read.
-                       //    And takes effect after a write with 0
+                                dev->name, __FUNCTION__);
+                       /*
+                        * TESTBIT is cleared on read.
+                        * And takes effect after a write with 0
+                        */
                        outl(0, mipsnet_reg_address(dev, interruptControl));
                } else {
                        pr_debug("%s:%s(): no valid fags 0x%016llx\n",
-                                dev->name, __FUNCTION__, interruptFlags);
-                       // Maybe shared IRQ, just ignore, no clearing.
+                                dev->name, __FUNCTION__, interruptFlags);
+                       /* Maybe shared IRQ, just ignore, no clearing. */
                        retval = IRQ_NONE;
                }
 
@@ -159,7 +160,7 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
                retval = IRQ_NONE;
        }
        return retval;
-}                              //mipsnet_interrupt()
+}
 
 static int mipsnet_open(struct net_device *dev)
 {
@@ -171,18 +172,18 @@ static int mipsnet_open(struct net_device *dev)
 
        if (err) {
                pr_debug("%s: %s(): can't get irq %d\n",
-                        dev->name, __FUNCTION__, dev->irq);
+                        dev->name, __FUNCTION__, dev->irq);
                release_region(dev->base_addr, MIPSNET_IO_EXTENT);
                return err;
        }
 
        pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n",
-                dev->name, __FUNCTION__, dev->base_addr, dev->irq);
+                dev->name, __FUNCTION__, dev->base_addr, dev->irq);
 
 
        netif_start_queue(dev);
 
-       // test interrupt handler
+       /* test interrupt handler */
        outl(MIPSNET_INTCTL_TESTBIT,
             mipsnet_reg_address(dev, interruptControl));
 
@@ -199,8 +200,6 @@ static int mipsnet_close(struct net_device *dev)
 
 static void mipsnet_set_mclist(struct net_device *dev)
 {
-       // we don't do anything
-       return;
 }
 
 static int __init mipsnet_probe(struct device *dev)
@@ -226,13 +225,13 @@ static int __init mipsnet_probe(struct device *dev)
         */
        netdev->base_addr = 0x4200;
        netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 +
-                     inl(mipsnet_reg_address(netdev, interruptInfo));
+                     inl(mipsnet_reg_address(netdev, interruptInfo));
 
-       // Get the io region now, get irq on open()
+       /* Get the io region now, get irq on open() */
        if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) {
                pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} "
-                        "for dev is not availble.\n", netdev->name,
-                        __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT);
+                        "for dev is not availble.\n", netdev->name,
+                        __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT);
                err = -EBUSY;
                goto out_free_netdev;
        }
index 026c732024c99e8dd7708f6291732682af34976c..0132c6714a40322df917063e6cdccaa50d08fbe4 100644 (file)
@@ -9,32 +9,34 @@
 /*
  *  Id of this Net device, as seen by the core.
  */
-#define MIPS_NET_DEV_ID ((uint64_t)           \
-                            ((uint64_t)'M'<< 0)| \
-                            ((uint64_t)'I'<< 8)| \
-                            ((uint64_t)'P'<<16)| \
-                            ((uint64_t)'S'<<24)| \
-                            ((uint64_t)'N'<<32)| \
-                            ((uint64_t)'E'<<40)| \
-                            ((uint64_t)'T'<<48)| \
-                            ((uint64_t)'0'<<56))
+#define MIPS_NET_DEV_ID ((uint64_t)       \
+                            ((uint64_t) 'M' <<  0)| \
+                            ((uint64_t) 'I' <<  8)| \
+                            ((uint64_t) 'P' << 16)| \
+                            ((uint64_t) 'S' << 24)| \
+                            ((uint64_t) 'N' << 32)| \
+                            ((uint64_t) 'E' << 40)| \
+                            ((uint64_t) 'T' << 48)| \
+                            ((uint64_t) '0' << 56))
 
 /*
  * Net status/control block as seen by sw in the core.
  * (Why not use bit fields? can't be bothered with cross-platform struct
  *  packing.)
  */
-typedef struct _net_control_block {
-       /// dev info for probing
-       ///  reads as MIPSNET%d where %d is some form of version
-       uint64_t devId;         /*0x00 */
+struct net_control_block {
+       /*
+        * dev info for probing
+        * reads as MIPSNET%d where %d is some form of version
+        */
+       uint64_t devId;         /* 0x00 */
 
        /*
         * read only busy flag.
         * Set and cleared by the Net Device to indicate that an rx or a tx
         * is in progress.
         */
-       uint32_t busy;          /*0x08 */
+       uint32_t busy;          /* 0x08 */
 
        /*
         * Set by the Net Device.
@@ -43,16 +45,16 @@ typedef struct _net_control_block {
         * rxDataBuffer.  The value will decrease till 0 until all the data
         * from rxDataBuffer has been read.
         */
-       uint32_t rxDataCount;   /*0x0c */
+       uint32_t rxDataCount;   /* 0x0c */
 #define MIPSNET_MAX_RXTX_DATACOUNT (1<<16)
 
        /*
-        * Settable from the MIPS core, cleared by the Net Device.
-        * The core should set the number of bytes it wants to send,
-        *   then it should write those bytes of data to txDataBuffer.
-        * The device will clear txDataCount has been processed (not necessarily sent).
+        * Settable from the MIPS core, cleared by the Net Device.  The core
+        * should set the number of bytes it wants to send, then it should
+        * write those bytes of data to txDataBuffer.  The device will clear
+        * txDataCount has been processed (not necessarily sent).
         */
-       uint32_t txDataCount;   /*0x10 */
+       uint32_t txDataCount;   /* 0x10 */
 
        /*
         * Interrupt control
@@ -69,39 +71,42 @@ typedef struct _net_control_block {
         *    To clear the test interrupt, write 0 to this register.
         */
        uint32_t interruptControl;      /*0x14 */
-#define MIPSNET_INTCTL_TXDONE     ((uint32_t)(1<< 0))
-#define MIPSNET_INTCTL_RXDONE     ((uint32_t)(1<< 1))
-#define MIPSNET_INTCTL_TESTBIT    ((uint32_t)(1<<31))
-#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT)
+#define MIPSNET_INTCTL_TXDONE     ((uint32_t)(1 <<  0))
+#define MIPSNET_INTCTL_RXDONE     ((uint32_t)(1 <<  1))
+#define MIPSNET_INTCTL_TESTBIT    ((uint32_t)(1 << 31))
+#define MIPSNET_INTCTL_ALLSOURCES      (MIPSNET_INTCTL_TXDONE | \
+                                        MIPSNET_INTCTL_RXDONE | \
+                                        MIPSNET_INTCTL_TESTBIT)
 
        /*
-        * Readonly core-specific interrupt info for the device to signal the core.
-        * The meaning of the contents of this field might change.
-        */
-       /*###\todo: the whole memIntf interrupt scheme is messy: the device should have
-        *  no control what so ever of what VPE/register set is being used.
-        *  The MemIntf should only expose interrupt lines, and something in the
-        *  config should be responsible for the line<->core/vpe bindings.
+        * Readonly core-specific interrupt info for the device to signal the
+        * core.  The meaning of the contents of this field might change.
+        *
+        * TODO: the whole memIntf interrupt scheme is messy: the device should
+        *       have no control what so ever of what VPE/register set is being
+        *       used.  The MemIntf should only expose interrupt lines, and
+        *       something in the config should be responsible for the
+        *       line<->core/vpe bindings.
         */
-       uint32_t interruptInfo; /*0x18 */
+       uint32_t interruptInfo; /* 0x18 */
 
        /*
         *  This is where the received data is read out.
         *  There is more data to read until rxDataReady is 0.
         *  Only 1 byte at this regs offset is used.
         */
-       uint32_t rxDataBuffer;  /*0x1c */
+       uint32_t rxDataBuffer;  /* 0x1c */
 
        /*
-        * This is where the data to transmit is written.
-        * Data should be written for the amount specified in the txDataCount register.
-        *  Only 1 byte at this regs offset is used.
+        * This is where the data to transmit is written.  Data should be
+        * written for the amount specified in the txDataCount register.  Only
+        * 1 byte at this regs offset is used.
         */
-       uint32_t txDataBuffer;  /*0x20 */
-} MIPS_T_NetControl;
+       uint32_t txDataBuffer;  /* 0x20 */
+};
 
 #define MIPSNET_IO_EXTENT 0x40 /* being generous */
 
-#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field)
+#define field_offset(field) (offsetof(struct net_control_block, field))
 
 #endif /* __MIPSNET_H */
index e029b8afbd370d8077dc21086ec742192159b180..89b3f0b7cdc0f81a42a79eb2ecca2df0092e78ea 100644 (file)
@@ -884,7 +884,7 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev,
                ++mlx4_version_printed;
        }
 
-       return mlx4_init_one(pdev, id);
+       return __mlx4_init_one(pdev, id);
 }
 
 static void mlx4_remove_one(struct pci_dev *pdev)
index b33d21f4efffb69182a93a53117779180abf9377..84f2d6382f1edf0cf9a6f2dfac0b9b34842586d8 100644 (file)
@@ -784,7 +784,6 @@ static int mv643xx_eth_open(struct net_device *dev)
        unsigned int port_num = mp->port_num;
        unsigned int size;
        int err;
-       DECLARE_MAC_BUF(mac);
 
        /* Clear any pending ethernet port interrupts */
        mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
@@ -1296,6 +1295,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        struct ethtool_cmd cmd;
        int duplex = DUPLEX_HALF;
        int speed = 0;                  /* default to auto-negotiation */
+       DECLARE_MAC_BUF(mac);
 
        pd = pdev->dev.platform_data;
        if (pd == NULL) {
index 86c9c06433cbbd2802ba2b56e2f9d3cd932ed17a..06ca4252155f40920902acae2900b76516533f0d 100644 (file)
@@ -85,7 +85,6 @@ struct net_device * __init mvme147lance_probe(int unit)
        dev->open = &m147lance_open;
        dev->stop = &m147lance_close;
        dev->hard_start_xmit = &lance_start_xmit;
-       dev->get_stats = &lance_get_stats;
        dev->set_multicast_list = &lance_set_multicast;
        dev->tx_timeout = &lance_tx_timeout;
        dev->dma = 0;
index e8afa101433ec5c0456d0ea72fba6424a64481e8..64c8151f200401aca8bf9d4c21e4c07f82850176 100644 (file)
@@ -75,7 +75,7 @@
 #include "myri10ge_mcp.h"
 #include "myri10ge_mcp_gen_header.h"
 
-#define MYRI10GE_VERSION_STR "1.3.2-1.269"
+#define MYRI10GE_VERSION_STR "1.3.2-1.287"
 
 MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
 MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -214,6 +214,8 @@ struct myri10ge_priv {
        unsigned long serial_number;
        int vendor_specific_offset;
        int fw_multicast_support;
+       unsigned long features;
+       u32 max_tso6;
        u32 read_dma;
        u32 write_dma;
        u32 read_write_dma;
@@ -311,6 +313,7 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
 #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
 
 static void myri10ge_set_multicast_list(struct net_device *dev);
+static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev);
 
 static inline void put_be32(__be32 val, __be32 __iomem * p)
 {
@@ -612,6 +615,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
        __be32 buf[16];
        u32 dma_low, dma_high, size;
        int status, i;
+       struct myri10ge_cmd cmd;
 
        size = 0;
        status = myri10ge_load_hotplug_firmware(mgp, &size);
@@ -688,6 +692,14 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
        dev_info(&mgp->pdev->dev, "handoff confirmed\n");
        myri10ge_dummy_rdma(mgp, 1);
 
+       /* probe for IPv6 TSO support */
+       mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+                                  &cmd, 0);
+       if (status == 0) {
+               mgp->max_tso6 = cmd.data0;
+               mgp->features |= NETIF_F_TSO6;
+       }
        return 0;
 }
 
@@ -1047,7 +1059,8 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
 
        hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
 
-       /* allocate an skb to attach the page(s) to. */
+       /* allocate an skb to attach the page(s) to. This is done
+        * after trying LRO, so as to avoid skb allocation overheads */
 
        skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16);
        if (unlikely(skb == NULL)) {
@@ -1217,7 +1230,8 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
 
 static int myri10ge_poll(struct napi_struct *napi, int budget)
 {
-       struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi);
+       struct myri10ge_priv *mgp =
+           container_of(napi, struct myri10ge_priv, napi);
        struct net_device *netdev = mgp->dev;
        struct myri10ge_rx_done *rx_done = &mgp->rx_done;
        int work_done;
@@ -1382,6 +1396,18 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
        return 0;
 }
 
+static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
+{
+       struct myri10ge_priv *mgp = netdev_priv(netdev);
+       unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
+
+       if (tso_enabled)
+               netdev->features |= flags;
+       else
+               netdev->features &= ~flags;
+       return 0;
+}
+
 static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
        "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
        "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -1506,7 +1532,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
        .set_rx_csum = myri10ge_set_rx_csum,
        .set_tx_csum = ethtool_op_set_tx_hw_csum,
        .set_sg = ethtool_op_set_sg,
-       .set_tso = ethtool_op_set_tso,
+       .set_tso = myri10ge_set_tso,
        .get_link = ethtool_op_get_link,
        .get_strings = myri10ge_get_strings,
        .get_sset_count = myri10ge_get_sset_count,
@@ -2164,7 +2190,8 @@ again:
                pseudo_hdr_offset = cksum_offset + skb->csum_offset;
                /* If the headers are excessively large, then we must
                 * fall back to a software checksum */
-               if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) {
+               if (unlikely(!mss && (cksum_offset > 255 ||
+                                     pseudo_hdr_offset > 127))) {
                        if (skb_checksum_help(skb))
                                goto drop;
                        cksum_offset = 0;
@@ -2184,9 +2211,18 @@ again:
                /* negative cum_len signifies to the
                 * send loop that we are still in the
                 * header portion of the TSO packet.
-                * TSO header must be at most 134 bytes long */
+                * TSO header can be at most 1KB long */
                cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb));
 
+               /* for IPv6 TSO, the checksum offset stores the
+                * TCP header length, to save the firmware from
+                * the need to parse the headers */
+               if (skb_is_gso_v6(skb)) {
+                       cksum_offset = tcp_hdrlen(skb);
+                       /* Can only handle headers <= max_tso6 long */
+                       if (unlikely(-cum_len > mgp->max_tso6))
+                               return myri10ge_sw_tso(skb, dev);
+               }
                /* for TSO, pseudo_hdr_offset holds mss.
                 * The firmware figures out where to put
                 * the checksum by parsing the header. */
@@ -2301,10 +2337,12 @@ again:
                        req++;
                        count++;
                        rdma_count++;
-                       if (unlikely(cksum_offset > seglen))
-                               cksum_offset -= seglen;
-                       else
-                               cksum_offset = 0;
+                       if (cksum_offset != 0 && !(mss && skb_is_gso_v6(skb))) {
+                               if (unlikely(cksum_offset > seglen))
+                                       cksum_offset -= seglen;
+                               else
+                                       cksum_offset = 0;
+                       }
                }
                if (frag_idx == frag_cnt)
                        break;
@@ -2387,6 +2425,41 @@ drop:
 
 }
 
+static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
+{
+       struct sk_buff *segs, *curr;
+       struct myri10ge_priv *mgp = dev->priv;
+       int status;
+
+       segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
+       if (unlikely(IS_ERR(segs)))
+               goto drop;
+
+       while (segs) {
+               curr = segs;
+               segs = segs->next;
+               curr->next = NULL;
+               status = myri10ge_xmit(curr, dev);
+               if (status != 0) {
+                       dev_kfree_skb_any(curr);
+                       if (segs != NULL) {
+                               curr = segs;
+                               segs = segs->next;
+                               curr->next = NULL;
+                               dev_kfree_skb_any(segs);
+                       }
+                       goto drop;
+               }
+       }
+       dev_kfree_skb_any(skb);
+       return 0;
+
+drop:
+       dev_kfree_skb_any(skb);
+       mgp->stats.tx_dropped += 1;
+       return 0;
+}
+
 static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
 {
        struct myri10ge_priv *mgp = netdev_priv(dev);
@@ -2706,7 +2779,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
 }
 
 #ifdef CONFIG_PM
-
 static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct myri10ge_priv *mgp;
@@ -2787,7 +2859,6 @@ abort_with_enabled:
        return -EIO;
 
 }
-
 #endif                         /* CONFIG_PM */
 
 static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp)
@@ -2954,8 +3025,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        mgp = netdev_priv(netdev);
        mgp->dev = netdev;
-       netif_napi_add(netdev, &mgp->napi,
-                      myri10ge_poll, myri10ge_napi_weight);
+       netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight);
        mgp->pdev = pdev;
        mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
        mgp->pause = myri10ge_flow_control;
@@ -3077,7 +3147,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netdev->change_mtu = myri10ge_change_mtu;
        netdev->set_multicast_list = myri10ge_set_multicast_list;
        netdev->set_mac_address = myri10ge_set_mac_address;
-       netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+       netdev->features = mgp->features;
        if (dac_enabled)
                netdev->features |= NETIF_F_HIGHDMA;
 
index a1d2a22296a985f88eb56877bbfd835425d6c623..58e57178c563f6129b4faf80d50e14408a0fe265 100644 (file)
@@ -10,7 +10,7 @@ struct mcp_dma_addr {
        __be32 low;
 };
 
-/* 4 Bytes */
+/* 4 Bytes.  8 Bytes for NDIS drivers. */
 struct mcp_slot {
        __sum16 checksum;
        __be16 length;
@@ -205,8 +205,87 @@ enum myri10ge_mcp_cmd_type {
        /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned
         * chipset */
 
-       MXGEFW_CMD_UNALIGNED_STATUS
-           /* return data = boolean, true if the chipset is known to be unaligned */
+       MXGEFW_CMD_UNALIGNED_STATUS,
+       /* return data = boolean, true if the chipset is known to be unaligned */
+
+       MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS,
+       /* data0 = number of big buffers to use.  It must be 0 or a power of 2.
+        * 0 indicates that the NIC consumes as many buffers as they are required
+        * for packet. This is the default behavior.
+        * A power of 2 number indicates that the NIC always uses the specified
+        * number of buffers for each big receive packet.
+        * It is up to the driver to ensure that this value is big enough for
+        * the NIC to be able to receive maximum-sized packets.
+        */
+
+       MXGEFW_CMD_GET_MAX_RSS_QUEUES,
+       MXGEFW_CMD_ENABLE_RSS_QUEUES,
+       /* data0 = number of slices n (0, 1, ..., n-1) to enable
+        * data1 = interrupt mode. 0=share one INTx/MSI, 1=use one MSI-X per queue.
+        * If all queues share one interrupt, the driver must have set
+        * RSS_SHARED_INTERRUPT_DMA before enabling queues.
+        */
+       MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET,
+       MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA,
+       /* data0, data1 = bus address lsw, msw */
+       MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
+       /* get the offset of the indirection table */
+       MXGEFW_CMD_SET_RSS_TABLE_SIZE,
+       /* set the size of the indirection table */
+       MXGEFW_CMD_GET_RSS_KEY_OFFSET,
+       /* get the offset of the secret key */
+       MXGEFW_CMD_RSS_KEY_UPDATED,
+       /* tell nic that the secret key's been updated */
+       MXGEFW_CMD_SET_RSS_ENABLE,
+       /* data0 = enable/disable rss
+        * 0: disable rss.  nic does not distribute receive packets.
+        * 1: enable rss.  nic distributes receive packets among queues.
+        * data1 = hash type
+        * 1: IPV4
+        * 2: TCP_IPV4
+        * 3: IPV4 | TCP_IPV4
+        */
+
+       MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+       /* Return data = the max. size of the entire headers of a IPv6 TSO packet.
+        * If the header size of a IPv6 TSO packet is larger than the specified
+        * value, then the driver must not use TSO.
+        * This size restriction only applies to IPv6 TSO.
+        * For IPv4 TSO, the maximum size of the headers is fixed, and the NIC
+        * always has enough header buffer to store maximum-sized headers.
+        */
+
+       MXGEFW_CMD_SET_TSO_MODE,
+       /* data0 = TSO mode.
+        * 0: Linux/FreeBSD style (NIC default)
+        * 1: NDIS/NetBSD style
+        */
+
+       MXGEFW_CMD_MDIO_READ,
+       /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */
+       MXGEFW_CMD_MDIO_WRITE,
+       /* data0 = dev_addr,  data1 = register/addr, data2 = value  */
+
+       MXGEFW_CMD_XFP_I2C_READ,
+       /* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the
+        * obtained data is cached inside the xaui-xfi chip :
+        *   data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes,
+        *   data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ]
+        * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes
+        * During the i2c operation,  MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts
+        *  will return MXGEFW_CMD_ERROR_BUSY
+        */
+       MXGEFW_CMD_XFP_BYTE,
+       /* Return the last obtained copy of a given byte in the xfp i2c table
+        * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ)
+        *   data0 : index of the desired table entry
+        *  Return data = the byte stored at the requested index in the table
+        */
+
+       MXGEFW_CMD_GET_VPUMP_OFFSET,
+       /* Return data = NIC memory offset of mcp_vpump_public_global */
+       MXGEFW_CMD_RESET_VPUMP,
+       /* Resets the VPUMP state */
 };
 
 enum myri10ge_mcp_cmd_status {
@@ -220,7 +299,10 @@ enum myri10ge_mcp_cmd_status {
        MXGEFW_CMD_ERROR_BAD_PORT,
        MXGEFW_CMD_ERROR_RESOURCES,
        MXGEFW_CMD_ERROR_MULTICAST,
-       MXGEFW_CMD_ERROR_UNALIGNED
+       MXGEFW_CMD_ERROR_UNALIGNED,
+       MXGEFW_CMD_ERROR_NO_MDIO,
+       MXGEFW_CMD_ERROR_XFP_FAILURE,
+       MXGEFW_CMD_ERROR_XFP_ABSENT
 };
 
 #define MXGEFW_OLD_IRQ_DATA_LEN 40
index 527f9dcc7f69f3b7bc212ed4c363d0690c66b98b..50e1ec67ef9c5f4d0fa9419b03de64961e3c3962 100644 (file)
@@ -1576,7 +1576,7 @@ static int netdev_open(struct net_device *dev)
 
        /* Set the timer to check for link beat. */
        init_timer(&np->timer);
-       np->timer.expires = jiffies + NATSEMI_TIMER_FREQ;
+       np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ);
        np->timer.data = (unsigned long)dev;
        np->timer.function = &netdev_timer; /* timer handler */
        add_timer(&np->timer);
@@ -1856,7 +1856,11 @@ static void netdev_timer(unsigned long data)
                        next_tick = 1;
                }
        }
-       mod_timer(&np->timer, jiffies + next_tick);
+
+       if (next_tick > 1)
+               mod_timer(&np->timer, round_jiffies(jiffies + next_tick));
+       else
+               mod_timer(&np->timer, jiffies + next_tick);
 }
 
 static void dump_ring(struct net_device *dev)
@@ -3310,13 +3314,19 @@ static int natsemi_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata (pdev);
        struct netdev_private *np = netdev_priv(dev);
+       int ret = 0;
 
        rtnl_lock();
        if (netif_device_present(dev))
                goto out;
        if (netif_running(dev)) {
                BUG_ON(!np->hands_off);
-               pci_enable_device(pdev);
+               ret = pci_enable_device(pdev);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "pci_enable_device() failed: %d\n", ret);
+                       goto out;
+               }
        /*      pci_power_on(pdev); */
 
                napi_enable(&np->napi);
@@ -3331,12 +3341,12 @@ static int natsemi_resume (struct pci_dev *pdev)
                spin_unlock_irq(&np->lock);
                enable_irq(dev->irq);
 
-               mod_timer(&np->timer, jiffies + 1*HZ);
+               mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ));
        }
        netif_device_attach(dev);
 out:
        rtnl_unlock();
-       return 0;
+       return ret;
 }
 
 #endif /* CONFIG_PM */
index 368f2560856db82d796a99b1611748e9b653cc41..fbc7531d3c7d8aed647056c905e4aa74a476b0e8 100644 (file)
@@ -93,7 +93,7 @@ static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr
        bus_width = *(volatile unsigned char *)ABWCR;
        bus_width &= 1 << ((base_addr >> 21) & 7);
 
-       for (i = 0; i < sizeof(reg_offset) / sizeof(u32); i++)
+       for (i = 0; i < ARRAY_SIZE(reg_offset); i++)
                if (bus_width == 0)
                        reg_offset[i] = i * 2 + 1;
                else
@@ -115,7 +115,7 @@ static int h8300_ne_irq[] = {EXT_IRQ5};
 
 static inline int init_dev(struct net_device *dev)
 {
-       if (h8300_ne_count < (sizeof(h8300_ne_base) / sizeof(unsigned long))) {
+       if (h8300_ne_count < ARRAY_SIZE(h8300_ne_base)) {
                dev->base_addr = h8300_ne_base[h8300_ne_count];
                dev->irq       = h8300_ne_irq[h8300_ne_count];
                h8300_ne_count++;
index 09768524511281d06fd881f9faabdd4c4717e1bf..3edc971d0ecabfba1ecfdee18af52bc5e1204682 100644 (file)
@@ -183,7 +183,7 @@ static struct card {
        short addr_offset;
        unsigned char *vendor_id;
        char *cardname;
-       long config;
+       unsigned long config;
 } cards[] = {
        {
                .id0         = NI65_ID0,
index 14361e885415ca583c7bcc2eddd8a113120702ab..c65199df8a7f54aac9b4268c0aa640771267d06c 100644 (file)
@@ -97,13 +97,16 @@ static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp)
               &lp->evm_saa9730_regs->InterruptBlock1);
 }
 
-static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
+static void __used show_saa9730_regs(struct net_device *dev)
 {
+       struct lan_saa9730_private *lp = netdev_priv(dev);
        int i, j;
+
        printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]);
        printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]);
        printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]);
        printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]);
+
        for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
                for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
                        printk("TxmBuffer[%d][%d] = %x\n", i, j,
@@ -146,11 +149,13 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
               readl(&lp->lan_saa9730_regs->RxCtl));
        printk("lp->lan_saa9730_regs->RxStatus = %x\n",
               readl(&lp->lan_saa9730_regs->RxStatus));
+
        for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
                writel(i, &lp->lan_saa9730_regs->CamAddress);
                printk("lp->lan_saa9730_regs->CamData = %x\n",
                       readl(&lp->lan_saa9730_regs->CamData));
        }
+
        printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets);
        printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors);
        printk("dev->stats.tx_aborted_errors = %lx\n",
@@ -855,7 +860,7 @@ static void lan_saa9730_tx_timeout(struct net_device *dev)
        /* Transmitter timeout, serious problems */
        dev->stats.tx_errors++;
        printk("%s: transmit timed out, reset\n", dev->name);
-       /*show_saa9730_regs(lp); */
+       /*show_saa9730_regs(dev); */
        lan_saa9730_restart(lp);
 
        dev->trans_start = jiffies;
index 68f728f0b600f962bb46422749b250faaeaea46f..7967240534d5b647d97313920c9d5ff7b2455bc0 100644 (file)
@@ -4396,7 +4396,7 @@ static void sky2_shutdown(struct pci_dev *pdev)
        if (!hw)
                return;
 
-       napi_disable(&hw->napi);
+       del_timer_sync(&hw->watchdog_timer);
 
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
index a679f4310ce1ae0ef64ed1ea8b7d8bb11f7f299a..8038f2882c9b177ac433476065c8ab6ac501d1e7 100644 (file)
@@ -1461,7 +1461,6 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
        }
        return IRQ_NONE;
 #else
-       struct tc35815_local *lp = dev->priv;
        int handled;
        u32 status;
 
index 8d04654f0c59ccb461db144ca79e2780cc2f75a7..4e1b84e6d66ab308330184a034ba7f52d82fb91a 100644 (file)
@@ -1906,7 +1906,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
     /************** pci *****************/
        if ((err = pci_enable_device(pdev)))    /* it trigers interrupt, dunno why. */
-               RET(err);                       /* it's not a problem though */
+               goto err_pci;                   /* it's not a problem though */
 
        if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
            !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
@@ -2076,6 +2076,7 @@ err_out_res:
        pci_release_regions(pdev);
 err_dma:
        pci_disable_device(pdev);
+err_pci:
        vfree(nic);
 
        RET(err);
index 30b1cca8144ce360b23db4106983fb9c1cf45822..76efb3feffbf0eb8fd531f1063816666d9c9a271 100644 (file)
@@ -9034,7 +9034,7 @@ static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len)
        int i;
        u32 j;
 
-       for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) {
+       for (i = 0; i < ARRAY_SIZE(test_pattern); i++) {
                for (j = 0; j < len; j += 4) {
                        u32 val;
 
index 9b9cd83fb8b660dbfeb8d44e330e851221412435..41f34bb91cad9d12dd0fdb245398d2d60e72a487 100644 (file)
@@ -1041,7 +1041,7 @@ static struct InfoLeaf infoleaf_array[] = {
     {DC21142, dc21142_infoleaf},
     {DC21143, dc21143_infoleaf}
 };
-#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
+#define INFOLEAF_SIZE ARRAY_SIZE(infoleaf_array)
 
 /*
 ** List the SROM info block functions
@@ -1056,7 +1056,7 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = {
     compact_infoblock
 };
 
-#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
+#define COMPACT (ARRAY_SIZE(dc_infoblock) - 1)
 
 /*
 ** Miscellaneous defines...
index 12af0cc037fbf3859ebd55f8223ebfc9899d78c6..9fb8d7f079943c07c9bca5f982a7cc26ea2c4663 100644 (file)
@@ -1017,4 +1017,4 @@ struct de4x5_ioctl {
 #define DE4X5_SET_OMR           0x0d /* Set the OMR Register contents */
 #define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
 
-#define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
+#define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
index ee08292bcf8579f3f23bcb748702aad8ae1761db..e5e2c9c4ebfee5cc1174e7c36130d8da5b516a65 100644 (file)
@@ -292,6 +292,7 @@ static void tulip_up(struct net_device *dev)
        struct tulip_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->base_addr;
        int next_tick = 3*HZ;
+       u32 reg;
        int i;
 
 #ifdef CONFIG_TULIP_NAPI
@@ -307,14 +308,14 @@ static void tulip_up(struct net_device *dev)
 
        /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
        iowrite32(0x00000001, ioaddr + CSR0);
-       pci_read_config_dword(tp->pdev, PCI_COMMAND, &i);  /* flush write */
+       pci_read_config_dword(tp->pdev, PCI_COMMAND, &reg);  /* flush write */
        udelay(100);
 
        /* Deassert reset.
           Wait the specified 50 PCI cycles after a reset by initializing
           Tx and Rx queues and the address filter list. */
        iowrite32(tp->csr0, ioaddr + CSR0);
-       pci_read_config_dword(tp->pdev, PCI_COMMAND, &i);  /* flush write */
+       pci_read_config_dword(tp->pdev, PCI_COMMAND, &reg);  /* flush write */
        udelay(100);
 
        if (tulip_debug > 1)
index d00e7d41f6a5ce6d47c694753e198eac329c6167..bec413ba9bcabb65d97122baf928ea91a89a46db 100644 (file)
@@ -63,7 +63,7 @@
 #define UGETH_MSG_DEFAULT      (NETIF_MSG_IFUP << 1 ) - 1
 
 void uec_set_ethtool_ops(struct net_device *netdev);
-       
+
 static DEFINE_SPINLOCK(ugeth_lock);
 
 static struct {
@@ -3454,9 +3454,12 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
        u16 length, howmany = 0;
        u32 bd_status;
        u8 *bdBuffer;
+       struct net_device * dev;
 
        ugeth_vdbg("%s: IN", __FUNCTION__);
 
+       dev = ugeth->dev;
+
        /* collect received buffers */
        bd = ugeth->rxBd[rxQ];
 
index 26058b4f8f36b2c5785a9291fd4baf8af10e017d..ff37bf437a99e3b955e373b12b2070c1ba37b62d 100644 (file)
@@ -154,8 +154,8 @@ struct cosa_data {
        int nchannels;                  /* # of channels on this card */
        int driver_status;              /* For communicating with firmware */
        int firmware_status;            /* Downloaded, reseted, etc. */
-       long int rxbitmap, txbitmap;    /* Bitmap of channels who are willing to send/receive data */
-       long int rxtx;                  /* RX or TX in progress? */
+       unsigned long rxbitmap, txbitmap;/* Bitmap of channels who are willing to send/receive data */
+       unsigned long rxtx;             /* RX or TX in progress? */
        int enabled;
        int usage;                              /* usage count */
        int txchan, txsize, rxsize;
index b39a541b25093b8724bb72603a4cf712d40a04f6..05df0a345b609744f243d1bbafcd05bbbe0e7d9f 100644 (file)
@@ -1342,11 +1342,11 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map)
        if (flp->initialized)
                return(-EINVAL);
 
-       for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
+       for(i=0; i < ARRAY_SIZE(valid_port); i++)
                if (valid_port[i] == map->base_addr)
                        break;   
 
-       if (i == sizeof(valid_port) / sizeof(int))
+       if (i == ARRAY_SIZE(valid_port))
                return(-EINVAL);
 
        if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
@@ -1487,12 +1487,12 @@ got_type:
                }
        }
 
-       for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
+       for(i=0; i < ARRAY_SIZE(valid_mem); i++)
                if (valid_mem[i] == map->mem_start)
                        break;   
 
        err = -EINVAL;
-       if (i == sizeof(valid_mem) / sizeof(int))
+       if (i == ARRAY_SIZE(valid_mem))
                goto fail2;
 
        if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E)
index 5f7ffa0a76c0973ab6d27fc3ff68a8944a2366f8..3d4ed647c311de9ebb84bc5b6b97c6af281f526e 100644 (file)
@@ -26,6 +26,7 @@
 */
 
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/types.h>
 
 #include "b43.h"
index 34a44c1b6314126f1929bb2feaf6acf912428de4..3488f2447bbf4daa41e8036f3b2a23783c2dd2c4 100644 (file)
@@ -4,6 +4,7 @@
 #include "b43.h"
 
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/list.h>
 #include <linux/skbuff.h>
 
index fcb777383e70e663245f7d84b46f0f32bfd02a89..f4faff6a7d6c43e4a862988edf914ecbc44ce3cd 100644 (file)
 
 */
 
+#include <linux/capability.h>
+#include <linux/io.h>
+
 #include "b43.h"
 #include "sysfs.h"
 #include "main.h"
 #include "phy.h"
 
-#include <linux/capability.h>
-
 #define GENERIC_FILESIZE       64
 
 static int get_integer(const char *buf, size_t count)
index c27b2c1c06af5de29aedbd996e32dc2787423866..e6516a186d0eadc2a752ac26fa32fb49dec20c5a 100644 (file)
@@ -661,7 +661,7 @@ struct local_info {
 #define HOSTAP_BITS_TRANSMIT 0
 #define HOSTAP_BITS_BAP_TASKLET 1
 #define HOSTAP_BITS_BAP_TASKLET2 2
-       long bits;
+       unsigned long bits;
 
        struct ap_data *ap;
 
index bd73ebf033401cbddbffb901784c0de53bcf2489..1e23b7f4cca7adb74a25854558e3290b9534e044 100644 (file)
@@ -33,8 +33,8 @@ typedef struct ray_dev_t {
     void __iomem *rmem;            /* pointer to receive buffer window       */
     struct pcmcia_device *finder;            /* pointer back to struct pcmcia_device for card    */
     struct timer_list timer;
-    long tx_ccs_lock;
-    long ccs_lock;
+    unsigned long tx_ccs_lock;
+    unsigned long ccs_lock;
     int   dl_param_ccs;
     union {
         struct b4_startup_params b4;
index f464b82c7d5fe3f7795397b217d2459bdd85e211..7fd505cc4f7ab3b9a8fb32a8847596bca1d51d19 100644 (file)
@@ -74,22 +74,12 @@ struct netfront_info {
 
        struct napi_struct napi;
 
-       struct xen_netif_tx_front_ring tx;
-       struct xen_netif_rx_front_ring rx;
-
-       spinlock_t   tx_lock;
-       spinlock_t   rx_lock;
-
        unsigned int evtchn;
+       struct xenbus_device *xbdev;
 
-       /* Receive-ring batched refills. */
-#define RX_MIN_TARGET 8
-#define RX_DFL_MIN_TARGET 64
-#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
-       unsigned rx_min_target, rx_max_target, rx_target;
-       struct sk_buff_head rx_batch;
-
-       struct timer_list rx_refill_timer;
+       spinlock_t   tx_lock;
+       struct xen_netif_tx_front_ring tx;
+       int tx_ring_ref;
 
        /*
         * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
@@ -108,14 +98,23 @@ struct netfront_info {
        grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
        unsigned tx_skb_freelist;
 
+       spinlock_t   rx_lock ____cacheline_aligned_in_smp;
+       struct xen_netif_rx_front_ring rx;
+       int rx_ring_ref;
+
+       /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+       unsigned rx_min_target, rx_max_target, rx_target;
+       struct sk_buff_head rx_batch;
+
+       struct timer_list rx_refill_timer;
+
        struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
        grant_ref_t gref_rx_head;
        grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
 
-       struct xenbus_device *xbdev;
-       int tx_ring_ref;
-       int rx_ring_ref;
-
        unsigned long rx_pfn_array[NET_RX_RING_SIZE];
        struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
        struct mmu_update rx_mmu[NET_RX_RING_SIZE];
index f0eba534f805bec0f38e9d12aa6a1bcccd2aebf2..01c351c176ac27267bc03cdfdcf6c2f0d64e1467 100644 (file)
@@ -689,8 +689,6 @@ int pci_hp_deregister (struct hotplug_slot *slot)
 int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
                                         struct hotplug_slot_info *info)
 {
-       int retval;
-
        if ((slot == NULL) || (info == NULL))
                return -ENODEV;
 
index 728b3c863d87762ff6e1b1505af77126736b2b11..71d561fda0a2bb0903cf91ccaf78ae6a9b37f07d 100644 (file)
@@ -658,7 +658,7 @@ int
 pci_restore_state(struct pci_dev *dev)
 {
        int i;
-       int val;
+       u32 val;
 
        /* PCI Express register must be restored first */
        pci_restore_pcie_state(dev);
index 71b33707117fb8b73c3518135cfc0b70a01b18e0..839bb1c0db58c9af53211483cc735370217cd3d6 100644 (file)
@@ -101,7 +101,7 @@ static int ignore = -1;
 /* Bit map or list of interrupts to choose from */
 static u_int irq_mask = 0xffff;
 static int irq_list[16];
-static int irq_list_count;
+static unsigned int irq_list_count;
 /* The card status change interrupt -- 0 means autoselect */
 static int cs_irq = 0;
 
index dd0ddf19ee570a681026ad3a29fe893598cffa59..abc10fe49bd85889fa813aba43c703eeacba4678 100644 (file)
@@ -58,7 +58,7 @@ MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
 
 static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
 static int irq_list[16];
-static int irq_list_count = 0;
+static unsigned int irq_list_count = 0;
 
 module_param(irq_mode, int, 0444);
 module_param_array(irq_list, int, &irq_list_count, 0444);
index c158cf38b9ddbf15c6970a84e9e4d345dd89605e..749ac3710914e519c122284a4bd0f32670b990ee 100644 (file)
@@ -90,7 +90,7 @@ static int do_scan = 1;
 /* Bit map of interrupts to choose from */
 static u_int irq_mask = 0xffff;
 static int irq_list[16];
-static int irq_list_count;
+static unsigned int irq_list_count;
 
 /* The card status change interrupt -- 0 means autoselect */
 static int cs_irq;
index 93ee05eeaeba810f6bda495c5655cccc4031de7f..78277a118b6773268d7813b33d3fbe19dc79d6d0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SuperH On-Chip RTC Support
  *
- * Copyright (C) 2006  Paul Mundt
+ * Copyright (C) 2006, 2007  Paul Mundt
  * Copyright (C) 2006  Jamie Lenehan
  *
  * Based on the old arch/sh/kernel/cpu/rtc.c by:
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
+#include <asm/rtc.h>
 
 #define DRV_NAME       "sh-rtc"
-#define DRV_VERSION    "0.1.2"
+#define DRV_VERSION    "0.1.3"
 
 #ifdef CONFIG_CPU_SH3
 #define rtc_reg_size           sizeof(u16)
 #define RTC_BIT_INVERTED       0       /* No bug on SH7708, SH7709A */
+#define RTC_DEF_CAPABILITIES   0UL
 #elif defined(CONFIG_CPU_SH4)
 #define rtc_reg_size           sizeof(u32)
 #define RTC_BIT_INVERTED       0x40    /* bug on SH7750, SH7750S */
+#define RTC_DEF_CAPABILITIES   RTC_CAP_4_DIGIT_YEAR
 #endif
 
 #define RTC_REG(r)     ((r) * rtc_reg_size)
@@ -80,6 +83,7 @@ struct sh_rtc {
        struct rtc_device *rtc_dev;
        spinlock_t lock;
        int rearm_aie;
+       unsigned long capabilities;     /* See asm-sh/rtc.h for cap bits */
 };
 
 static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
@@ -319,14 +323,14 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
                tm->tm_mday     = BCD2BIN(readb(rtc->regbase + RDAYCNT));
                tm->tm_mon      = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
 
-#if defined(CONFIG_CPU_SH4)
-               yr  = readw(rtc->regbase + RYRCNT);
-               yr100 = BCD2BIN(yr >> 8);
-               yr &= 0xff;
-#else
-               yr  = readb(rtc->regbase + RYRCNT);
-               yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
-#endif
+               if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+                       yr  = readw(rtc->regbase + RYRCNT);
+                       yr100 = BCD2BIN(yr >> 8);
+                       yr &= 0xff;
+               } else {
+                       yr  = readb(rtc->regbase + RYRCNT);
+                       yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
+               }
 
                tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
 
@@ -375,14 +379,14 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
        writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
        writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);
 
-#ifdef CONFIG_CPU_SH3
-       year = tm->tm_year % 100;
-       writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
-#else
-       year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
-               BIN2BCD(tm->tm_year % 100);
-       writew(year, rtc->regbase + RYRCNT);
-#endif
+       if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+               year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
+                       BIN2BCD(tm->tm_year % 100);
+               writew(year, rtc->regbase + RYRCNT);
+       } else {
+               year = tm->tm_year % 100;
+               writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
+       }
 
        /* Start RTC */
        tmp = readb(rtc->regbase + RCR2);
@@ -589,6 +593,17 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
                goto err_badmap;
        }
 
+       rtc->capabilities = RTC_DEF_CAPABILITIES;
+       if (pdev->dev.platform_data) {
+               struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data;
+
+               /*
+                * Some CPUs have special capabilities in addition to the
+                * default set. Add those in here.
+                */
+               rtc->capabilities |= pinfo->capabilities;
+       }
+
        platform_set_drvdata(pdev, rtc);
 
        return 0;
index 90aa53fc4f3e40cfb4fadee0e7f72e176ec45265..7507067351bd83b0ff00b20d890ae7a4671a5ed2 100644 (file)
@@ -891,7 +891,7 @@ zfcp_unit_dequeue(struct zfcp_unit *unit)
 /*
  * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI
  * commands.
- * It also genrates fcp-nameserver request/response buffer and unsolicited 
+ * It also genrates fcp-nameserver request/response buffer and unsolicited
  * status read fsf_req buffers.
  *
  * locks:       must only be called with zfcp_data.config_sema taken
@@ -982,7 +982,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
        struct zfcp_adapter *adapter;
 
        /*
-        * Note: It is safe to release the list_lock, as any list changes 
+        * Note: It is safe to release the list_lock, as any list changes
         * are protected by the config_sema, which must be held to get here
         */
 
@@ -1038,6 +1038,10 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
        spin_lock_init(&adapter->san_dbf_lock);
        spin_lock_init(&adapter->scsi_dbf_lock);
 
+       retval = zfcp_adapter_debug_register(adapter);
+       if (retval)
+               goto debug_register_failed;
+
        /* initialize error recovery stuff */
 
        rwlock_init(&adapter->erp_lock);
@@ -1058,7 +1062,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
        /* mark adapter unusable as long as sysfs registration is not complete */
        atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
 
-       adapter->ccw_device = ccw_device;
        dev_set_drvdata(&ccw_device->dev, adapter);
 
        if (zfcp_sysfs_adapter_create_files(&ccw_device->dev))
@@ -1085,6 +1088,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
  generic_services_failed:
        zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
  sysfs_failed:
+       zfcp_adapter_debug_unregister(adapter);
+ debug_register_failed:
        dev_set_drvdata(&ccw_device->dev, NULL);
        zfcp_reqlist_free(adapter);
  failed_low_mem_buffers:
@@ -1130,6 +1135,8 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
                goto out;
        }
 
+       zfcp_adapter_debug_unregister(adapter);
+
        /* remove specified adapter data structure from list */
        write_lock_irq(&zfcp_data.config_lock);
        list_del(&adapter->list);
index c0d1c0eb32099f225a8d972cc164d1a19d3ae25b..e01cbf152a81d3622a5d4a607b103ab472e607d0 100644 (file)
@@ -148,15 +148,12 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
        down(&zfcp_data.config_sema);
        adapter = dev_get_drvdata(&ccw_device->dev);
 
-       retval = zfcp_adapter_debug_register(adapter);
-       if (retval)
-               goto out;
        retval = zfcp_erp_thread_setup(adapter);
        if (retval) {
                ZFCP_LOG_INFO("error: start of error recovery thread for "
                              "adapter %s failed\n",
                              zfcp_get_busid_by_adapter(adapter));
-               goto out_erp_thread;
+               goto out;
        }
 
        retval = zfcp_adapter_scsi_register(adapter);
@@ -175,8 +172,6 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
 
  out_scsi_register:
        zfcp_erp_thread_kill(adapter);
- out_erp_thread:
-       zfcp_adapter_debug_unregister(adapter);
  out:
        up(&zfcp_data.config_sema);
        return retval;
@@ -199,7 +194,6 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device)
        zfcp_erp_adapter_shutdown(adapter, 0);
        zfcp_erp_wait(adapter);
        zfcp_erp_thread_kill(adapter);
-       zfcp_adapter_debug_unregister(adapter);
        up(&zfcp_data.config_sema);
        return 0;
 }
index b36dfc40d9fa26b41ee3aca598eabe3a9c999bd0..16e5563e0c651959aad3bd4e7cf7c90aacf0bfaf 100644 (file)
@@ -1,23 +1,23 @@
-/* 
+/*
  * This file is part of the zfcp device driver for
  * FCP adapters for IBM System z9 and zSeries.
  *
  * (C) Copyright IBM Corp. 2002, 2006
- * 
- * This program is free software; you can redistribute it and/or modify 
- * it under the terms of the GNU General Public License as published by 
- * the Free Software Foundation; either version 2, or (at your option) 
- * any later version. 
- * 
- * This program is distributed in the hope that it will be useful, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
- * GNU General Public License for more details. 
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
- */ 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
 #ifndef ZFCP_DEF_H
 #define ZFCP_DEF_H
@@ -90,7 +90,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list)
 #define ZFCP_DEVICE_TYPE        0x1732
 #define ZFCP_DEVICE_MODEL       0x03
 #define ZFCP_DEVICE_MODEL_PRIV 0x04
+
 /* allow as many chained SBALs as are supported by hardware */
 #define ZFCP_MAX_SBALS_PER_REQ         FSF_MAX_SBALS_PER_REQ
 #define ZFCP_MAX_SBALS_PER_CT_REQ      FSF_MAX_SBALS_PER_REQ
@@ -508,7 +508,7 @@ struct zfcp_rc_entry {
 
 /*
  * this allows removal of logging code by the preprocessor
- * (the most detailed log level still to be compiled in is specified, 
+ * (the most detailed log level still to be compiled in is specified,
  * higher log levels are removed)
  */
 #define ZFCP_LOG_LEVEL_LIMIT   ZFCP_LOG_LEVEL_TRACE
@@ -546,7 +546,7 @@ do { \
        if (ZFCP_LOG_CHECK(level)) \
                _ZFCP_LOG(fmt, ##args); \
 } while (0)
-       
+
 #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
 # define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0)
 #else
@@ -583,8 +583,8 @@ do { \
 
 /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
 
-/* 
- * Note, the leftmost status byte is common among adapter, port 
+/*
+ * Note, the leftmost status byte is common among adapter, port
  * and unit
  */
 #define ZFCP_COMMON_FLAGS                      0xfff00000
@@ -1007,8 +1007,8 @@ struct zfcp_fsf_req {
        u32                    fsf_command;    /* FSF Command copy */
        struct fsf_qtcb        *qtcb;          /* address of associated QTCB */
        u32                    seq_no;         /* Sequence number of request */
-        unsigned long          data;           /* private data of request */ 
-       struct timer_list      timer;          /* used for erp or scsi er */
+       unsigned long          data;           /* private data of request */
+       struct timer_list     timer;           /* used for erp or scsi er */
        struct zfcp_erp_action *erp_action;    /* used if this request is
                                                  issued on behalf of erp */
        mempool_t              *pool;          /* used if request was alloacted
index 16b4418ab257460069342c8518fa3d6fc6ed438d..a6475a2bb8a7df713343ce615a1c10ec2442fc11 100644 (file)
@@ -1,22 +1,22 @@
-/* 
+/*
  * This file is part of the zfcp device driver for
  * FCP adapters for IBM System z9 and zSeries.
  *
  * (C) Copyright IBM Corp. 2002, 2006
- * 
- * This program is free software; you can redistribute it and/or modify 
- * it under the terms of the GNU General Public License as published by 
- * the Free Software Foundation; either version 2, or (at your option) 
- * any later version. 
- * 
- * This program is distributed in the hope that it will be useful, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
- * GNU General Public License for more details. 
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_ERP
@@ -191,7 +191,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    called if an adapter failed,
  *             initiates adapter recovery which is done
@@ -228,7 +228,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    Wrappper for zfcp_erp_adapter_reopen_internal
  *              used to ensure the correct locking
@@ -476,7 +476,7 @@ zfcp_test_link(struct zfcp_port *port)
 
 
 /*
- * function:   
+ * function:
  *
  * purpose:    called if a port failed to be opened normally
  *             initiates Forced Reopen recovery which is done
@@ -517,7 +517,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    Wrappper for zfcp_erp_port_forced_reopen_internal
  *              used to ensure the correct locking
@@ -543,7 +543,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    called if a port is to be opened
  *             initiates Reopen recovery which is done
@@ -612,7 +612,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    called if a unit is to be opened
  *             initiates Reopen recovery which is done
@@ -704,7 +704,7 @@ static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    disable I/O,
  *             return any open requests and clean them up,
@@ -725,7 +725,7 @@ zfcp_erp_port_block(struct zfcp_port *port, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    enable I/O
  *
@@ -742,7 +742,7 @@ zfcp_erp_port_unblock(struct zfcp_port *port)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    disable I/O,
  *             return any open requests and clean them up,
@@ -763,7 +763,7 @@ zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    enable I/O
  *
@@ -792,7 +792,7 @@ zfcp_erp_action_ready(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:
  *
@@ -967,7 +967,7 @@ static void zfcp_erp_timeout_handler(unsigned long data)
  * zfcp_erp_action_dismiss - dismiss an erp_action
  *
  * adapter->erp_lock must be held
- * 
+ *
  * Dismissal of an erp_action is usually required if an erp_action of
  * higher priority is generated.
  */
@@ -1005,9 +1005,9 @@ zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:
  *
@@ -1094,7 +1094,7 @@ zfcp_erp_thread(void *data)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    drives single error recovery action and schedules higher and
  *             subordinate actions, if necessary
@@ -1206,7 +1206,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
 
        /*
         * put this target through the erp mill again if someone has
-        * requested to change the status of a target being online 
+        * requested to change the status of a target being online
         * to offline or the other way around
         * (old retval is preserved if nothing has to be done here)
         */
@@ -1228,7 +1228,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
  unlock:
        write_unlock(&adapter->erp_lock);
        read_unlock_irqrestore(&zfcp_data.config_lock, flags);
-       
+
        if (retval != ZFCP_ERP_CONTINUES)
                zfcp_erp_action_cleanup(action, adapter, port, unit, retval);
 
@@ -1250,9 +1250,9 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_DISMISSED      - if action has been dismissed
  *             retval                  - otherwise
@@ -1322,7 +1322,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    triggers retry of this action after a certain amount of time
  *             by means of timer provided by erp_action
@@ -1346,7 +1346,7 @@ zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
-/* 
+/*
  * function:    zfcp_erp_adapter_failed
  *
  * purpose:     sets the adapter and all underlying devices to ERP_FAILED
@@ -1362,7 +1362,7 @@ zfcp_erp_adapter_failed(struct zfcp_adapter *adapter)
        debug_text_event(adapter->erp_dbf, 2, "a_afail");
 }
 
-/* 
+/*
  * function:    zfcp_erp_port_failed
  *
  * purpose:     sets the port and all underlying devices to ERP_FAILED
@@ -1386,7 +1386,7 @@ zfcp_erp_port_failed(struct zfcp_port *port)
        debug_event(port->adapter->erp_dbf, 2, &port->wwpn, sizeof (wwn_t));
 }
 
-/* 
+/*
  * function:    zfcp_erp_unit_failed
  *
  * purpose:     sets the unit to ERP_FAILED
@@ -1417,7 +1417,7 @@ zfcp_erp_unit_failed(struct zfcp_unit *unit)
  *              successfully is reset.
  *
  * returns:    ZFCP_ERP_CONTINUES      - action continues (not considered)
- *             ZFCP_ERP_SUCCEEDED      - action finished successfully 
+ *             ZFCP_ERP_SUCCEEDED      - action finished successfully
  *             ZFCP_ERP_EXIT           - action failed and will not continue
  */
 static int
@@ -1646,7 +1646,7 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    remaining things in good cases,
  *             escalation in bad cases
@@ -1687,8 +1687,8 @@ zfcp_erp_strategy_followup_actions(int action,
                break;
 
        case ZFCP_ERP_ACTION_REOPEN_UNIT:
-               if (status == ZFCP_ERP_SUCCEEDED) ;     /* no further action */
-               else
+               /* Nothing to do if status == ZFCP_ERP_SUCCEEDED */
+               if (status != ZFCP_ERP_SUCCEEDED)
                        zfcp_erp_port_reopen_internal(unit->port, 0);
                break;
        }
@@ -1815,7 +1815,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    Wrappper for zfcp_erp_port_reopen_all_internal
  *              used to ensure the correct locking
@@ -1852,9 +1852,9 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    FIXME
  */
@@ -1871,7 +1871,7 @@ zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, int clear_mask)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    this routine executes the 'Reopen Adapter' action
  *             (the entire action is processed synchronously, since
@@ -1908,9 +1908,9 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_SUCCEEDED      - action finished successfully
  *              ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -1930,9 +1930,9 @@ zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_SUCCEEDED      - action finished successfully
  *              ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -1957,7 +1957,7 @@ zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action)
  * purpose:    allocate the irq associated with this devno and register
  *             the FSF adapter with the SCSI stack
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
@@ -2197,7 +2197,7 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
        zfcp_erp_action_to_running(erp_action);
        write_unlock_irq(&adapter->erp_lock);
 
-       ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL);
+       ret = zfcp_fsf_exchange_port_data(erp_action);
        if (ret == -EOPNOTSUPP) {
                debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp");
                return ZFCP_ERP_SUCCEEDED;
@@ -2249,7 +2249,7 @@ zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    this routine executes the 'Reopen Physical Port' action
  *
@@ -2308,7 +2308,7 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    this routine executes the 'Reopen Port' action
  *
@@ -2530,7 +2530,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    makes the erp thread continue with reopen (physical) port
  *             actions which have been paused until the name server port
@@ -2570,9 +2570,9 @@ zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_CONTINUES      - action continues (asynchronously)
  *             ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -2626,9 +2626,9 @@ zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_CONTINUES      - action continues (asynchronously)
  *             ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -2663,9 +2663,9 @@ zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_CONTINUES      - action continues (asynchronously)
  *             ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -2700,9 +2700,9 @@ zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_CONTINUES      - action continues (asynchronously)
  *             ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -2737,7 +2737,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    this routine executes the 'Reopen Unit' action
  *             currently no retries
@@ -2825,9 +2825,9 @@ zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_CONTINUES      - action continues (asynchronously)
  *             ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -2865,9 +2865,9 @@ zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
 }
 
 /*
- * function:   
+ * function:
  *
- * purpose:    
+ * purpose:
  *
  * returns:    ZFCP_ERP_CONTINUES      - action continues (asynchronously)
  *             ZFCP_ERP_FAILED         - action finished unsuccessfully
@@ -2913,7 +2913,7 @@ void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req)
 }
 
 /*
- * function:   
+ * function:
  *
  * purpose:    enqueue the specified error recovery action, if needed
  *
@@ -2992,7 +2992,7 @@ zfcp_erp_action_enqueue(int action,
                                              port->erp_action.action);
                                debug_text_event(adapter->erp_dbf, 4,
                                                 "pf_actenq_drp");
-                       } else 
+                       } else
                                debug_text_event(adapter->erp_dbf, 4,
                                                 "pf_actenq_drpcp");
                        debug_event(adapter->erp_dbf, 4, &port->wwpn,
index 991d45667a44d0453f06d0134d1345a8a5509d2a..8534cf09546c3c120a6b23d4a1a8ebd76a6b7894 100644 (file)
@@ -1,22 +1,22 @@
-/* 
+/*
  * This file is part of the zfcp device driver for
  * FCP adapters for IBM System z9 and zSeries.
  *
  * (C) Copyright IBM Corp. 2002, 2006
- * 
- * This program is free software; you can redistribute it and/or modify 
- * it under the terms of the GNU General Public License as published by 
- * the Free Software Foundation; either version 2, or (at your option) 
- * any later version. 
- * 
- * This program is distributed in the hope that it will be useful, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
- * GNU General Public License for more details. 
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef ZFCP_EXT_H
@@ -82,9 +82,11 @@ extern int  zfcp_fsf_open_unit(struct zfcp_erp_action *);
 extern int  zfcp_fsf_close_unit(struct zfcp_erp_action *);
 
 extern int  zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
-extern int  zfcp_fsf_exchange_port_data(struct zfcp_erp_action *,
-                                       struct zfcp_adapter *,
-                                       struct fsf_qtcb_bottom_port *);
+extern int  zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *,
+                                              struct fsf_qtcb_bottom_config *);
+extern int  zfcp_fsf_exchange_port_data(struct zfcp_erp_action *);
+extern int  zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *,
+                                             struct fsf_qtcb_bottom_port *);
 extern int  zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
                                  u32, u32, struct zfcp_sg_list *);
 extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
index 99299976e89195288a32768147325b4958e99aea..ff866ebd44ac1ae2771d62b346d485489c2473e5 100644 (file)
@@ -80,10 +80,10 @@ static const char zfcp_act_subtable_type[5][8] = {
 /*
  * function:   zfcp_fsf_req_alloc
  *
- * purpose:     Obtains an fsf_req and potentially a qtcb (for all but 
+ * purpose:     Obtains an fsf_req and potentially a qtcb (for all but
  *              unsolicited requests) via helper functions
  *              Does some initial fsf request set-up.
- *              
+ *
  * returns:    pointer to allocated fsf_req if successfull
  *              NULL otherwise
  *
@@ -192,7 +192,7 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
  * returns:    0 - success
  *             !0 - failure
  *
- * context:    
+ * context:
  */
 int
 zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
@@ -214,8 +214,8 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
        }
 
        /*
-        * fsf_req may be deleted due to waking up functions, so 
-        * cleanup is saved here and used later 
+        * fsf_req may be deleted due to waking up functions, so
+        * cleanup is saved here and used later
         */
        if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
                cleanup = 1;
@@ -259,9 +259,9 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
  *             and initiates appropriate actions
  *             (usually calling FSF command specific handlers)
  *
- * returns:    
+ * returns:
  *
- * context:    
+ * context:
  *
  * locks:
  */
@@ -638,7 +638,7 @@ zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
  *
  * purpose:    calls the appropriate command specific handler
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
@@ -854,7 +854,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
  *
  * purpose:    is called for finished Open Port command
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
@@ -1088,7 +1088,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
  * returns:    address of initiated FSF request
  *             NULL - request could not be initiated
  *
- * FIXME(design): should be watched by a timeout !!! 
+ * FIXME(design): should be watched by a timeout !!!
  * FIXME(design) shouldn't this be modified to return an int
  *               also...don't know how though
  */
@@ -1157,7 +1157,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
  *
  * purpose:    is called for finished Abort FCP Command request
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
@@ -1941,25 +1941,28 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 {
        volatile struct qdio_buffer_element *sbale;
        struct zfcp_fsf_req *fsf_req;
+       struct zfcp_adapter *adapter = erp_action->adapter;
        unsigned long lock_flags;
-       int retval = 0;
+       int retval;
 
        /* setup new FSF request */
-       retval = zfcp_fsf_req_create(erp_action->adapter,
+       retval = zfcp_fsf_req_create(adapter,
                                     FSF_QTCB_EXCHANGE_CONFIG_DATA,
                                     ZFCP_REQ_AUTO_CLEANUP,
-                                    erp_action->adapter->pool.fsf_req_erp,
+                                    adapter->pool.fsf_req_erp,
                                     &lock_flags, &fsf_req);
-       if (retval < 0) {
+       if (retval) {
                ZFCP_LOG_INFO("error: Could not create exchange configuration "
                              "data request for adapter %s.\n",
-                             zfcp_get_busid_by_adapter(erp_action->adapter));
-               goto out;
+                             zfcp_get_busid_by_adapter(adapter));
+               write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+                                       lock_flags);
+               return retval;
        }
 
        sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
-        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
 
        fsf_req->qtcb->bottom.config.feature_selection =
                        FSF_FEATURE_CFDC |
@@ -1971,23 +1974,71 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 
        zfcp_erp_start_timer(fsf_req);
        retval = zfcp_fsf_req_send(fsf_req);
+       write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+                               lock_flags);
        if (retval) {
-               ZFCP_LOG_INFO
-                   ("error: Could not send exchange configuration data "
-                    "command on the adapter %s\n",
-                    zfcp_get_busid_by_adapter(erp_action->adapter));
+               ZFCP_LOG_INFO("error: Could not send exchange configuration "
+                             "data command on the adapter %s\n",
+                             zfcp_get_busid_by_adapter(adapter));
                zfcp_fsf_req_free(fsf_req);
                erp_action->fsf_req = NULL;
-               goto out;
        }
+       else
+               ZFCP_LOG_DEBUG("exchange configuration data request initiated "
+                              "(adapter %s)\n",
+                              zfcp_get_busid_by_adapter(adapter));
 
-       ZFCP_LOG_DEBUG("exchange configuration data request initiated "
-                      "(adapter %s)\n",
-                      zfcp_get_busid_by_adapter(erp_action->adapter));
+       return retval;
+}
 
- out:
-       write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
+int
+zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
+                               struct fsf_qtcb_bottom_config *data)
+{
+       volatile struct qdio_buffer_element *sbale;
+       struct zfcp_fsf_req *fsf_req;
+       unsigned long lock_flags;
+       int retval;
+
+       /* setup new FSF request */
+       retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
+                                    0, NULL, &lock_flags, &fsf_req);
+       if (retval) {
+               ZFCP_LOG_INFO("error: Could not create exchange configuration "
+                             "data request for adapter %s.\n",
+                             zfcp_get_busid_by_adapter(adapter));
+               write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+                                       lock_flags);
+               return retval;
+       }
+
+       sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+       fsf_req->qtcb->bottom.config.feature_selection =
+                       FSF_FEATURE_CFDC |
+                       FSF_FEATURE_LUN_SHARING |
+                       FSF_FEATURE_NOTIFICATION_LOST |
+                       FSF_FEATURE_UPDATE_ALERT;
+
+       if (data)
+               fsf_req->data = (unsigned long) data;
+
+       zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+       retval = zfcp_fsf_req_send(fsf_req);
+       write_unlock_irqrestore(&adapter->request_queue.queue_lock,
                                lock_flags);
+       if (retval)
+               ZFCP_LOG_INFO("error: Could not send exchange configuration "
+                             "data command on the adapter %s\n",
+                             zfcp_get_busid_by_adapter(adapter));
+       else
+               wait_event(fsf_req->completion_wq,
+                          fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
+       zfcp_fsf_req_free(fsf_req);
+
        return retval;
 }
 
@@ -2016,11 +2067,17 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
        adapter->peer_d_id = 0;
 
        if (xchg_ok) {
+
+               if (fsf_req->data)
+                       memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data,
+                               bottom, sizeof (struct fsf_qtcb_bottom_config));
+
                fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
                fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
                fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
                fc_host_speed(shost) = bottom->fc_link_speed;
-               fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
+               fc_host_supported_classes(shost) =
+                               FC_COS_CLASS2 | FC_COS_CLASS3;
                adapter->hydra_version = bottom->adapter_type;
                if (fc_host_permanent_port_name(shost) == -1)
                        fc_host_permanent_port_name(shost) =
@@ -2053,7 +2110,8 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
                       min(FC_SERIAL_NUMBER_SIZE, 17));
        }
 
-       ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
+       ZFCP_LOG_NORMAL("The adapter %s reported the following "
+                       "characteristics:\n"
                        "WWNN 0x%016Lx, "
                        "WWPN 0x%016Lx, "
                        "S_ID 0x%06x,\n"
@@ -2090,7 +2148,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
        return 0;
 }
 
-/*
+/**
  * function:    zfcp_fsf_exchange_config_data_handler
  *
  * purpose:     is called for finished Exchange Configuration Data command
@@ -2125,7 +2183,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                                        adapter->peer_wwpn,
                                        adapter->peer_d_id);
                        debug_text_event(fsf_req->adapter->erp_dbf, 0,
-                                        "top-p-to-p");
+                                       "top-p-to-p");
                        break;
                case FC_PORTTYPE_NLPORT:
                        ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
@@ -2138,8 +2196,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                        return -EIO;
                case FC_PORTTYPE_NPORT:
                        ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
-                                     "network detected at adapter %s.\n",
-                                     zfcp_get_busid_by_adapter(adapter));
+                                       "network detected at adapter %s.\n",
+                                       zfcp_get_busid_by_adapter(adapter));
                        break;
                default:
                        ZFCP_LOG_NORMAL("bug: The fibrechannel topology "
@@ -2179,7 +2237,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
                        return -EIO;
 
-               atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
+               atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
+                               &adapter->status);
 
                zfcp_fsf_link_down_info_eval(adapter,
                        &qtcb->header.fsf_status_qual.link_down_info);
@@ -2187,7 +2246,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
        default:
                debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
                debug_event(fsf_req->adapter->erp_dbf, 0,
-                           &fsf_req->qtcb->header.fsf_status, sizeof (u32));
+                           &fsf_req->qtcb->header.fsf_status, sizeof(u32));
                zfcp_erp_adapter_shutdown(adapter, 0);
                return -EIO;
        }
@@ -2197,74 +2256,118 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
 /**
  * zfcp_fsf_exchange_port_data - request information about local port
  * @erp_action: ERP action for the adapter for which port data is requested
- * @adapter: for which port data is requested
- * @data: response to exchange port data request
  */
 int
-zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
-                           struct zfcp_adapter *adapter,
-                           struct fsf_qtcb_bottom_port *data)
+zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
 {
        volatile struct qdio_buffer_element *sbale;
-        struct zfcp_fsf_req *fsf_req;
+       struct zfcp_fsf_req *fsf_req;
+       struct zfcp_adapter *adapter = erp_action->adapter;
        unsigned long lock_flags;
-       int retval = 0;
+       int retval;
 
        if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
                ZFCP_LOG_INFO("error: exchange port data "
-                              "command not supported by adapter %s\n",
+                             "command not supported by adapter %s\n",
                              zfcp_get_busid_by_adapter(adapter));
-                return -EOPNOTSUPP;
-        }
+               return -EOPNOTSUPP;
+       }
 
        /* setup new FSF request */
        retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
-                                    erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
-                                    NULL, &lock_flags, &fsf_req);
-       if (retval < 0) {
+                                    ZFCP_REQ_AUTO_CLEANUP,
+                                    adapter->pool.fsf_req_erp,
+                                    &lock_flags, &fsf_req);
+       if (retval) {
                ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-                              "exchange port data request for"
-                              "the adapter %s.\n",
+                             "exchange port data request for"
+                             "the adapter %s.\n",
                              zfcp_get_busid_by_adapter(adapter));
                write_unlock_irqrestore(&adapter->request_queue.queue_lock,
                                        lock_flags);
                return retval;
        }
 
-       if (data)
-               fsf_req->data = (unsigned long) data;
-
        sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
-        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
 
-       if (erp_action) {
-               erp_action->fsf_req = fsf_req;
-               fsf_req->erp_action = erp_action;
-               zfcp_erp_start_timer(fsf_req);
-       } else
-               zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+       erp_action->fsf_req = fsf_req;
+       fsf_req->erp_action = erp_action;
+       zfcp_erp_start_timer(fsf_req);
 
        retval = zfcp_fsf_req_send(fsf_req);
+       write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+
        if (retval) {
                ZFCP_LOG_INFO("error: Could not send an exchange port data "
-                              "command on the adapter %s\n",
+                             "command on the adapter %s\n",
                              zfcp_get_busid_by_adapter(adapter));
                zfcp_fsf_req_free(fsf_req);
-               if (erp_action)
-                       erp_action->fsf_req = NULL;
+               erp_action->fsf_req = NULL;
+       }
+       else
+               ZFCP_LOG_DEBUG("exchange port data request initiated "
+                              "(adapter %s)\n",
+                              zfcp_get_busid_by_adapter(adapter));
+       return retval;
+}
+
+
+/**
+ * zfcp_fsf_exchange_port_data_sync - request information about local port
+ * and wait until information is ready
+ */
+int
+zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
+                               struct fsf_qtcb_bottom_port *data)
+{
+       volatile struct qdio_buffer_element *sbale;
+       struct zfcp_fsf_req *fsf_req;
+       unsigned long lock_flags;
+       int retval;
+
+       if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
+               ZFCP_LOG_INFO("error: exchange port data "
+                             "command not supported by adapter %s\n",
+                             zfcp_get_busid_by_adapter(adapter));
+               return -EOPNOTSUPP;
+       }
+
+       /* setup new FSF request */
+       retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
+                               0, NULL, &lock_flags, &fsf_req);
+       if (retval) {
+               ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+                             "exchange port data request for"
+                             "the adapter %s.\n",
+                             zfcp_get_busid_by_adapter(adapter));
                write_unlock_irqrestore(&adapter->request_queue.queue_lock,
                                        lock_flags);
                return retval;
        }
 
+       if (data)
+               fsf_req->data = (unsigned long) data;
+
+       sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+       zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+       retval = zfcp_fsf_req_send(fsf_req);
        write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
 
-       if (!erp_action) {
+       if (retval)
+               ZFCP_LOG_INFO("error: Could not send an exchange port data "
+                             "command on the adapter %s\n",
+                             zfcp_get_busid_by_adapter(adapter));
+       else
                wait_event(fsf_req->completion_wq,
                           fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
-               zfcp_fsf_req_free(fsf_req);
-       }
+
+       zfcp_fsf_req_free(fsf_req);
+
        return retval;
 }
 
@@ -2277,18 +2380,16 @@ static void
 zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
 {
        struct zfcp_adapter *adapter;
-       struct fsf_qtcb *qtcb;
-       struct fsf_qtcb_bottom_port *bottom, *data;
+       struct fsf_qtcb_bottom_port *bottom;
        struct Scsi_Host *shost;
 
        adapter = fsf_req->adapter;
-       qtcb = fsf_req->qtcb;
-       bottom = &qtcb->bottom.port;
+       bottom = &fsf_req->qtcb->bottom.port;
        shost = adapter->scsi_host;
 
-       data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
-       if (data)
-               memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port));
+       if (fsf_req->data)
+               memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom,
+                       sizeof(struct fsf_qtcb_bottom_port));
 
        if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
                fc_host_permanent_port_name(shost) = bottom->wwpn;
@@ -2336,10 +2437,10 @@ zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
 /*
  * function:    zfcp_fsf_open_port
  *
- * purpose:    
+ * purpose:
  *
  * returns:    address of initiated FSF request
- *             NULL - request could not be initiated 
+ *             NULL - request could not be initiated
  */
 int
 zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
@@ -2400,7 +2501,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
  *
  * purpose:    is called for finished Open Port command
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
@@ -3002,7 +3103,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
  *
  * purpose:    is called for finished Open LUN command
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
@@ -3265,7 +3366,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
  * purpose:
  *
  * returns:    address of fsf_req - request successfully initiated
- *             NULL - 
+ *             NULL -
  *
  * assumptions: This routine does not check whether the associated
  *              remote port/lun has already been opened. This should be
@@ -3586,17 +3687,17 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
                        ZFCP_LOG_DEBUG(
                                "Data did not fit into available buffer(s), "
                               "waiting for more...\n");
-               retval = -EIO;
-       } else {
-               ZFCP_LOG_NORMAL("error: No truncation implemented but "
-                               "required. Shutting down unit "
-                               "(adapter %s, port 0x%016Lx, "
-                               "unit 0x%016Lx)\n",
-                               zfcp_get_busid_by_unit(unit),
-                               unit->port->wwpn,
-                               unit->fcp_lun);
-               zfcp_erp_unit_shutdown(unit, 0);
-               retval = -EINVAL;
+                       retval = -EIO;
+               } else {
+                       ZFCP_LOG_NORMAL("error: No truncation implemented but "
+                                       "required. Shutting down unit "
+                                       "(adapter %s, port 0x%016Lx, "
+                                       "unit 0x%016Lx)\n",
+                                       zfcp_get_busid_by_unit(unit),
+                                       unit->port->wwpn,
+                                       unit->fcp_lun);
+                       zfcp_erp_unit_shutdown(unit, 0);
+                       retval = -EINVAL;
                }
                goto no_fit;
        }
@@ -3727,7 +3828,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
  *
  * purpose:    is called for finished Send FCP Command
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
@@ -3964,7 +4065,7 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
  *
  * purpose:    evaluates FCP_RSP IU
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
@@ -4192,7 +4293,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
  *
  * purpose:    evaluates FCP_RSP IU
  *
- * returns:    
+ * returns:
  */
 static int
 zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
@@ -4635,7 +4736,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
        INIT_LIST_HEAD(&fsf_req->list);
        init_timer(&fsf_req->timer);
 
-       /* initialize waitqueue which may be used to wait on 
+       /* initialize waitqueue which may be used to wait on
           this request completion */
        init_waitqueue_head(&fsf_req->completion_wq);
 
index 71186618947c5abf7187b210a71b17f99bf94f73..8cce5cc11d50c23e0df383ad08d65ee5ab67136f 100644 (file)
@@ -1,22 +1,22 @@
-/* 
+/*
  * This file is part of the zfcp device driver for
  * FCP adapters for IBM System z9 and zSeries.
  *
  * (C) Copyright IBM Corp. 2002, 2006
- * 
- * This program is free software; you can redistribute it and/or modify 
- * it under the terms of the GNU General Public License as published by 
- * the Free Software Foundation; either version 2, or (at your option) 
- * any later version. 
- * 
- * This program is distributed in the hope that it will be useful, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
- * GNU General Public License for more details. 
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef FSF_H
index c6899efdc8f66fd8633ec03b38993b43762dd86b..3f105fdcf239610b18e14a9617b90630b0444302 100644 (file)
@@ -174,10 +174,9 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
                 * That is why we need to clear the link-down flag
                 * which is set again in case we have missed by a mile.
                 */
-               zfcp_erp_adapter_reopen(
-                       adapter, 
-                       ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
-                       ZFCP_STATUS_COMMON_ERP_FAILED);
+               zfcp_erp_adapter_reopen(adapter,
+                                      ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+                                      ZFCP_STATUS_COMMON_ERP_FAILED);
        }
        return retval;
 }
index ad7eb4a9261c64a0450b1a4e0adf54c6c0de0aa9..abae2027f7e598c9b6c6249f6064889af140afa1 100644 (file)
@@ -1,22 +1,22 @@
-/* 
+/*
  * This file is part of the zfcp device driver for
  * FCP adapters for IBM System z9 and zSeries.
  *
  * (C) Copyright IBM Corp. 2002, 2006
- * 
- * This program is free software; you can redistribute it and/or modify 
- * it under the terms of the GNU General Public License as published by 
- * the Free Software Foundation; either version 2, or (at your option) 
- * any later version. 
- * 
- * This program is distributed in the hope that it will be useful, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
- * GNU General Public License for more details. 
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_SCSI
@@ -101,7 +101,7 @@ zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
                ((unsigned char *) fcp_cmd +
                 sizeof (struct fcp_cmnd_iu) + additional_length);
        /*
-        * fcp_dl_addr = start address of fcp_cmnd structure + 
+        * fcp_dl_addr = start address of fcp_cmnd structure +
         * size of fixed part + size of dynamically sized add_dcp_cdb field
         * SEE FCP-2 documentation
         */
@@ -189,13 +189,12 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
                unit->device = NULL;
                zfcp_erp_unit_failed(unit);
                zfcp_unit_put(unit);
-       } else {
+       } else
                ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at "
                                "address %p\n", sdpnt);
-       }
 }
 
-/* 
+/*
  * called from scsi midlayer to allow finetuning of a device.
  */
 static int
@@ -361,12 +360,11 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
        list_for_each_entry(port, &adapter->port_list_head, list) {
                if (!port->rport || (id != port->rport->scsi_target_id))
                        continue;
-               list_for_each_entry(unit, &port->unit_list_head, list) {
+               list_for_each_entry(unit, &port->unit_list_head, list)
                        if (lun == unit->scsi_lun) {
                                retval = unit;
                                goto out;
                        }
-               }
        }
  out:
        return retval;
@@ -374,7 +372,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
 
 /**
  * zfcp_scsi_eh_abort_handler - abort the specified SCSI command
- * @scpnt: pointer to scsi_cmnd to be aborted 
+ * @scpnt: pointer to scsi_cmnd to be aborted
  * Return: SUCCESS - command has been aborted and cleaned up in internal
  *          bookkeeping, SCSI stack won't be called for aborted command
  *         FAILED - otherwise
@@ -733,7 +731,7 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost)
        if (!data)
                return NULL;
 
-       ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+       ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
        if (ret) {
                kfree(data);
                return NULL; /* XXX return zeroed fc_stats? */
@@ -763,7 +761,7 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
        if (!data)
                return;
 
-       ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+       ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
        if (ret) {
                kfree(data);
        } else {
@@ -802,6 +800,7 @@ struct fc_function_template zfcp_transport_functions = {
        .show_host_port_type = 1,
        .show_host_speed = 1,
        .show_host_port_id = 1,
+       .disable_target_scan = 1,
 };
 
 /**
index 81a484175863ee2bdac9fb49764f6091149cb18b..63f75ee95c338e588e005228d2b2b18aee204862 100644 (file)
@@ -139,7 +139,7 @@ static struct attribute_group zfcp_unit_attr_group = {
        .attrs = zfcp_unit_attrs,
 };
 
-/** 
+/**
  * zfcp_sysfs_create_unit_files - create sysfs unit files
  * @dev: pointer to belonging device
  *
@@ -151,7 +151,7 @@ zfcp_sysfs_unit_create_files(struct device *dev)
        return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group);
 }
 
-/** 
+/**
  * zfcp_sysfs_remove_unit_files - remove sysfs unit files
  * @dev: pointer to belonging device
  *
index 6f2c71ef47eee062990b76641128361c840f2b85..30905cebefbb4d876f8c249f9334e291ccce5751 100644 (file)
@@ -272,6 +272,13 @@ config SCSI_FC_ATTRS
          each attached FiberChannel device to sysfs, say Y.
          Otherwise, say N.
 
+config SCSI_FC_TGT_ATTRS
+       bool "SCSI target support for FiberChannel Transport Attributes"
+       depends on SCSI_FC_ATTRS
+       depends on SCSI_TGT = y || SCSI_TGT = SCSI_FC_ATTRS
+       help
+               If you want to use SCSI target mode drivers enable this option.
+
 config SCSI_ISCSI_ATTRS
        tristate "iSCSI Transport Attributes"
        depends on SCSI && NET
@@ -289,6 +296,20 @@ config SCSI_SAS_ATTRS
 
 source "drivers/scsi/libsas/Kconfig"
 
+config SCSI_SRP_ATTRS
+       tristate "SRP Transport Attributes"
+       depends on SCSI
+       help
+         If you wish to export transport-specific information about
+         each attached SRP device to sysfs, say Y.
+
+config SCSI_SRP_TGT_ATTRS
+       bool "SCSI target support for SRP Transport Attributes"
+       depends on SCSI_SRP_ATTRS
+       depends on SCSI_TGT = y || SCSI_TGT = SCSI_SRP_ATTRS
+       help
+               If you want to use SCSI target mode drivers enable this option.
+
 endmenu
 
 menuconfig SCSI_LOWLEVEL
@@ -502,7 +523,6 @@ config SCSI_ADVANSYS
        tristate "AdvanSys SCSI support"
        depends on SCSI
        depends on ISA || EISA || PCI
-       depends on BROKEN || X86_32
        help
          This is a driver for all SCSI host adapters manufactured by
          AdvanSys. It is documented in the kernel source in
@@ -524,19 +544,32 @@ config SCSI_IN2000
          module will be called in2000.
 
 config SCSI_ARCMSR
-       tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
+       tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter"
        depends on PCI && SCSI
        help
-         This driver supports all of ARECA's SATA RAID controller cards.
+         This driver supports all of ARECA's SATA/SAS RAID controller cards.
          This is an ARECA-maintained driver by Erich Chen.
-         If you have any problems, please mail to: < erich@areca.com.tw >
+         If you have any problems, please mail to: <erich@areca.com.tw>.
          Areca supports Linux RAID config tools.
-
-         < http://www.areca.com.tw >
+         Please link <http://www.areca.com.tw>
 
          To compile this driver as a module, choose M here: the
          module will be called arcmsr (modprobe arcmsr).
 
+config SCSI_ARCMSR_AER
+       bool "Enable PCI Error Recovery Capability in Areca Driver(ARCMSR)"
+       depends on SCSI_ARCMSR && PCIEAER
+       default n
+       help
+         The advanced error reporting(AER) capability is "NOT" provided by
+         ARC1200/1201/1202 SATA RAID controllers cards.
+         If your card is one of ARC1200/1201/1202, please use the default setting, n.
+         If your card is other models, you could pick it
+         on condition that the kernel version is greater than 2.6.19.
+         This function is maintained driver by Nick Cheng. If you have any
+         problems or suggestion, you are welcome to contact with <nick.cheng@areca.com.tw>.
+         To enable this function, choose Y here.
+
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 
 config SCSI_HPTIOP
@@ -836,6 +869,7 @@ config SCSI_IPS
 config SCSI_IBMVSCSI
        tristate "IBM Virtual SCSI support"
        depends on PPC_PSERIES || PPC_ISERIES
+       select SCSI_SRP_ATTRS
        help
          This is the IBM POWER Virtual SCSI Client
 
@@ -844,7 +878,7 @@ config SCSI_IBMVSCSI
 
 config SCSI_IBMVSCSIS
        tristate "IBM Virtual SCSI Server support"
-       depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP
+       depends on PPC_PSERIES && SCSI_SRP && SCSI_SRP_TGT_ATTRS
        help
          This is the SRP target driver for IBM pSeries virtual environments.
 
index 86a7ba7bad63f4f7b9e3c005e45381a0c351d2db..6141389dcdb24fd28f014e278a2ddec5a614b03b 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS)   += scsi_transport_fc.o
 obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
 obj-$(CONFIG_SCSI_SAS_ATTRS)   += scsi_transport_sas.o
 obj-$(CONFIG_SCSI_SAS_LIBSAS)  += libsas/
+obj-$(CONFIG_SCSI_SRP_ATTRS)   += scsi_transport_srp.o
 
 obj-$(CONFIG_ISCSI_TCP)        += libiscsi.o   iscsi_tcp.o
 obj-$(CONFIG_INFINIBAND_ISER)  += libiscsi.o
index f8e449a98d29e03f9c03a491bbea94c7b158ceb7..988f0bc5eda5e081929864f40f87fbf4e0b49f75 100644 (file)
@@ -1542,9 +1542,7 @@ part2:
        hostdata->connected = cmd;
        hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
 
-       if (cmd->SCp.ptr != (char *)cmd->sense_buffer) {
-               initialize_SCp(cmd);
-       }
+       initialize_SCp(cmd);
 
        return 0;
 
@@ -2133,7 +2131,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                sink = 1;
                                do_abort(instance);
                                cmd->result = DID_ERROR << 16;
-                               cmd->done(cmd);
+                               cmd->scsi_done(cmd);
                                return;
 #endif
                                /* 
@@ -2196,7 +2194,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                                sink = 1;
                                                do_abort(instance);
                                                cmd->result = DID_ERROR << 16;
-                                               cmd->done(cmd);
+                                               cmd->scsi_done(cmd);
                                                /* XXX - need to source or sink data here, as appropriate */
                                        } else
                                                cmd->SCp.this_residual -= transfersize - len;
@@ -2280,19 +2278,16 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                                cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
 
 #ifdef AUTOSENSE
+                                       if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+                                               hostdata->ses.cmd_len) {
+                                               scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+                                               hostdata->ses.cmd_len = 0 ;
+                                       }
+
                                        if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+                                               scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+
                                                dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no));
-                                               cmd->cmnd[0] = REQUEST_SENSE;
-                                               cmd->cmnd[1] &= 0xe0;
-                                               cmd->cmnd[2] = 0;
-                                               cmd->cmnd[3] = 0;
-                                               cmd->cmnd[4] = sizeof(cmd->sense_buffer);
-                                               cmd->cmnd[5] = 0;
-
-                                               cmd->SCp.buffer = NULL;
-                                               cmd->SCp.buffers_residual = 0;
-                                               cmd->SCp.ptr = (char *) cmd->sense_buffer;
-                                               cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
 
                                                LIST(cmd, hostdata->issue_queue);
                                                cmd->host_scribble = (unsigned char *)
@@ -2740,7 +2735,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
                        tmp->host_scribble = NULL;
                        tmp->result = DID_ABORT << 16;
                        dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no));
-                       tmp->done(tmp);
+                       tmp->scsi_done(tmp);
                        return SUCCESS;
                }
 #if (NDEBUG  & NDEBUG_ABORT)
@@ -2805,7 +2800,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
                                        *prev = (Scsi_Cmnd *) tmp->host_scribble;
                                        tmp->host_scribble = NULL;
                                        tmp->result = DID_ABORT << 16;
-                                       tmp->done(tmp);
+                                       tmp->scsi_done(tmp);
                                        return SUCCESS;
                                }
                }
index bccf13f715321a9daaaf82cac1a50d6b868646a8..bdc468c9e1d9d6de71ba091041096fd831512ee7 100644 (file)
 
 #include <linux/interrupt.h>
 
+#ifdef AUTOSENSE
+#include <scsi/scsi_eh.h>
+#endif
+
 #define NCR5380_PUBLIC_RELEASE 7
 #define NCR53C400_PUBLIC_RELEASE 2
 
@@ -281,6 +285,9 @@ struct NCR5380_hostdata {
        unsigned pendingr;
        unsigned pendingw;
 #endif
+#ifdef AUTOSENSE
+       struct scsi_eh_save ses;
+#endif
 };
 
 #ifdef __KERNEL__
index 79b4df1581400691d1b9bbf9676b732a01586167..96e8e29aa05dd5428c58f64c33bbe046c2424d3a 100644 (file)
@@ -1385,7 +1385,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
                                this->host_scribble = NULL;
                                esp_release_dmabufs(esp, this);
                                this->result = DID_ABORT << 16;
-                               this->done(this);
+                               this->scsi_done(this);
                                if(don)
                                        esp->dma_ints_on(esp);
                                return SUCCESS;
index 3a8089705febc738ef719312c734948cc87dac72..9e64b21ef637787c3a5d6e2d709377dafe649c3a 100644 (file)
@@ -97,7 +97,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mca.h>
-#include <linux/interrupt.h>
 #include <asm/io.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
@@ -314,10 +313,10 @@ NCR_D700_probe(struct device *dev)
                break;
        }
 
-       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
-       memset(p, '\0', sizeof(*p));
+
        p->dev = dev;
        snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
        if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) {
index 0c758d1452baa3196010a12f266d3a67d7d17c5e..d4bda201774652d9f3df315fa182832abb52610c 100644 (file)
@@ -37,7 +37,7 @@ static struct platform_device *a4000t_scsi_device;
 
 static int __devinit a4000t_probe(struct device *dev)
 {
-       struct Scsi_Host * host = NULL;
+       struct Scsi_Host *host;
        struct NCR_700_Host_Parameters *hostdata;
 
        if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
@@ -47,12 +47,11 @@ static int __devinit a4000t_probe(struct device *dev)
                                "A4000T builtin SCSI"))
                goto out;
 
-       hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
-       if (hostdata == NULL) {
+       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+       if (!hostdata) {
                printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
                goto out_release;
        }
-       memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
        /* Fill in the required pieces of hostdata */
        hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
index 6800e578e4b1f82dc2a9b4763588497f2835fe63..80e448d0f3dbd541bae7406b68617d904472bc13 100644 (file)
@@ -177,9 +177,9 @@ int check_interval = 24 * 60 * 60;
 module_param(check_interval, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
 
-int check_reset = 1;
-module_param(check_reset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter.");
+int aac_check_reset = 1;
+module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter.");
 
 int expose_physicals = -1;
 module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
@@ -1305,7 +1305,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
                          (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
                          dev->supplement_adapter_info.VpdInfo.Tsid);
                }
-               if (!check_reset ||
+               if (!aac_check_reset ||
                  (dev->supplement_adapter_info.SupportedOptions2 &
                  le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
                        printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
index 94727b9375ecafde6fc46a74c4b7188bfe63fb2c..03b51025a8f441fdb4258d452f218fd5d05c8ee4 100644 (file)
@@ -1871,4 +1871,4 @@ extern int aac_reset_devices;
 extern int aac_commit;
 extern int update_interval;
 extern int check_interval;
-extern int check_reset;
+extern int aac_check_reset;
index bb870906b4cf72fa15ec8243403bf13812a1c824..240a0bb8986fe3d428c58430234f241bdddd7630 100644 (file)
@@ -1372,8 +1372,9 @@ int aac_check_health(struct aac_dev * aac)
 
        printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
 
-       if (!check_reset || (aac->supplement_adapter_info.SupportedOptions2 &
-         le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
+       if (!aac_check_reset ||
+               (aac->supplement_adapter_info.SupportedOptions2 &
+                       le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
                goto out;
        host = aac->scsi_host_ptr;
        if (aac->thread->pid != current->pid)
index 79c0b6e37a3b92abe629101857f0364a046acfd6..9dd3952516c548c84b61b0754ab406b14ae36dd0 100644 (file)
-#define ASC_VERSION "3.3K"     /* AdvanSys Driver Version */
+#define DRV_NAME "advansys"
+#define ASC_VERSION "3.4"      /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  *
  * Copyright (c) 1995-2000 Advanced System Products, Inc.
  * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
+ * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
  * All Rights Reserved.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
- * changed its name to ConnectCom Solutions, Inc.
- *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  */
 
 /*
-
-  Documentation for the AdvanSys Driver
-
-  A. Linux Kernels Supported by this Driver
-  B. Adapters Supported by this Driver
-  C. Linux source files modified by AdvanSys Driver
-  D. Source Comments
-  E. Driver Compile Time Options and Debugging
-  F. Driver LILO Option
-  G. Tests to run before releasing new driver
-  H. Release History
-  I. Known Problems/Fix List
-  J. Credits (Chronological Order)
-
-  A. Linux Kernels Supported by this Driver
-
-     This driver has been tested in the following Linux kernels: v2.2.18
-     v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
-     alpha, and PowerPC platforms.
-
-  B. Adapters Supported by this Driver
-
-     AdvanSys (Advanced System Products, Inc.) manufactures the following
-     RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
-     (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
-     buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
-     transfer) SCSI Host Adapters for the PCI bus.
-
-     The CDB counts below indicate the number of SCSI CDB (Command
-     Descriptor Block) requests that can be stored in the RISC chip
-     cache and board LRAM. A CDB is a single SCSI command. The driver
-     detect routine will display the number of CDBs available for each
-     adapter detected. The number of CDBs used by the driver can be
-     lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
-
-     Laptop Products:
-        ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
-
-     Connectivity Products:
-        ABP510/5150 - Bus-Master ISA (240 CDB)
-        ABP5140 - Bus-Master ISA PnP (16 CDB)
-        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
-        ABP902/3902 - Bus-Master PCI (16 CDB)
-        ABP3905 - Bus-Master PCI (16 CDB)
-        ABP915 - Bus-Master PCI (16 CDB)
-        ABP920 - Bus-Master PCI (16 CDB)
-        ABP3922 - Bus-Master PCI (16 CDB)
-        ABP3925 - Bus-Master PCI (16 CDB)
-        ABP930 - Bus-Master PCI (16 CDB)
-        ABP930U - Bus-Master PCI Ultra (16 CDB)
-        ABP930UA - Bus-Master PCI Ultra (16 CDB)
-        ABP960 - Bus-Master PCI MAC/PC (16 CDB)
-        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
-
-     Single Channel Products:
-        ABP542 - Bus-Master ISA with floppy (240 CDB)
-        ABP742 - Bus-Master EISA (240 CDB)
-        ABP842 - Bus-Master VL (240 CDB)
-        ABP940 - Bus-Master PCI (240 CDB)
-        ABP940U - Bus-Master PCI Ultra (240 CDB)
-        ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
-        ABP970 - Bus-Master PCI MAC/PC (240 CDB)
-        ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
-        ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
-        ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
-        ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
-        ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
-
-     Multi-Channel Products:
-        ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
-        ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
-        ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
-        ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
-        ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
-        ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
-        ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
-        ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
-        ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
-
-  C. Linux source files modified by AdvanSys Driver
-
-     This section for historical purposes documents the changes
-     originally made to the Linux kernel source to add the advansys
-     driver. As Linux has changed some of these files have also
-     been modified.
-
-     1. linux/arch/i386/config.in:
-
-          bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
-
-     2. linux/drivers/scsi/hosts.c:
-
-          #ifdef CONFIG_SCSI_ADVANSYS
-          #include "advansys.h"
-          #endif
-
-        and after "static struct scsi_host_template builtin_scsi_hosts[] =":
-
-          #ifdef CONFIG_SCSI_ADVANSYS
-          ADVANSYS,
-          #endif
-
-     3. linux/drivers/scsi/Makefile:
-
-          ifdef CONFIG_SCSI_ADVANSYS
-          SCSI_SRCS := $(SCSI_SRCS) advansys.c
-          SCSI_OBJS := $(SCSI_OBJS) advansys.o
-          else
-          SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
-          endif
-
-     4. linux/init/main.c:
-
-          extern void advansys_setup(char *str, int *ints);
-
-        and add the following lines to the bootsetups[] array.
-
-          #ifdef CONFIG_SCSI_ADVANSYS
-             { "advansys=", advansys_setup },
-          #endif
-
-  D. Source Comments
-
-     1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
-
-     2. This driver should be maintained in multiple files. But to make
-        it easier to include with Linux and to follow Linux conventions,
-        the whole driver is maintained in the source files advansys.h and
-        advansys.c. In this file logical sections of the driver begin with
-        a comment that contains '---'. The following are the logical sections
-        of the driver below.
-
-           --- Linux Version
-           --- Linux Include File
-           --- Driver Options
-           --- Debugging Header
-           --- Asc Library Constants and Macros
-           --- Adv Library Constants and Macros
-           --- Driver Constants and Macros
-           --- Driver Structures
-           --- Driver Data
-           --- Driver Function Prototypes
-           --- Linux 'struct scsi_host_template' and advansys_setup() Functions
-           --- Loadable Driver Support
-           --- Miscellaneous Driver Functions
-           --- Functions Required by the Asc Library
-           --- Functions Required by the Adv Library
-           --- Tracing and Debugging Functions
-           --- Asc Library Functions
-           --- Adv Library Functions
-
-     3. The string 'XXX' is used to flag code that needs to be re-written
-        or that contains a problem that needs to be addressed.
-
-     4. I have stripped comments from and reformatted the source for the
-        Asc Library and Adv Library to reduce the size of this file. This
-        source can be found under the following headings. The Asc Library
-        is used to support Narrow Boards. The Adv Library is used to
-        support Wide Boards.
-
-           --- Asc Library Constants and Macros
-           --- Adv Library Constants and Macros
-           --- Asc Library Functions
-           --- Adv Library Functions
-
-  E. Driver Compile Time Options and Debugging
-
-     In this source file the following constants can be defined. They are
-     defined in the source below. Both of these options are enabled by
-     default.
-
-     1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
-
-        Enabling this option adds assertion logic statements to the
-        driver. If an assertion fails a message will be displayed to
-        the console, but the system will continue to operate. Any
-        assertions encountered should be reported to the person
-        responsible for the driver. Assertion statements may proactively
-        detect problems with the driver and facilitate fixing these
-        problems. Enabling assertions will add a small overhead to the
-        execution of the driver.
-
-     2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
-
-        Enabling this option adds tracing functions to the driver and
-        the ability to set a driver tracing level at boot time. This
-        option will also export symbols not required outside the driver to
-        the kernel name space. This option is very useful for debugging
-        the driver, but it will add to the size of the driver execution
-        image and add overhead to the execution of the driver.
-
-        The amount of debugging output can be controlled with the global
-        variable 'asc_dbglvl'. The higher the number the more output. By
-        default the debug level is 0.
-
-        If the driver is loaded at boot time and the LILO Driver Option
-        is included in the system, the debug level can be changed by
-        specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
-        first three hex digits of the pseudo I/O Port must be set to
-        'deb' and the fourth hex digit specifies the debug level: 0 - F.
-        The following command line will look for an adapter at 0x330
-        and set the debug level to 2.
-
-           linux advansys=0x330,0,0,0,0xdeb2
-
-        If the driver is built as a loadable module this variable can be
-        defined when the driver is loaded. The following insmod command
-        will set the debug level to one.
-
-           insmod advansys.o asc_dbglvl=1
-
-        Debugging Message Levels:
-           0: Errors Only
-           1: High-Level Tracing
-           2-N: Verbose Tracing
-
-        To enable debug output to console, please make sure that:
-
-        a. System and kernel logging is enabled (syslogd, klogd running).
-        b. Kernel messages are routed to console output. Check
-           /etc/syslog.conf for an entry similar to this:
-
-                kern.*                  /dev/console
-
-        c. klogd is started with the appropriate -c parameter
-           (e.g. klogd -c 8)
-
-        This will cause printk() messages to be be displayed on the
-        current console. Refer to the klogd(8) and syslogd(8) man pages
-        for details.
-
-        Alternatively you can enable printk() to console with this
-        program. However, this is not the 'official' way to do this.
-        Debug output is logged in /var/log/messages.
-
-          main()
-          {
-                  syscall(103, 7, 0, 0);
-          }
-
-        Increasing LOG_BUF_LEN in kernel/printk.c to something like
-        40960 allows more debug messages to be buffered in the kernel
-        and written to the console or log file.
-
-     3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
-
-        Enabling this option adds statistics collection and display
-        through /proc to the driver. The information is useful for
-        monitoring driver and device performance. It will add to the
-        size of the driver execution image and add minor overhead to
-        the execution of the driver.
-
-        Statistics are maintained on a per adapter basis. Driver entry
-        point call counts and transfer size counts are maintained.
-        Statistics are only available for kernels greater than or equal
-        to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
-
-        AdvanSys SCSI adapter files have the following path name format:
-
-           /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
-
-        This information can be displayed with cat. For example:
-
-           cat /proc/scsi/advansys/0
-
-        When ADVANSYS_STATS is not defined the AdvanSys /proc files only
-        contain adapter and device configuration information.
-
-  F. Driver LILO Option
-
-     If init/main.c is modified as described in the 'Directions for Adding
-     the AdvanSys Driver to Linux' section (B.4.) above, the driver will
-     recognize the 'advansys' LILO command line and /etc/lilo.conf option.
-     This option can be used to either disable I/O port scanning or to limit
-     scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
-     PCI boards will still be searched for and detected. This option only
-     affects searching for ISA and VL boards.
-
-     Examples:
-       1. Eliminate I/O port scanning:
-            boot: linux advansys=
-              or
-            boot: linux advansys=0x0
-       2. Limit I/O port scanning to one I/O port:
-            boot: linux advansys=0x110
-       3. Limit I/O port scanning to four I/O ports:
-            boot: linux advansys=0x110,0x210,0x230,0x330
-
-     For a loadable module the same effect can be achieved by setting
-     the 'asc_iopflag' variable and 'asc_ioport' array when loading
-     the driver, e.g.
-
-           insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
-
-     If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
-     I/O Port may be added to specify the driver debug level. Refer to
-     the 'Driver Compile Time Options and Debugging' section above for
-     more information.
-
-  G. Tests to run before releasing new driver
-
-     1. In the supported kernels verify there are no warning or compile
-        errors when the kernel is built as both a driver and as a module
-        and with the following options:
-
-        ADVANSYS_DEBUG - enabled and disabled
-        CONFIG_SMP - enabled and disabled
-        CONFIG_PROC_FS - enabled and disabled
-
-     2. Run tests on an x86, alpha, and PowerPC with at least one narrow
-        card and one wide card attached to a hard disk and CD-ROM drive:
-        fdisk, mkfs, fsck, bonnie, copy/compare test from the
-        CD-ROM to the hard drive.
-
-  H. Release History
-
-     BETA-1.0 (12/23/95):
-         First Release
-
-     BETA-1.1 (12/28/95):
-         1. Prevent advansys_detect() from being called twice.
-         2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
-
-     1.2 (1/12/96):
-         1. Prevent re-entrancy in the interrupt handler which
-            resulted in the driver hanging Linux.
-         2. Fix problem that prevented ABP-940 cards from being
-            recognized on some PCI motherboards.
-         3. Add support for the ABP-5140 PnP ISA card.
-         4. Fix check condition return status.
-         5. Add conditionally compiled code for Linux v1.3.X.
-
-     1.3 (2/23/96):
-         1. Fix problem in advansys_biosparam() that resulted in the
-            wrong drive geometry being returned for drives > 1GB with
-            extended translation enabled.
-         2. Add additional tracing during device initialization.
-         3. Change code that only applies to ISA PnP adapter.
-         4. Eliminate 'make dep' warning.
-         5. Try to fix problem with handling resets by increasing their
-            timeout value.
-
-     1.4 (5/8/96):
-         1. Change definitions to eliminate conflicts with other subsystems.
-         2. Add versioning code for the shared interrupt changes.
-         3. Eliminate problem in asc_rmqueue() with iterating after removing
-            a request.
-         4. Remove reset request loop problem from the "Known Problems or
-            Issues" section. This problem was isolated and fixed in the
-            mid-level SCSI driver.
-
-     1.5 (8/8/96):
-         1. Add support for ABP-940U (PCI Ultra) adapter.
-         2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
-            request_irq and supplying a dev_id pointer to both request_irq()
-            and free_irq().
-         3. In AscSearchIOPortAddr11() restore a call to check_region() which
-            should be used before I/O port probing.
-         4. Fix bug in asc_prt_hex() which resulted in the displaying
-            the wrong data.
-         5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
-         6. Change driver versioning to be specific to each Linux sub-level.
-         7. Change statistics gathering to be per adapter instead of global
-            to the driver.
-         8. Add more information and statistics to the adapter /proc file:
-            /proc/scsi/advansys[0...].
-         9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
-            This problem has been addressed with the SCSI mid-level changes
-            made in v1.3.89. The advansys_select_queue_depths() function
-            was added for the v1.3.89 changes.
-
-     1.6 (9/10/96):
-         1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
-
-     1.7 (9/25/96):
-         1. Enable clustering and optimize the setting of the maximum number
-            of scatter gather elements for any particular board. Clustering
-            increases CPU utilization, but results in a relatively larger
-            increase in I/O throughput.
-         2. Improve the performance of the request queuing functions by
-            adding a last pointer to the queue structure.
-         3. Correct problems with reset and abort request handling that
-            could have hung or crashed Linux.
-         4. Add more information to the adapter /proc file:
-            /proc/scsi/advansys[0...].
-         5. Remove the request timeout issue form the driver issues list.
-         6. Miscellaneous documentation additions and changes.
-
-     1.8 (10/4/96):
-         1. Make changes to handle the new v2.1.0 kernel memory mapping
-            in which a kernel virtual address may not be equivalent to its
-            bus or DMA memory address.
-         2. Change abort and reset request handling to make it yet even
-            more robust.
-         3. Try to mitigate request starvation by sending ordered requests
-            to heavily loaded, tag queuing enabled devices.
-         4. Maintain statistics on request response time.
-         5. Add request response time statistics and other information to
-            the adapter /proc file: /proc/scsi/advansys[0...].
-
-     1.9 (10/21/96):
-         1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
-            make use of mid-level SCSI driver device queue depth flow
-            control mechanism. This will eliminate aborts caused by a
-            device being unable to keep up with requests and eliminate
-            repeat busy or QUEUE FULL status returned by a device.
-         2. Incorporate miscellaneous Asc Library bug fixes.
-         3. To allow the driver to work in kernels with broken module
-            support set 'cmd_per_lun' if the driver is compiled as a
-            module. This change affects kernels v1.3.89 to present.
-         4. Remove PCI BIOS address from the driver banner. The PCI BIOS
-            is relocated by the motherboard BIOS and its new address can
-            not be determined by the driver.
-         5. Add mid-level SCSI queue depth information to the adapter
-            /proc file: /proc/scsi/advansys[0...].
-
-     2.0 (11/14/96):
-         1. Change allocation of global structures used for device
-            initialization to guarantee they are in DMA-able memory.
-            Previously when the driver was loaded as a module these
-            structures might not have been in DMA-able memory, causing
-            device initialization to fail.
-
-     2.1 (12/30/96):
-         1. In advansys_reset(), if the request is a synchronous reset
-            request, even if the request serial number has changed, then
-            complete the request.
-         2. Add Asc Library bug fixes including new microcode.
-         3. Clear inquiry buffer before using it.
-         4. Correct ifdef typo.
-
-     2.2 (1/15/97):
-         1. Add Asc Library bug fixes including new microcode.
-         2. Add synchronous data transfer rate information to the
-            adapter /proc file: /proc/scsi/advansys[0...].
-         3. Change ADVANSYS_DEBUG to be disabled by default. This
-            will reduce the size of the driver image, eliminate execution
-            overhead, and remove unneeded symbols from the kernel symbol
-            space that were previously added by the driver.
-         4. Add new compile-time option ADVANSYS_ASSERT for assertion
-            code that used to be defined within ADVANSYS_DEBUG. This
-            option is enabled by default.
-
-     2.8 (5/26/97):
-         1. Change version number to 2.8 to synchronize the Linux driver
-            version numbering with other AdvanSys drivers.
-         2. Reformat source files without tabs to present the same view
-            of the file to everyone regardless of the editor tab setting
-            being used.
-         3. Add Asc Library bug fixes.
-
-     3.1A (1/8/98):
-         1. Change version number to 3.1 to indicate that support for
-            Ultra-Wide adapters (ABP-940UW) is included in this release.
-         2. Add Asc Library (Narrow Board) bug fixes.
-         3. Report an underrun condition with the host status byte set
-            to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
-            causes the underrun condition to be ignored. When Linux defines
-            its own DID_UNDERRUN the constant defined in this file can be
-            removed.
-         4. Add patch to AscWaitTixISRDone().
-         5. Add support for up to 16 different AdvanSys host adapter SCSI
-            channels in one system. This allows four cards with four channels
-            to be used in one system.
-
-     3.1B (1/9/98):
-         1. Handle that PCI register base addresses are not always page
-            aligned even though ioremap() requires that the address argument
-            be page aligned.
-
-     3.1C (1/10/98):
-         1. Update latest BIOS version checked for from the /proc file.
-         2. Don't set microcode SDTR variable at initialization. Instead
-            wait until device capabilities have been detected from an Inquiry
-            command.
-
-     3.1D (1/21/98):
-         1. Improve performance when the driver is compiled as module by
-            allowing up to 64 scatter-gather elements instead of 8.
-
-     3.1E (5/1/98):
-         1. Set time delay in AscWaitTixISRDone() to 1000 ms.
-         2. Include SMP locking changes.
-         3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
-            access functions.
-         4. Update board serial number printing.
-         5. Try allocating an IRQ both with and without the IRQF_DISABLED
-            flag set to allow IRQ sharing with drivers that do not set
-            the IRQF_DISABLED flag. Also display a more descriptive error
-            message if request_irq() fails.
-         6. Update to latest Asc and Adv Libraries.
-
-     3.2A (7/22/99):
-         1. Update Adv Library to 4.16 which includes support for
-            the ASC38C0800 (Ultra2/LVD) IC.
-
-     3.2B (8/23/99):
-         1. Correct PCI compile time option for v2.1.93 and greater
-            kernels, advansys_info() string, and debug compile time
-            option.
-         2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
-            kernels. This caused an LVD detection/BIST problem problem
-            among other things.
-         3. Sort PCI cards by PCI Bus, Slot, Function ascending order
-            to be consistent with the BIOS.
-         4. Update to Asc Library S121 and Adv Library 5.2.
-
-     3.2C (8/24/99):
-         1. Correct PCI card detection bug introduced in 3.2B that
-            prevented PCI cards from being detected in kernels older
-            than v2.1.93.
-
-     3.2D (8/26/99):
-         1. Correct /proc device synchronous speed information display.
-            Also when re-negotiation is pending for a target device
-            note this condition with an * and footnote.
-         2. Correct initialization problem with Ultra-Wide cards that
-            have a pre-3.2 BIOS. A microcode variable changed locations
-            in 3.2 and greater BIOSes which caused WDTR to be attempted
-            erroneously with drives that don't support WDTR.
-
-     3.2E (8/30/99):
-         1. Fix compile error caused by v2.3.13 PCI structure change.
-         2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
-            checksum error for ISA cards.
-         3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
-            SCSI changes that it depended on were never included in Linux.
-
-     3.2F (9/3/99):
-         1. Handle new initial function code added in v2.3.16 for all
-            driver versions.
-
-     3.2G (9/8/99):
-         1. Fix PCI board detection in v2.3.13 and greater kernels.
-         2. Fix comiple errors in v2.3.X with debugging enabled.
-
-     3.2H (9/13/99):
-         1. Add 64-bit address, long support for Alpha and UltraSPARC.
-            The driver has been verified to work on an Alpha system.
-         2. Add partial byte order handling support for Power PC and
-            other big-endian platforms. This support has not yet been
-            completed or verified.
-         3. For wide boards replace block zeroing of request and
-            scatter-gather structures with individual field initialization
-            to improve performance.
-         4. Correct and clarify ROM BIOS version detection.
-
-     3.2I (10/8/99):
-         1. Update to Adv Library 5.4.
-         2. Add v2.3.19 underrun reporting to asc_isr_callback() and
-            adv_isr_callback().  Remove DID_UNDERRUN constant and other
-            no longer needed code that previously documented the lack
-            of underrun handling.
-
-     3.2J (10/14/99):
-         1. Eliminate compile errors for v2.0 and earlier kernels.
-
-     3.2K (11/15/99):
-         1. Correct debug compile error in asc_prt_adv_scsi_req_q().
-         2. Update Adv Library to 5.5.
-         3. Add ifdef handling for /proc changes added in v2.3.28.
-         4. Increase Wide board scatter-gather list maximum length to
-            255 when the driver is compiled into the kernel.
-
-     3.2L (11/18/99):
-         1. Fix bug in adv_get_sglist() that caused an assertion failure
-            at line 7475. The reqp->sgblkp pointer must be initialized
-            to NULL in adv_get_sglist().
-
-     3.2M (11/29/99):
-         1. Really fix bug in adv_get_sglist().
-         2. Incorporate v2.3.29 changes into driver.
-
-     3.2N (4/1/00):
-         1. Add CONFIG_ISA ifdef code.
-         2. Include advansys_interrupts_enabled name change patch.
-         3. For >= v2.3.28 use new SCSI error handling with new function
-            advansys_eh_bus_reset(). Don't include an abort function
-            because of base library limitations.
-         4. For >= v2.3.28 use per board lock instead of io_request_lock.
-         5. For >= v2.3.28 eliminate advansys_command() and
-            advansys_command_done().
-         6. Add some changes for PowerPC (Big Endian) support, but it isn't
-            working yet.
-         7. Fix "nonexistent resource free" problem that occurred on a module
-            unload for boards with an I/O space >= 255. The 'n_io_port' field
-            is only one byte and can not be used to hold an ioport length more
-            than 255.
-
-     3.3A (4/4/00):
-         1. Update to Adv Library 5.8.
-         2. For wide cards add support for CDBs up to 16 bytes.
-         3. Eliminate warnings when CONFIG_PROC_FS is not defined.
-
-     3.3B (5/1/00):
-         1. Support for PowerPC (Big Endian) wide cards. Narrow cards
-            still need work.
-         2. Change bitfields to shift and mask access for endian
-            portability.
-
-     3.3C (10/13/00):
-         1. Update for latest 2.4 kernel.
-         2. Test ABP-480 CardBus support in 2.4 kernel - works!
-         3. Update to Asc Library S123.
-         4. Update to Adv Library 5.12.
-
-     3.3D (11/22/00):
-         1. Update for latest 2.4 kernel.
-         2. Create patches for 2.2 and 2.4 kernels.
-
-     3.3E (1/9/01):
-         1. Now that 2.4 is released remove ifdef code for kernel versions
-            less than 2.2. The driver is now only supported in kernels 2.2,
-            2.4, and greater.
-         2. Add code to release and acquire the io_request_lock in
-            the driver entrypoint functions: advansys_detect and
-            advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
-            still holds the io_request_lock on entry to SCSI low-level drivers.
-            This was supposed to be removed before 2.4 was released but never
-            happened. When the mid-level SCSI driver is changed all references
-            to the io_request_lock should be removed from the driver.
-         3. Simplify error handling by removing advansys_abort(),
-            AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
-            now handled by resetting the SCSI bus and fully re-initializing
-            the chip. This simple method of error recovery has proven to work
-            most reliably after attempts at different methods. Also now only
-            support the "new" error handling method and remove the obsolete
-            error handling interface.
-         4. Fix debug build errors.
-
-     3.3F (1/24/01):
-         1. Merge with ConnectCom version from Andy Kellner which
-            updates Adv Library to 5.14.
-         2. Make PowerPC (Big Endian) work for narrow cards and
-            fix problems writing EEPROM for wide cards.
-         3. Remove interrupts_enabled assertion function.
-
-     3.3G (2/16/01):
-         1. Return an error from narrow boards if passed a 16 byte
-            CDB. The wide board can already handle 16 byte CDBs.
-
-     3.3GJ (4/15/02):
-        1. hacks for lk 2.5 series (D. Gilbert)
-
-     3.3GJD (10/14/02):
-         1. change select_queue_depths to slave_configure
-        2. make cmd_per_lun be sane again
-
-     3.3K [2004/06/24]:
-         1. continuing cleanup for lk 2.6 series
-         2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
-         3. Fix problem that oopsed ISA cards
-
-  I. Known Problems/Fix List (XXX)
-
-     1. Need to add memory mapping workaround. Test the memory mapping.
-        If it doesn't work revert to I/O port access. Can a test be done
-        safely?
-     2. Handle an interrupt not working. Keep an interrupt counter in
-        the interrupt handler. In the timeout function if the interrupt
-        has not occurred then print a message and run in polled mode.
-     3. Allow bus type scanning order to be changed.
-     4. Need to add support for target mode commands, cf. CAM XPT.
-
-  J. Credits (Chronological Order)
-
-     Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
-     and maintained it up to 3.3F. He continues to answer questions
-     and help maintain the driver.
-
-     Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
-     basis for the Linux v1.3.X changes which were included in the
-     1.2 release.
-
-     Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
-     in advansys_biosparam() which was fixed in the 1.3 release.
-
-     Erik Ratcliffe <erik@caldera.com> has done testing of the
-     AdvanSys driver in the Caldera releases.
-
-     Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
-     AscWaitTixISRDone() which he found necessary to make the
-     driver work with a SCSI-1 disk.
-
-     Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
-     support in the 3.1A driver.
-
-     Doug Gilbert <dgilbert@interlog.com> has made changes and
-     suggestions to improve the driver and done a lot of testing.
-
-     Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
-     in 3.2K.
-
-     Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
-     patch and helped with PowerPC wide and narrow board support.
-
-     Philip Blundell <philb@gnu.org> provided an
-     advansys_interrupts_enabled patch.
-
-     Dave Jones <dave@denial.force9.co.uk> reported the compiler
-     warnings generated when CONFIG_PROC_FS was not defined in
-     the 3.2M driver.
-
-     Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
-     problems) for wide cards.
-
-     Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
-     card error handling.
-
-     Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
-     board support and fixed a bug in AscGetEEPConfig().
-
-     Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
-     save_flags/restore_flags changes.
-
-     Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
-     driver development for ConnectCom (Version > 3.3F).
-
-  K. ConnectCom (AdvanSys) Contact Information
-
-     Mail:                   ConnectCom Solutions, Inc.
-                             1150 Ringwood Court
-                             San Jose, CA 95131
-     Operator/Sales:         1-408-383-9400
-     FAX:                    1-408-383-9612
-     Tech Support:           1-408-467-2930
-     Tech Support E-Mail:    linux@connectcom.net
-     FTP Site:               ftp.connectcom.net (login: anonymous)
-     Web Site:               http://www.connectcom.net
-
-*/
-
-/*
- * --- Linux Include Files
+ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
+ * changed its name to ConnectCom Solutions, Inc.
+ * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
  */
 
 #include <linux/module.h>
-
-#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
-#define CONFIG_ISA
-#endif /* CONFIG_X86 && !CONFIG_ISA */
-
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
-#include <linux/stat.h>
+#include <linux/isa.h>
+#include <linux/eisa.h>
+#include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/system.h>
 #include <asm/dma.h>
 
-/* FIXME: (by jejb@steeleye.com) This warning is present for two
- * reasons:
- *
- * 1) This driver badly needs converting to the correct driver model
- *    probing API
- *
- * 2) Although all of the necessary command mapping places have the
- * appropriate dma_map.. APIs, the driver still processes its internal
- * queue using bus_to_virt() and virt_to_bus() which are illegal under
- * the API.  The entire queue processing structure will need to be
- * altered to fix this.
- */
-#warning this driver is still not properly converted to the DMA API
-
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif /* CONFIG_PCI */
 
-/*
- * --- Driver Options
+/* FIXME:
+ *
+ *  1. Although all of the necessary command mapping places have the
+ *     appropriate dma_map.. APIs, the driver still processes its internal
+ *     queue using bus_to_virt() and virt_to_bus() which are illegal under
+ *     the API.  The entire queue processing structure will need to be
+ *     altered to fix this.
+ *  2. Need to add memory mapping workaround. Test the memory mapping.
+ *     If it doesn't work revert to I/O port access. Can a test be done
+ *     safely?
+ *  3. Handle an interrupt not working. Keep an interrupt counter in
+ *     the interrupt handler. In the timeout function if the interrupt
+ *     has not occurred then print a message and run in polled mode.
+ *  4. Need to add support for target mode commands, cf. CAM XPT.
+ *  5. check DMA mapping functions for failure
+ *  6. Use scsi_transport_spi
+ *  7. advansys_info is not safe against multiple simultaneous callers
+ *  8. Add module_param to override ISA/VLB ioport array
  */
-
-/* Enable driver assertions. */
-#define ADVANSYS_ASSERT
+#warning this driver is still not properly converted to the DMA API
 
 /* Enable driver /proc statistics. */
 #define ADVANSYS_STATS
 
 /* Enable driver tracing. */
-/* #define ADVANSYS_DEBUG */
-
-/*
- * --- Asc Library Constants and Macros
- */
-
-#define ASC_LIB_VERSION_MAJOR  1
-#define ASC_LIB_VERSION_MINOR  24
-#define ASC_LIB_SERIAL_NUMBER  123
+#undef ADVANSYS_DEBUG
 
 /*
  * Portable Data Types
 #define ASC_DCNT  __u32                /* Unsigned Data count type. */
 #define ASC_SDCNT __s32                /* Signed Data count type. */
 
-/*
- * These macros are used to convert a virtual address to a
- * 32-bit value. This currently can be used on Linux Alpha
- * which uses 64-bit virtual address but a 32-bit bus address.
- * This is likely to break in the future, but doing this now
- * will give us time to change the HW and FW to handle 64-bit
- * addresses.
- */
-#define ASC_VADDR_TO_U32   virt_to_bus
-#define ASC_U32_TO_VADDR   bus_to_virt
-
 typedef unsigned char uchar;
 
 #ifndef TRUE
@@ -857,29 +99,9 @@ typedef unsigned char uchar;
 #define FALSE    (0)
 #endif
 
-#define EOF      (-1)
 #define ERR      (-1)
 #define UW_ERR   (uint)(0xFFFF)
 #define isodd_word(val)   ((((uint)val) & (uint)0x0001) != 0)
-#define AscPCIConfigVendorIDRegister      0x0000
-#define AscPCIConfigDeviceIDRegister      0x0002
-#define AscPCIConfigCommandRegister       0x0004
-#define AscPCIConfigStatusRegister        0x0006
-#define AscPCIConfigRevisionIDRegister    0x0008
-#define AscPCIConfigCacheSize             0x000C
-#define AscPCIConfigLatencyTimer          0x000D
-#define AscPCIIOBaseRegister              0x0010
-#define AscPCICmdRegBits_IOMemBusMaster   0x0007
-#define ASC_PCI_ID2BUS(id)    ((id) & 0xFF)
-#define ASC_PCI_ID2DEV(id)    (((id) >> 11) & 0x1F)
-#define ASC_PCI_ID2FUNC(id)   (((id) >> 8) & 0x7)
-#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
-#define ASC_PCI_REVISION_3150             0x02
-#define ASC_PCI_REVISION_3050             0x03
-
-#define  ASC_DVCLIB_CALL_DONE     (1)
-#define  ASC_DVCLIB_CALL_FAILED   (0)
-#define  ASC_DVCLIB_CALL_ERROR    (-1)
 
 #define PCI_VENDOR_ID_ASP              0x10cd
 #define PCI_DEVICE_ID_ASP_1200A                0x1100
@@ -898,7 +120,7 @@ typedef unsigned char uchar;
 #define CC_VERY_LONG_SG_LIST 0
 #define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
 
-#define PortAddr                 unsigned short        /* port address size  */
+#define PortAddr                 unsigned int  /* port address size  */
 #define inp(port)                inb(port)
 #define outp(port, byte)         outb((byte), (port))
 
@@ -918,11 +140,10 @@ typedef unsigned char uchar;
 #define ASC_IS_PCMCIA       (0x0008)
 #define ASC_IS_MCA          (0x0020)
 #define ASC_IS_VL           (0x0040)
-#define ASC_ISA_PNP_PORT_ADDR  (0x279)
-#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
 #define ASC_IS_WIDESCSI_16  (0x0100)
 #define ASC_IS_WIDESCSI_32  (0x0200)
 #define ASC_IS_BIG_ENDIAN   (0x8000)
+
 #define ASC_CHIP_MIN_VER_VL      (0x01)
 #define ASC_CHIP_MAX_VER_VL      (0x07)
 #define ASC_CHIP_MIN_VER_PCI     (0x09)
@@ -941,16 +162,9 @@ typedef unsigned char uchar;
 #define ASC_CHIP_MAX_VER_EISA (0x47)
 #define ASC_CHIP_VER_EISA_BIT (0x40)
 #define ASC_CHIP_LATEST_VER_EISA   ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
-#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER   0x21
-#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER   0x0A
-#define ASC_MAX_VL_DMA_ADDR     (0x07FFFFFFL)
 #define ASC_MAX_VL_DMA_COUNT    (0x07FFFFFFL)
-#define ASC_MAX_PCI_DMA_ADDR    (0xFFFFFFFFL)
 #define ASC_MAX_PCI_DMA_COUNT   (0xFFFFFFFFL)
-#define ASC_MAX_ISA_DMA_ADDR    (0x00FFFFFFL)
 #define ASC_MAX_ISA_DMA_COUNT   (0x00FFFFFFL)
-#define ASC_MAX_EISA_DMA_ADDR   (0x07FFFFFFL)
-#define ASC_MAX_EISA_DMA_COUNT  (0x07FFFFFFL)
 
 #define ASC_SCSI_ID_BITS  3
 #define ASC_SCSI_TIX_TYPE     uchar
@@ -961,82 +175,17 @@ typedef unsigned char uchar;
 #define ASC_SCSI_WIDTH_BIT_SET  0xFF
 #define ASC_MAX_SENSE_LEN   32
 #define ASC_MIN_SENSE_LEN   14
-#define ASC_MAX_CDB_LEN     12
 #define ASC_SCSI_RESET_HOLD_TIME_US  60
 
-#define ADV_INQ_CLOCKING_ST_ONLY    0x0
-#define ADV_INQ_CLOCKING_DT_ONLY    0x1
-#define ADV_INQ_CLOCKING_ST_AND_DT  0x3
-
 /*
- * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
- * and CmdDt (Command Support Data) field bit definitions.
+ * Narrow boards only support 12-byte commands, while wide boards
+ * extend to 16-byte commands.
  */
-#define ADV_INQ_RTN_VPD_AND_CMDDT           0x3
-#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE       0x2
-#define ADV_INQ_RTN_VPD_FOR_PG_CODE         0x1
-#define ADV_INQ_RTN_STD_INQUIRY_DATA        0x0
-
-#define ASC_SCSIDIR_NOCHK    0x00
-#define ASC_SCSIDIR_T2H      0x08
-#define ASC_SCSIDIR_H2T      0x10
-#define ASC_SCSIDIR_NODATA   0x18
-#define SCSI_ASC_NOMEDIA          0x3A
-#define ASC_SRB_HOST(x)  ((uchar)((uchar)(x) >> 4))
-#define ASC_SRB_TID(x)   ((uchar)((uchar)(x) & (uchar)0x0F))
-#define ASC_SRB_LUN(x)   ((uchar)((uint)(x) >> 13))
-#define PUT_CDB1(x)   ((uchar)((uint)(x) >> 8))
-#define MS_CMD_DONE    0x00
-#define MS_EXTEND      0x01
+#define ASC_MAX_CDB_LEN     12
+#define ADV_MAX_CDB_LEN     16
+
 #define MS_SDTR_LEN    0x03
-#define MS_SDTR_CODE   0x01
 #define MS_WDTR_LEN    0x02
-#define MS_WDTR_CODE   0x03
-#define MS_MDP_LEN    0x05
-#define MS_MDP_CODE   0x00
-
-/*
- * Inquiry data structure and bitfield macros
- *
- * Only quantities of more than 1 bit are shifted, since the others are
- * just tested for true or false. C bitfields aren't portable between big
- * and little-endian platforms so they are not used.
- */
-
-#define ASC_INQ_DVC_TYPE(inq)       ((inq)->periph & 0x1f)
-#define ASC_INQ_QUALIFIER(inq)      (((inq)->periph & 0xe0) >> 5)
-#define ASC_INQ_DVC_TYPE_MOD(inq)   ((inq)->devtype & 0x7f)
-#define ASC_INQ_REMOVABLE(inq)      ((inq)->devtype & 0x80)
-#define ASC_INQ_ANSI_VER(inq)       ((inq)->ver & 0x07)
-#define ASC_INQ_ECMA_VER(inq)       (((inq)->ver & 0x38) >> 3)
-#define ASC_INQ_ISO_VER(inq)        (((inq)->ver & 0xc0) >> 6)
-#define ASC_INQ_RESPONSE_FMT(inq)   ((inq)->byte3 & 0x0f)
-#define ASC_INQ_TERM_IO(inq)        ((inq)->byte3 & 0x40)
-#define ASC_INQ_ASYNC_NOTIF(inq)    ((inq)->byte3 & 0x80)
-#define ASC_INQ_SOFT_RESET(inq)     ((inq)->flags & 0x01)
-#define ASC_INQ_CMD_QUEUE(inq)      ((inq)->flags & 0x02)
-#define ASC_INQ_LINK_CMD(inq)       ((inq)->flags & 0x08)
-#define ASC_INQ_SYNC(inq)           ((inq)->flags & 0x10)
-#define ASC_INQ_WIDE16(inq)         ((inq)->flags & 0x20)
-#define ASC_INQ_WIDE32(inq)         ((inq)->flags & 0x40)
-#define ASC_INQ_REL_ADDR(inq)       ((inq)->flags & 0x80)
-#define ASC_INQ_INFO_UNIT(inq)      ((inq)->info & 0x01)
-#define ASC_INQ_QUICK_ARB(inq)      ((inq)->info & 0x02)
-#define ASC_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
-
-typedef struct {
-       uchar periph;
-       uchar devtype;
-       uchar ver;
-       uchar byte3;
-       uchar add_len;
-       uchar res1;
-       uchar res2;
-       uchar flags;
-       uchar vendor_id[8];
-       uchar product_id[16];
-       uchar product_rev_level[4];
-} ASC_SCSI_INQUIRY;
 
 #define ASC_SG_LIST_PER_Q   7
 #define QS_FREE        0x00
@@ -1215,22 +364,9 @@ typedef struct asc_sg_head {
        ushort queue_cnt;
        ushort entry_to_copy;
        ushort res;
-       ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
+       ASC_SG_LIST sg_list[0];
 } ASC_SG_HEAD;
 
-#define ASC_MIN_SG_LIST   2
-
-typedef struct asc_min_sg_head {
-       ushort entry_cnt;
-       ushort queue_cnt;
-       ushort entry_to_copy;
-       ushort res;
-       ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
-} ASC_MIN_SG_HEAD;
-
-#define QCX_SORT        (0x0001)
-#define QCX_COALEASE    (0x0002)
-
 typedef struct asc_scsi_q {
        ASC_SCSIQ_1 q1;
        ASC_SCSIQ_2 q2;
@@ -1287,45 +423,12 @@ typedef struct asc_risc_sg_list_q {
        ASC_SG_LIST sg_list[7];
 } ASC_RISC_SG_LIST_Q;
 
-#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP  0x1000000UL
-#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP  1024
-#define ASCQ_ERR_NO_ERROR             0
-#define ASCQ_ERR_IO_NOT_FOUND         1
-#define ASCQ_ERR_LOCAL_MEM            2
-#define ASCQ_ERR_CHKSUM               3
-#define ASCQ_ERR_START_CHIP           4
-#define ASCQ_ERR_INT_TARGET_ID        5
-#define ASCQ_ERR_INT_LOCAL_MEM        6
-#define ASCQ_ERR_HALT_RISC            7
-#define ASCQ_ERR_GET_ASPI_ENTRY       8
-#define ASCQ_ERR_CLOSE_ASPI           9
-#define ASCQ_ERR_HOST_INQUIRY         0x0A
-#define ASCQ_ERR_SAVED_SRB_BAD        0x0B
-#define ASCQ_ERR_QCNTL_SG_LIST        0x0C
 #define ASCQ_ERR_Q_STATUS             0x0D
-#define ASCQ_ERR_WR_SCSIQ             0x0E
-#define ASCQ_ERR_PC_ADDR              0x0F
-#define ASCQ_ERR_SYN_OFFSET           0x10
-#define ASCQ_ERR_SYN_XFER_TIME        0x11
-#define ASCQ_ERR_LOCK_DMA             0x12
-#define ASCQ_ERR_UNLOCK_DMA           0x13
-#define ASCQ_ERR_VDS_CHK_INSTALL      0x14
-#define ASCQ_ERR_MICRO_CODE_HALT      0x15
-#define ASCQ_ERR_SET_LRAM_ADDR        0x16
 #define ASCQ_ERR_CUR_QNG              0x17
 #define ASCQ_ERR_SG_Q_LINKS           0x18
-#define ASCQ_ERR_SCSIQ_PTR            0x19
 #define ASCQ_ERR_ISR_RE_ENTRY         0x1A
 #define ASCQ_ERR_CRITICAL_RE_ENTRY    0x1B
 #define ASCQ_ERR_ISR_ON_CRITICAL      0x1C
-#define ASCQ_ERR_SG_LIST_ODD_ADDRESS  0x1D
-#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
-#define ASCQ_ERR_SCSIQ_NULL_PTR       0x1F
-#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR   0x20
-#define ASCQ_ERR_GET_NUM_OF_FREE_Q    0x21
-#define ASCQ_ERR_SEND_SCSI_Q          0x22
-#define ASCQ_ERR_HOST_REQ_RISC_HALT   0x23
-#define ASCQ_ERR_RESET_SDTR           0x24
 
 /*
  * Warning code values are set in ASC_DVC_VAR  'warn_code'.
@@ -1338,84 +441,51 @@ typedef struct asc_risc_sg_list_q {
 #define ASC_WARN_CMD_QNG_CONFLICT     0x0010
 #define ASC_WARN_EEPROM_RECOVER       0x0020
 #define ASC_WARN_CFG_MSW_RECOVER      0x0040
-#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
 
 /*
- * Error code values are set in ASC_DVC_VAR  'err_code'.
+ * Error code values are set in {ASC/ADV}_DVC_VAR  'err_code'.
  */
-#define ASC_IERR_WRITE_EEPROM         0x0001
-#define ASC_IERR_MCODE_CHKSUM         0x0002
-#define ASC_IERR_SET_PC_ADDR          0x0004
-#define ASC_IERR_START_STOP_CHIP      0x0008
-#define ASC_IERR_IRQ_NO               0x0010
-#define ASC_IERR_SET_IRQ_NO           0x0020
-#define ASC_IERR_CHIP_VERSION         0x0040
-#define ASC_IERR_SET_SCSI_ID          0x0080
-#define ASC_IERR_GET_PHY_ADDR         0x0100
-#define ASC_IERR_BAD_SIGNATURE        0x0200
-#define ASC_IERR_NO_BUS_TYPE          0x0400
-#define ASC_IERR_SCAM                 0x0800
-#define ASC_IERR_SET_SDTR             0x1000
-#define ASC_IERR_RW_LRAM              0x8000
-
-#define ASC_DEF_IRQ_NO  10
-#define ASC_MAX_IRQ_NO  15
-#define ASC_MIN_IRQ_NO  10
-#define ASC_MIN_REMAIN_Q        (0x02)
+#define ASC_IERR_NO_CARRIER            0x0001  /* No more carrier memory */
+#define ASC_IERR_MCODE_CHKSUM          0x0002  /* micro code check sum error */
+#define ASC_IERR_SET_PC_ADDR           0x0004
+#define ASC_IERR_START_STOP_CHIP       0x0008  /* start/stop chip failed */
+#define ASC_IERR_ILLEGAL_CONNECTION    0x0010  /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE     0x0020  /* SE device on DIFF bus */
+#define ASC_IERR_REVERSED_CABLE                0x0040  /* Narrow flat cable reversed */
+#define ASC_IERR_SET_SCSI_ID           0x0080  /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE            0x0100  /* HVD device on LVD port */
+#define ASC_IERR_BAD_SIGNATURE         0x0200  /* signature not found */
+#define ASC_IERR_NO_BUS_TYPE           0x0400
+#define ASC_IERR_BIST_PRE_TEST         0x0800  /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST         0x1000  /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE          0x2000  /* Invalid chip_type setting */
+
 #define ASC_DEF_MAX_TOTAL_QNG   (0xF0)
 #define ASC_MIN_TAG_Q_PER_DVC   (0x04)
-#define ASC_DEF_TAG_Q_PER_DVC   (0x04)
-#define ASC_MIN_FREE_Q        ASC_MIN_REMAIN_Q
+#define ASC_MIN_FREE_Q        (0x02)
 #define ASC_MIN_TOTAL_QNG     ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
 #define ASC_MAX_TOTAL_QNG 240
 #define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
 #define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG   8
 #define ASC_MAX_PCI_INRAM_TOTAL_QNG  20
 #define ASC_MAX_INRAM_TAG_QNG   16
-#define ASC_IOADR_TABLE_MAX_IX  11
 #define ASC_IOADR_GAP   0x10
-#define ASC_SEARCH_IOP_GAP 0x10
-#define ASC_MIN_IOP_ADDR   (PortAddr)0x0100
-#define ASC_MAX_IOP_ADDR   (PortAddr)0x3F0
-#define ASC_IOADR_1     (PortAddr)0x0110
-#define ASC_IOADR_2     (PortAddr)0x0130
-#define ASC_IOADR_3     (PortAddr)0x0150
-#define ASC_IOADR_4     (PortAddr)0x0190
-#define ASC_IOADR_5     (PortAddr)0x0210
-#define ASC_IOADR_6     (PortAddr)0x0230
-#define ASC_IOADR_7     (PortAddr)0x0250
-#define ASC_IOADR_8     (PortAddr)0x0330
-#define ASC_IOADR_DEF   ASC_IOADR_8
-#define ASC_LIB_SCSIQ_WK_SP        256
-#define ASC_MAX_SYN_XFER_NO        16
 #define ASC_SYN_MAX_OFFSET         0x0F
 #define ASC_DEF_SDTR_OFFSET        0x0F
-#define ASC_DEF_SDTR_INDEX         0x00
 #define ASC_SDTR_ULTRA_PCI_10MB_INDEX  0x02
-#define SYN_XFER_NS_0  25
-#define SYN_XFER_NS_1  30
-#define SYN_XFER_NS_2  35
-#define SYN_XFER_NS_3  40
-#define SYN_XFER_NS_4  50
-#define SYN_XFER_NS_5  60
-#define SYN_XFER_NS_6  70
-#define SYN_XFER_NS_7  85
-#define SYN_ULTRA_XFER_NS_0    12
-#define SYN_ULTRA_XFER_NS_1    19
-#define SYN_ULTRA_XFER_NS_2    25
-#define SYN_ULTRA_XFER_NS_3    32
-#define SYN_ULTRA_XFER_NS_4    38
-#define SYN_ULTRA_XFER_NS_5    44
-#define SYN_ULTRA_XFER_NS_6    50
-#define SYN_ULTRA_XFER_NS_7    57
-#define SYN_ULTRA_XFER_NS_8    63
-#define SYN_ULTRA_XFER_NS_9    69
-#define SYN_ULTRA_XFER_NS_10   75
-#define SYN_ULTRA_XFER_NS_11   82
-#define SYN_ULTRA_XFER_NS_12   88
-#define SYN_ULTRA_XFER_NS_13   94
-#define SYN_ULTRA_XFER_NS_14  100
-#define SYN_ULTRA_XFER_NS_15  107
+#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
+
+/* The narrow chip only supports a limited selection of transfer rates.
+ * These are encoded in the range 0..7 or 0..15 depending whether the chip
+ * is Ultra-capable or not.  These tables let us convert from one to the other.
+ */
+static const unsigned char asc_syn_xfer_period[8] = {
+       25, 30, 35, 40, 50, 60, 70, 85
+};
+
+static const unsigned char asc_syn_ultra_xfer_period[16] = {
+       12, 19, 25, 32, 38, 44, 50, 57, 63, 69, 75, 82, 88, 94, 100, 107
+};
 
 typedef struct ext_msg {
        uchar msg_type;
@@ -1456,22 +526,16 @@ typedef struct asc_dvc_cfg {
        uchar isa_dma_speed;
        uchar isa_dma_channel;
        uchar chip_version;
-       ushort lib_serial_no;
-       ushort lib_version;
        ushort mcode_date;
        ushort mcode_version;
        uchar max_tag_qng[ASC_MAX_TID + 1];
-       uchar *overrun_buf;
        uchar sdtr_period_offset[ASC_MAX_TID + 1];
-       ushort pci_slot_info;
        uchar adapter_info[6];
-       struct device *dev;
 } ASC_DVC_CFG;
 
 #define ASC_DEF_DVC_CNTL       0xFFFF
 #define ASC_DEF_CHIP_SCSI_ID   7
 #define ASC_DEF_ISA_DMA_SPEED  4
-#define ASC_INIT_STATE_NULL          0x0000
 #define ASC_INIT_STATE_BEG_GET_CFG   0x0001
 #define ASC_INIT_STATE_END_GET_CFG   0x0002
 #define ASC_INIT_STATE_BEG_SET_CFG   0x0004
@@ -1484,43 +548,39 @@ typedef struct asc_dvc_cfg {
 #define ASC_INIT_STATE_WITHOUT_EEP   0x8000
 #define ASC_BUG_FIX_IF_NOT_DWB       0x0001
 #define ASC_BUG_FIX_ASYN_USE_SYN     0x0002
-#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
 #define ASC_MIN_TAGGED_CMD  7
 #define ASC_MAX_SCSI_RESET_WAIT      30
+#define ASC_OVERRUN_BSIZE              64
 
 struct asc_dvc_var;            /* Forward Declaration. */
 
-typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
-typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
-
 typedef struct asc_dvc_var {
        PortAddr iop_base;
        ushort err_code;
        ushort dvc_cntl;
        ushort bug_fix_cntl;
        ushort bus_type;
-       ASC_ISR_CALLBACK isr_callback;
-       ASC_EXE_CALLBACK exe_callback;
        ASC_SCSI_BIT_ID_TYPE init_sdtr;
        ASC_SCSI_BIT_ID_TYPE sdtr_done;
        ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
        ASC_SCSI_BIT_ID_TYPE unit_not_ready;
        ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
        ASC_SCSI_BIT_ID_TYPE start_motor;
+       uchar overrun_buf[ASC_OVERRUN_BSIZE] __aligned(8);
+       dma_addr_t overrun_dma;
        uchar scsi_reset_wait;
        uchar chip_no;
        char is_in_int;
        uchar max_total_qng;
        uchar cur_total_qng;
        uchar in_critical_cnt;
-       uchar irq_no;
        uchar last_q_shortage;
        ushort init_state;
        uchar cur_dvc_qng[ASC_MAX_TID + 1];
        uchar max_dvc_qng[ASC_MAX_TID + 1];
        ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
        ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
-       uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
+       const uchar *sdtr_period_tbl;
        ASC_DVC_CFG *cfg;
        ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
        char redo_scam;
@@ -1529,9 +589,11 @@ typedef struct asc_dvc_var {
        ASC_DCNT max_dma_count;
        ASC_SCSI_BIT_ID_TYPE no_scam;
        ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+       uchar min_sdtr_index;
        uchar max_sdtr_index;
-       uchar host_init_sdtr_index;
        struct asc_board *drv_ptr;
+       int ptr_map_count;
+       void **ptr_map;
        ASC_DCNT uc_break;
 } ASC_DVC_VAR;
 
@@ -1568,12 +630,7 @@ typedef struct asc_cap_info_array {
 #define ASC_EEP_MAX_DVC_ADDR_VL   15
 #define ASC_EEP_DVC_CFG_BEG      32
 #define ASC_EEP_MAX_DVC_ADDR     45
-#define ASC_EEP_DEFINED_WORDS    10
-#define ASC_EEP_MAX_ADDR         63
-#define ASC_EEP_RES_WORDS         0
 #define ASC_EEP_MAX_RETRY        20
-#define ASC_MAX_INIT_BUSY_RETRY   8
-#define ASC_EEP_ISA_PNP_WSIZE    16
 
 /*
  * These macros keep the chip SCSI id and ISA DMA speed
@@ -1609,17 +666,10 @@ typedef struct asceep_config {
        ushort chksum;
 } ASCEEP_CONFIG;
 
-#define ASC_PCI_CFG_LSW_SCSI_PARITY  0x0800
-#define ASC_PCI_CFG_LSW_BURST_MODE   0x0080
-#define ASC_PCI_CFG_LSW_INTR_ABLE    0x0020
-
 #define ASC_EEP_CMD_READ          0x80
 #define ASC_EEP_CMD_WRITE         0x40
 #define ASC_EEP_CMD_WRITE_ABLE    0x30
 #define ASC_EEP_CMD_WRITE_DISABLE 0x00
-#define ASC_OVERRUN_BSIZE  0x00000048UL
-#define ASC_CTRL_BREAK_ONCE        0x0001
-#define ASC_CTRL_BREAK_STAY_IDLE   0x0002
 #define ASCV_MSGOUT_BEG         0x0000
 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
 #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
@@ -1796,16 +846,9 @@ typedef struct asceep_config {
 #define ASC_1000_ID0W      0x04C1
 #define ASC_1000_ID0W_FIX  0x00C1
 #define ASC_1000_ID1B      0x25
-#define ASC_EISA_BIG_IOP_GAP   (0x1C30-0x0C50)
-#define ASC_EISA_SMALL_IOP_GAP (0x0020)
-#define ASC_EISA_MIN_IOP_ADDR  (0x0C30)
-#define ASC_EISA_MAX_IOP_ADDR  (0xFC50)
 #define ASC_EISA_REV_IOP_MASK  (0x0C83)
-#define ASC_EISA_PID_IOP_MASK  (0x0C80)
 #define ASC_EISA_CFG_IOP_MASK  (0x0C86)
 #define ASC_GET_EISA_SLOT(iop)  (PortAddr)((iop) & 0xF000)
-#define ASC_EISA_ID_740    0x01745004UL
-#define ASC_EISA_ID_750    0x01755004UL
 #define INS_HALTINT        (ushort)0x6281
 #define INS_HALT           (ushort)0x6280
 #define INS_SINT           (ushort)0x6200
@@ -1828,11 +871,10 @@ typedef struct asc_mc_saved {
 #define AscGetRiscVarDoneQTail(port)        AscReadLramByte((port), ASCV_DONENEXT_B)
 #define AscPutRiscVarFreeQHead(port, val)   AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
 #define AscPutRiscVarDoneQTail(port, val)   AscWriteLramByte((port), ASCV_DONENEXT_B, val)
-#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
-#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
-#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
-#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
-#define AscSynIndexToPeriod(index)        (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
+#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data))
+#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id))
+#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data)
+#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id))
 #define AscGetChipSignatureByte(port)     (uchar)inp((port)+IOP_SIG_BYTE)
 #define AscGetChipSignatureWord(port)     (ushort)inpw((port)+IOP_SIG_WORD)
 #define AscGetChipVerNo(port)             (uchar)inp((port)+IOP_VERSION)
@@ -1887,125 +929,6 @@ typedef struct asc_mc_saved {
 #define AscReadChipDvcID(port)            (uchar)inp((port)+IOP_REG_ID)
 #define AscWriteChipDvcID(port, data)     outp((port)+IOP_REG_ID, data)
 
-static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
-static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
-static void AscWaitEEPRead(void);
-static void AscWaitEEPWrite(void);
-static ushort AscReadEEPWord(PortAddr, uchar);
-static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
-static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscStartChip(PortAddr);
-static int AscStopChip(PortAddr);
-static void AscSetChipIH(PortAddr, ushort);
-static int AscIsChipHalted(PortAddr);
-static void AscAckInterrupt(PortAddr);
-static void AscDisableInterrupt(PortAddr);
-static void AscEnableInterrupt(PortAddr);
-static void AscSetBank(PortAddr, uchar);
-static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
-#ifdef CONFIG_ISA
-static ushort AscGetIsaDmaChannel(PortAddr);
-static ushort AscSetIsaDmaChannel(PortAddr, ushort);
-static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
-static uchar AscGetIsaDmaSpeed(PortAddr);
-#endif /* CONFIG_ISA */
-static uchar AscReadLramByte(PortAddr, ushort);
-static ushort AscReadLramWord(PortAddr, ushort);
-#if CC_VERY_LONG_SG_LIST
-static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
-#endif /* CC_VERY_LONG_SG_LIST */
-static void AscWriteLramWord(PortAddr, ushort, ushort);
-static void AscWriteLramByte(PortAddr, ushort, uchar);
-static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
-static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
-static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
-static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
-static ushort AscInitFromEEP(ASC_DVC_VAR *);
-static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
-static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
-static int AscTestExternalLram(ASC_DVC_VAR *);
-static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
-static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
-static void AscSetChipSDTR(PortAddr, uchar, uchar);
-static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
-static uchar AscAllocFreeQueue(PortAddr, uchar);
-static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-static int AscHostReqRiscHalt(PortAddr);
-static int AscStopQueueExe(PortAddr);
-static int AscSendScsiQueue(ASC_DVC_VAR *,
-                           ASC_SCSI_Q *scsiq, uchar n_q_required);
-static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
-static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
-static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
-static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
-static ushort AscInitLram(ASC_DVC_VAR *);
-static ushort AscInitQLinkVar(ASC_DVC_VAR *);
-static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
-static int AscIsrChipHalted(ASC_DVC_VAR *);
-static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
-                                  ASC_QDONE_INFO *, ASC_DCNT);
-static int AscIsrQDone(ASC_DVC_VAR *);
-static int AscCompareString(uchar *, uchar *, int);
-#ifdef CONFIG_ISA
-static ushort AscGetEisaChipCfg(PortAddr);
-static ASC_DCNT AscGetEisaProductID(PortAddr);
-static PortAddr AscSearchIOPortAddrEISA(PortAddr);
-static PortAddr AscSearchIOPortAddr11(PortAddr);
-static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
-static void AscSetISAPNPWaitForKey(void);
-#endif /* CONFIG_ISA */
-static uchar AscGetChipScsiCtrl(PortAddr);
-static uchar AscSetChipScsiID(PortAddr, uchar);
-static uchar AscGetChipVersion(PortAddr, ushort);
-static ushort AscGetChipBusType(PortAddr);
-static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
-static int AscFindSignature(PortAddr);
-static void AscToggleIRQAct(PortAddr);
-static uchar AscGetChipIRQ(PortAddr, ushort);
-static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
-static ushort AscGetChipBiosAddress(PortAddr, ushort);
-static inline ulong DvcEnterCritical(void);
-static inline void DvcLeaveCritical(ulong);
-#ifdef CONFIG_PCI
-static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
-static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
-#endif /* CONFIG_PCI */
-static ushort AscGetChipBiosAddress(PortAddr, ushort);
-static void DvcSleepMilliSecond(ASC_DCNT);
-static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
-static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
-static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
-static ushort AscInitGetConfig(ASC_DVC_VAR *);
-static ushort AscInitSetConfig(ASC_DVC_VAR *);
-static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
-static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
-static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
-static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
-static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
-static int AscISR(ASC_DVC_VAR *);
-static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
-static int AscSgListToQueue(int);
-#ifdef CONFIG_ISA
-static void AscEnableIsaDma(uchar);
-#endif /* CONFIG_ISA */
-static ASC_DCNT AscGetMaxDmaCount(ushort);
-static const char *advansys_info(struct Scsi_Host *shost);
-
-/*
- * --- Adv Library Constants and Macros
- */
-
-#define ADV_LIB_VERSION_MAJOR  5
-#define ADV_LIB_VERSION_MINOR  14
-
-/*
- * Define Adv Library required special types.
- */
-
 /*
  * Portable Data Types
  *
@@ -2044,12 +967,6 @@ static const char *advansys_info(struct Scsi_Host *shost);
 
 #define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
 
-/*
- * For wide  boards a CDB length maximum of 16 bytes
- * is supported.
- */
-#define ADV_MAX_CDB_LEN     16
-
 /*
  * Define total number of simultaneous maximum element scatter-gather
  * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
@@ -2058,28 +975,14 @@ static const char *advansys_info(struct Scsi_Host *shost);
  * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
  * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
  * structures or 255 scatter-gather elements.
- *
  */
 #define ADV_TOT_SG_BLOCK        ASC_DEF_MAX_HOST_QNG
 
 /*
- * Define Adv Library required maximum number of scatter-gather
- * elements per request.
+ * Define maximum number of scatter-gather elements per request.
  */
 #define ADV_MAX_SG_LIST         255
-
-/* Number of SG blocks needed. */
-#define ADV_NUM_SG_BLOCK \
-    ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
-
-/* Total contiguous memory needed for SG blocks. */
-#define ADV_SG_TOTAL_MEM_SIZE \
-    (sizeof(ADV_SG_BLOCK) *  ADV_NUM_SG_BLOCK)
-
-#define ADV_PAGE_SIZE PAGE_SIZE
-
-#define ADV_NUM_PAGE_CROSSING \
-    ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+#define NO_OF_SG_PER_BLOCK              15
 
 #define ADV_EEP_DVC_CFG_BEGIN           (0x00)
 #define ADV_EEP_DVC_CFG_END             (0x15)
@@ -2385,10 +1288,6 @@ typedef struct adveep_38C1600_config {
  * EEPROM Commands
  */
 #define ASC_EEP_CMD_DONE             0x0200
-#define ASC_EEP_CMD_DONE_ERR         0x0001
-
-/* cfg_word */
-#define EEP_CFG_WORD_BIG_ENDIAN      0x8000
 
 /* bios_ctrl */
 #define BIOS_CTRL_BIOS               0x0001
@@ -2405,10 +1304,8 @@ typedef struct adveep_38C1600_config {
 #define BIOS_CTRL_AIPP_DIS           0x2000
 
 #define ADV_3550_MEMSIZE   0x2000      /* 8 KB Internal Memory */
-#define ADV_3550_IOLEN     0x40        /* I/O Port Range in bytes */
 
 #define ADV_38C0800_MEMSIZE  0x4000    /* 16 KB Internal Memory */
-#define ADV_38C0800_IOLEN    0x100     /* I/O Port Range in bytes */
 
 /*
  * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
@@ -2418,8 +1315,6 @@ typedef struct adveep_38C1600_config {
  * #define ADV_38C1600_MEMSIZE  0x8000L   * 32 KB Internal Memory *
  */
 #define ADV_38C1600_MEMSIZE  0x4000    /* 16 KB Internal Memory */
-#define ADV_38C1600_IOLEN    0x100     /* I/O Port Range 256 bytes */
-#define ADV_38C1600_MEMLEN   0x1000    /* Memory Range 4KB bytes */
 
 /*
  * Byte I/O register address from base of 'iop_base'.
@@ -2549,8 +1444,6 @@ typedef struct adveep_38C1600_config {
 #define ADV_CHIP_ID_BYTE         0x25
 #define ADV_CHIP_ID_WORD         0x04C1
 
-#define ADV_SC_SCSI_BUS_RESET    0x2000
-
 #define ADV_INTR_ENABLE_HOST_INTR                   0x01
 #define ADV_INTR_ENABLE_SEL_INTR                    0x02
 #define ADV_INTR_ENABLE_DPR_INTR                    0x04
@@ -2590,8 +1483,6 @@ typedef struct adveep_38C1600_config {
 #define ADV_TICKLE_B                        0x02
 #define ADV_TICKLE_C                        0x03
 
-#define ADV_SCSI_CTRL_RSTOUT        0x2000
-
 #define AdvIsIntPending(port) \
     (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
 
@@ -2744,14 +1635,11 @@ typedef struct adveep_38C1600_config {
  */
 #define INTAB           0x01
 
-/* a_advlib.h */
-
 /*
  * Adv Library Status Definitions
  */
 #define ADV_TRUE        1
 #define ADV_FALSE       0
-#define ADV_NOERROR     1
 #define ADV_SUCCESS     1
 #define ADV_BUSY        0
 #define ADV_ERROR       (-1)
@@ -2762,30 +1650,11 @@ typedef struct adveep_38C1600_config {
 #define ASC_WARN_BUSRESET_ERROR         0x0001 /* SCSI Bus Reset error */
 #define ASC_WARN_EEPROM_CHKSUM          0x0002 /* EEP check sum error */
 #define ASC_WARN_EEPROM_TERMINATION     0x0004 /* EEP termination bad field */
-#define ASC_WARN_SET_PCI_CONFIG_SPACE   0x0080 /* PCI config space set error */
 #define ASC_WARN_ERROR                  0xFFFF /* ADV_ERROR return */
 
 #define ADV_MAX_TID                     15     /* max. target identifier */
 #define ADV_MAX_LUN                     7      /* max. logical unit number */
 
-/*
- * Error code values are set in ADV_DVC_VAR 'err_code'.
- */
-#define ASC_IERR_WRITE_EEPROM       0x0001     /* write EEPROM error */
-#define ASC_IERR_MCODE_CHKSUM       0x0002     /* micro code check sum error */
-#define ASC_IERR_NO_CARRIER         0x0004     /* No more carrier memory. */
-#define ASC_IERR_START_STOP_CHIP    0x0008     /* start/stop chip failed */
-#define ASC_IERR_CHIP_VERSION       0x0040     /* wrong chip version */
-#define ASC_IERR_SET_SCSI_ID        0x0080     /* set SCSI ID failed */
-#define ASC_IERR_HVD_DEVICE         0x0100     /* HVD attached to LVD connector. */
-#define ASC_IERR_BAD_SIGNATURE      0x0200     /* signature not found */
-#define ASC_IERR_ILLEGAL_CONNECTION 0x0400     /* Illegal cable connection */
-#define ASC_IERR_SINGLE_END_DEVICE  0x0800     /* Single-end used w/differential */
-#define ASC_IERR_REVERSED_CABLE     0x1000     /* Narrow flat cable reversed */
-#define ASC_IERR_BIST_PRE_TEST      0x2000     /* BIST pre-test error */
-#define ASC_IERR_BIST_RAM_TEST      0x4000     /* BIST RAM test error */
-#define ASC_IERR_BAD_CHIPTYPE       0x8000     /* Invalid 'chip_type' setting. */
-
 /*
  * Fixed locations of microcode operating variables.
  */
@@ -2902,8 +1771,7 @@ typedef struct adv_carr_t {
 #define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
 
 #define ADV_CARRIER_NUM_PAGE_CROSSING \
-    (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
-        (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+    (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + (PAGE_SIZE - 1))/PAGE_SIZE)
 
 #define ADV_CARRIER_BUFSIZE \
     ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
@@ -2937,80 +1805,17 @@ typedef struct adv_dvc_cfg {
        ushort disc_enable;     /* enable disconnection */
        uchar chip_version;     /* chip version */
        uchar termination;      /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
-       ushort lib_version;     /* Adv Library version number */
        ushort control_flag;    /* Microcode Control Flag */
        ushort mcode_date;      /* Microcode date */
        ushort mcode_version;   /* Microcode version */
-       ushort pci_slot_info;   /* high byte device/function number */
-       /* bits 7-3 device num., bits 2-0 function num. */
-       /* low byte bus num. */
        ushort serial1;         /* EEPROM serial number word 1 */
        ushort serial2;         /* EEPROM serial number word 2 */
        ushort serial3;         /* EEPROM serial number word 3 */
-       struct device *dev;     /* pointer to the pci dev structure for this board */
 } ADV_DVC_CFG;
 
 struct adv_dvc_var;
 struct adv_scsi_req_q;
 
-typedef void (*ADV_ISR_CALLBACK)
- (struct adv_dvc_var *, struct adv_scsi_req_q *);
-
-typedef void (*ADV_ASYNC_CALLBACK)
- (struct adv_dvc_var *, uchar);
-
-/*
- * Adapter operation variable structure.
- *
- * One structure is required per host adapter.
- *
- * Field naming convention:
- *
- *  *_able indicates both whether a feature should be enabled or disabled
- *  and whether a device isi capable of the feature. At initialization
- *  this field may be set, but later if a device is found to be incapable
- *  of the feature, the field is cleared.
- */
-typedef struct adv_dvc_var {
-       AdvPortAddr iop_base;   /* I/O port address */
-       ushort err_code;        /* fatal error code */
-       ushort bios_ctrl;       /* BIOS control word, EEPROM word 12 */
-       ADV_ISR_CALLBACK isr_callback;
-       ADV_ASYNC_CALLBACK async_callback;
-       ushort wdtr_able;       /* try WDTR for a device */
-       ushort sdtr_able;       /* try SDTR for a device */
-       ushort ultra_able;      /* try SDTR Ultra speed for a device */
-       ushort sdtr_speed1;     /* EEPROM SDTR Speed for TID 0-3   */
-       ushort sdtr_speed2;     /* EEPROM SDTR Speed for TID 4-7   */
-       ushort sdtr_speed3;     /* EEPROM SDTR Speed for TID 8-11  */
-       ushort sdtr_speed4;     /* EEPROM SDTR Speed for TID 12-15 */
-       ushort tagqng_able;     /* try tagged queuing with a device */
-       ushort ppr_able;        /* PPR message capable per TID bitmask. */
-       uchar max_dvc_qng;      /* maximum number of tagged commands per device */
-       ushort start_motor;     /* start motor command allowed */
-       uchar scsi_reset_wait;  /* delay in seconds after scsi bus reset */
-       uchar chip_no;          /* should be assigned by caller */
-       uchar max_host_qng;     /* maximum number of Q'ed command allowed */
-       uchar irq_no;           /* IRQ number */
-       ushort no_scam;         /* scam_tolerant of EEPROM */
-       struct asc_board *drv_ptr;      /* driver pointer to private structure */
-       uchar chip_scsi_id;     /* chip SCSI target ID */
-       uchar chip_type;
-       uchar bist_err_code;
-       ADV_CARR_T *carrier_buf;
-       ADV_CARR_T *carr_freelist;      /* Carrier free list. */
-       ADV_CARR_T *icq_sp;     /* Initiator command queue stopper pointer. */
-       ADV_CARR_T *irq_sp;     /* Initiator response queue stopper pointer. */
-       ushort carr_pending_cnt;        /* Count of pending carriers. */
-       /*
-        * Note: The following fields will not be used after initialization. The
-        * driver may discard the buffer after initialization is done.
-        */
-       ADV_DVC_CFG *cfg;       /* temporary configuration structure  */
-} ADV_DVC_VAR;
-
-#define NO_OF_SG_PER_BLOCK              15
-
 typedef struct asc_sg_block {
        uchar reserved1;
        uchar reserved2;
@@ -3068,6 +1873,83 @@ typedef struct adv_scsi_req_q {
        uchar pad[2];           /* Pad out to a word boundary. */
 } ADV_SCSI_REQ_Q;
 
+/*
+ * The following two structures are used to process Wide Board requests.
+ *
+ * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
+ * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
+ * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
+ * Mid-Level SCSI request structure.
+ *
+ * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
+ * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
+ * up to 255 scatter-gather elements may be used per request or
+ * ADV_SCSI_REQ_Q.
+ *
+ * Both structures must be 32 byte aligned.
+ */
+typedef struct adv_sgblk {
+       ADV_SG_BLOCK sg_block;  /* Sgblock structure. */
+       uchar align[32];        /* Sgblock structure padding. */
+       struct adv_sgblk *next_sgblkp;  /* Next scatter-gather structure. */
+} adv_sgblk_t;
+
+typedef struct adv_req {
+       ADV_SCSI_REQ_Q scsi_req_q;      /* Adv Library request structure. */
+       uchar align[32];        /* Request structure padding. */
+       struct scsi_cmnd *cmndp;        /* Mid-Level SCSI command pointer. */
+       adv_sgblk_t *sgblkp;    /* Adv Library scatter-gather pointer. */
+       struct adv_req *next_reqp;      /* Next Request Structure. */
+} adv_req_t;
+
+/*
+ * Adapter operation variable structure.
+ *
+ * One structure is required per host adapter.
+ *
+ * Field naming convention:
+ *
+ *  *_able indicates both whether a feature should be enabled or disabled
+ *  and whether a device isi capable of the feature. At initialization
+ *  this field may be set, but later if a device is found to be incapable
+ *  of the feature, the field is cleared.
+ */
+typedef struct adv_dvc_var {
+       AdvPortAddr iop_base;   /* I/O port address */
+       ushort err_code;        /* fatal error code */
+       ushort bios_ctrl;       /* BIOS control word, EEPROM word 12 */
+       ushort wdtr_able;       /* try WDTR for a device */
+       ushort sdtr_able;       /* try SDTR for a device */
+       ushort ultra_able;      /* try SDTR Ultra speed for a device */
+       ushort sdtr_speed1;     /* EEPROM SDTR Speed for TID 0-3   */
+       ushort sdtr_speed2;     /* EEPROM SDTR Speed for TID 4-7   */
+       ushort sdtr_speed3;     /* EEPROM SDTR Speed for TID 8-11  */
+       ushort sdtr_speed4;     /* EEPROM SDTR Speed for TID 12-15 */
+       ushort tagqng_able;     /* try tagged queuing with a device */
+       ushort ppr_able;        /* PPR message capable per TID bitmask. */
+       uchar max_dvc_qng;      /* maximum number of tagged commands per device */
+       ushort start_motor;     /* start motor command allowed */
+       uchar scsi_reset_wait;  /* delay in seconds after scsi bus reset */
+       uchar chip_no;          /* should be assigned by caller */
+       uchar max_host_qng;     /* maximum number of Q'ed command allowed */
+       ushort no_scam;         /* scam_tolerant of EEPROM */
+       struct asc_board *drv_ptr;      /* driver pointer to private structure */
+       uchar chip_scsi_id;     /* chip SCSI target ID */
+       uchar chip_type;
+       uchar bist_err_code;
+       ADV_CARR_T *carrier_buf;
+       ADV_CARR_T *carr_freelist;      /* Carrier free list. */
+       ADV_CARR_T *icq_sp;     /* Initiator command queue stopper pointer. */
+       ADV_CARR_T *irq_sp;     /* Initiator response queue stopper pointer. */
+       ushort carr_pending_cnt;        /* Count of pending carriers. */
+       struct adv_req *orig_reqp;      /* adv_req_t memory block. */
+       /*
+        * Note: The following fields will not be used after initialization. The
+        * driver may discard the buffer after initialization is done.
+        */
+       ADV_DVC_CFG *cfg;       /* temporary configuration structure  */
+} ADV_DVC_VAR;
+
 /*
  * Microcode idle loop commands
  */
@@ -3092,10 +1974,8 @@ typedef struct adv_scsi_req_q {
 /*
  * Wait loop time out values.
  */
-#define SCSI_WAIT_10_SEC             10UL      /* 10 seconds */
 #define SCSI_WAIT_100_MSEC           100UL     /* 100 milliseconds */
 #define SCSI_US_PER_MSEC             1000      /* microseconds per millisecond */
-#define SCSI_MS_PER_SEC              1000UL    /* milliseconds per second */
 #define SCSI_MAX_RETRY               10        /* retry count */
 
 #define ADV_ASYNC_RDMA_FAILURE          0x01   /* Fatal RDMA failure. */
@@ -3105,53 +1985,6 @@ typedef struct adv_scsi_req_q {
 
 #define ADV_HOST_SCSI_BUS_RESET      0x80      /* Host Initiated SCSI Bus Reset. */
 
-/*
- * Device drivers must define the following functions.
- */
-static inline ulong DvcEnterCritical(void);
-static inline void DvcLeaveCritical(ulong);
-static void DvcSleepMilliSecond(ADV_DCNT);
-static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
-static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
-static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
-                              uchar *, ASC_SDCNT *, int);
-static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
-
-/*
- * Adv Library functions available to drivers.
- */
-static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static int AdvISR(ADV_DVC_VAR *);
-static int AdvInitGetConfig(ADV_DVC_VAR *);
-static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
-static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
-static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
-static int AdvResetChipAndSB(ADV_DVC_VAR *);
-static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
-
-/*
- * Internal Adv Library functions.
- */
-static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
-static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
-static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
-static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
-static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-static void AdvWaitEEPCmd(AdvPortAddr);
-static ushort AdvReadEEPWord(AdvPortAddr, int);
-
-/*
- * PCI Bus Definitions
- */
-#define AscPCICmdRegBits_BusMastering     0x0007
-#define AscPCICmdRegBits_ParErrRespCtrl   0x0040
-
 /* Read byte from a register. */
 #define AdvReadByteRegister(iop_base, reg_off) \
      (ADV_MEM_READB((iop_base) + (reg_off)))
@@ -3319,23 +2152,6 @@ do { \
 #define QHSTA_M_FROZEN_TIDQ         0x46       /* TID Queue frozen. */
 #define QHSTA_M_SGBACKUP_ERROR      0x47       /* Scatter-Gather backup error */
 
-/*
- * Default EEPROM Configuration structure defined in a_init.c.
- */
-static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
-static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
-static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
-
-/*
- * DvcGetPhyAddr() flag arguments
- */
-#define ADV_IS_SCSIQ_FLAG       0x01   /* 'addr' is ASC_SCSI_REQ_Q pointer */
-#define ADV_ASCGETSGLIST_VADDR  0x02   /* 'addr' is AscGetSGList() virtual addr */
-#define ADV_IS_SENSE_FLAG       0x04   /* 'addr' is sense virtual pointer */
-#define ADV_IS_DATA_FLAG        0x08   /* 'addr' is data virtual pointer */
-#define ADV_IS_SGLIST_FLAG      0x10   /* 'addr' is sglist virtual pointer */
-#define ADV_IS_CARRIER_FLAG     0x20   /* 'addr' is ADV_CARR_T pointer */
-
 /* Return the address that is aligned at the next doubleword >= to 'addr'. */
 #define ADV_8BALIGN(addr)      (((ulong) (addr) + 0x7) & ~0x7)
 #define ADV_16BALIGN(addr)     (((ulong) (addr) + 0xF) & ~0xF)
@@ -3353,92 +2169,10 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
          (sizeof(ADV_SG_BLOCK) * \
           ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
 
-/*
- * Inquiry data structure and bitfield macros
- *
- * Using bitfields to access the subchar data isn't portable across
- * endianness, so instead mask and shift. Only quantities of more
- * than 1 bit are shifted, since the others are just tested for true
- * or false.
- */
-
-#define ADV_INQ_DVC_TYPE(inq)       ((inq)->periph & 0x1f)
-#define ADV_INQ_QUALIFIER(inq)      (((inq)->periph & 0xe0) >> 5)
-#define ADV_INQ_DVC_TYPE_MOD(inq)   ((inq)->devtype & 0x7f)
-#define ADV_INQ_REMOVABLE(inq)      ((inq)->devtype & 0x80)
-#define ADV_INQ_ANSI_VER(inq)       ((inq)->ver & 0x07)
-#define ADV_INQ_ECMA_VER(inq)       (((inq)->ver & 0x38) >> 3)
-#define ADV_INQ_ISO_VER(inq)        (((inq)->ver & 0xc0) >> 6)
-#define ADV_INQ_RESPONSE_FMT(inq)   ((inq)->byte3 & 0x0f)
-#define ADV_INQ_TERM_IO(inq)        ((inq)->byte3 & 0x40)
-#define ADV_INQ_ASYNC_NOTIF(inq)    ((inq)->byte3 & 0x80)
-#define ADV_INQ_SOFT_RESET(inq)     ((inq)->flags & 0x01)
-#define ADV_INQ_CMD_QUEUE(inq)      ((inq)->flags & 0x02)
-#define ADV_INQ_LINK_CMD(inq)       ((inq)->flags & 0x08)
-#define ADV_INQ_SYNC(inq)           ((inq)->flags & 0x10)
-#define ADV_INQ_WIDE16(inq)         ((inq)->flags & 0x20)
-#define ADV_INQ_WIDE32(inq)         ((inq)->flags & 0x40)
-#define ADV_INQ_REL_ADDR(inq)       ((inq)->flags & 0x80)
-#define ADV_INQ_INFO_UNIT(inq)      ((inq)->info & 0x01)
-#define ADV_INQ_QUICK_ARB(inq)      ((inq)->info & 0x02)
-#define ADV_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
-
-typedef struct {
-       uchar periph;           /* peripheral device type [0:4] */
-       /* peripheral qualifier [5:7] */
-       uchar devtype;          /* device type modifier (for SCSI I) [0:6] */
-       /* RMB - removable medium bit [7] */
-       uchar ver;              /* ANSI approved version [0:2] */
-       /* ECMA version [3:5] */
-       /* ISO version [6:7] */
-       uchar byte3;            /* response data format [0:3] */
-       /* 0 SCSI 1 */
-       /* 1 CCS */
-       /* 2 SCSI-2 */
-       /* 3-F reserved */
-       /* reserved [4:5] */
-       /* terminate I/O process bit (see 5.6.22) [6] */
-       /* asynch. event notification (processor) [7] */
-       uchar add_len;          /* additional length */
-       uchar res1;             /* reserved */
-       uchar res2;             /* reserved */
-       uchar flags;            /* soft reset implemented [0] */
-       /* command queuing [1] */
-       /* reserved [2] */
-       /* linked command for this logical unit [3] */
-       /* synchronous data transfer [4] */
-       /* wide bus 16 bit data transfer [5] */
-       /* wide bus 32 bit data transfer [6] */
-       /* relative addressing mode [7] */
-       uchar vendor_id[8];     /* vendor identification */
-       uchar product_id[16];   /* product identification */
-       uchar product_rev_level[4];     /* product revision level */
-       uchar vendor_specific[20];      /* vendor specific */
-       uchar info;             /* information unit supported [0] */
-       /* quick arbitrate supported [1] */
-       /* clocking field [2:3] */
-       /* reserved [4:7] */
-       uchar res3;             /* reserved */
-} ADV_SCSI_INQUIRY;            /* 58 bytes */
-
-/*
- * --- Driver Constants and Macros
- */
-
-#define ASC_NUM_BOARD_SUPPORTED 16
-#define ASC_NUM_IOPORT_PROBE    4
-#define ASC_NUM_BUS             4
-
-/* Reference Scsi_Host hostdata */
-#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
-
-/* asc_board_t flags */
-#define ASC_HOST_IN_RESET       0x01
+/* struct asc_board flags */
 #define ASC_IS_WIDE_BOARD       0x04   /* AdvanSys Wide Board */
-#define ASC_SELECT_QUEUE_DEPTHS 0x08
 
 #define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
-#define ASC_WIDE_BOARD(boardp)   ((boardp)->flags & ASC_IS_WIDE_BOARD)
 
 #define NO_ISA_DMA              0xff   /* No ISA DMA Channel Used */
 
@@ -3473,82 +2207,14 @@ typedef struct {
 #define HOST_BYTE(byte)     ((byte) << 16)
 #define DRIVER_BYTE(byte)   ((byte) << 24)
 
-/*
- * The following definitions and macros are OS independent interfaces to
- * the queue functions:
- *  REQ - SCSI request structure
- *  REQP - pointer to SCSI request structure
- *  REQPTID(reqp) - reqp's target id
- *  REQPNEXT(reqp) - reqp's next pointer
- *  REQPNEXTP(reqp) - pointer to reqp's next pointer
- *  REQPTIME(reqp) - reqp's time stamp value
- *  REQTIMESTAMP() - system time stamp value
- */
-typedef struct scsi_cmnd REQ, *REQP;
-#define REQPNEXT(reqp)       ((REQP) ((reqp)->host_scribble))
-#define REQPNEXTP(reqp)      ((REQP *) &((reqp)->host_scribble))
-#define REQPTID(reqp)        ((reqp)->device->id)
-#define REQPTIME(reqp)       ((reqp)->SCp.this_residual)
-#define REQTIMESTAMP()       (jiffies)
-
-#define REQTIMESTAT(function, ascq, reqp, tid) \
-{ \
-    /*
-     * If the request time stamp is less than the system time stamp, then \
-     * maybe the system time stamp wrapped. Set the request time to zero.\
-     */ \
-    if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
-        REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
-    } else { \
-        /* Indicate an error occurred with the assertion. */ \
-        ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
-        REQPTIME(reqp) = 0; \
-    } \
-    /* Handle first minimum time case without external initialization. */ \
-    if (((ascq)->q_tot_cnt[tid] == 1) ||  \
-        (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
-            (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
-            ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
-                (function), (tid), (ascq)->q_min_tim[tid]); \
-        } \
-    if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
-        (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
-        ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
-            (function), tid, (ascq)->q_max_tim[tid]); \
-    } \
-    (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
-    /* Reset the time stamp field. */ \
-    REQPTIME(reqp) = 0; \
-}
-
-/* asc_enqueue() flags */
-#define ASC_FRONT       1
-#define ASC_BACK        2
-
-/* asc_dequeue_list() argument */
-#define ASC_TID_ALL        (-1)
-
-/* Return non-zero, if the queue is empty. */
-#define ASC_QUEUE_EMPTY(ascq)    ((ascq)->q_tidmask == 0)
-
-#define PCI_MAX_SLOT            0x1F
-#define PCI_MAX_BUS             0xFF
-#define PCI_IOADDRESS_MASK      0xFFFE
-#define ASC_PCI_DEVICE_ID_CNT   6      /* PCI Device ID count. */
-
+#define ASC_STATS(shost, counter) ASC_STATS_ADD(shost, counter, 1)
 #ifndef ADVANSYS_STATS
-#define ASC_STATS(shost, counter)
 #define ASC_STATS_ADD(shost, counter, count)
 #else /* ADVANSYS_STATS */
-#define ASC_STATS(shost, counter) \
-    (ASC_BOARDP(shost)->asc_stats.counter++)
-
 #define ASC_STATS_ADD(shost, counter, count) \
-    (ASC_BOARDP(shost)->asc_stats.counter += (count))
+       (((struct asc_board *) shost_priv(shost))->asc_stats.counter += (count))
 #endif /* ADVANSYS_STATS */
 
-#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
-
 /* If the result wraps when calculating tenths, return 0. */
 #define ASC_TENTHS(num, den) \
     (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
@@ -3589,13 +2255,8 @@ typedef struct scsi_cmnd REQ, *REQP;
 
 #ifndef ADVANSYS_DEBUG
 
-#define ASC_DBG(lvl, s)
-#define ASC_DBG1(lvl, s, a1)
-#define ASC_DBG2(lvl, s, a1, a2)
-#define ASC_DBG3(lvl, s, a1, a2, a3)
-#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
+#define ASC_DBG(lvl, s...)
 #define ASC_DBG_PRT_SCSI_HOST(lvl, s)
-#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
 #define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
 #define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
 #define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
@@ -3614,40 +2275,11 @@ typedef struct scsi_cmnd REQ, *REQP;
  * 2-N: Verbose Tracing
  */
 
-#define ASC_DBG(lvl, s) \
-    { \
-        if (asc_dbglvl >= (lvl)) { \
-            printk(s); \
-        } \
-    }
-
-#define ASC_DBG1(lvl, s, a1) \
-    { \
-        if (asc_dbglvl >= (lvl)) { \
-            printk((s), (a1)); \
-        } \
-    }
-
-#define ASC_DBG2(lvl, s, a1, a2) \
-    { \
-        if (asc_dbglvl >= (lvl)) { \
-            printk((s), (a1), (a2)); \
-        } \
-    }
-
-#define ASC_DBG3(lvl, s, a1, a2, a3) \
-    { \
-        if (asc_dbglvl >= (lvl)) { \
-            printk((s), (a1), (a2), (a3)); \
-        } \
-    }
-
-#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
-    { \
-        if (asc_dbglvl >= (lvl)) { \
-            printk((s), (a1), (a2), (a3), (a4)); \
-        } \
-    }
+#define ASC_DBG(lvl, format, arg...) {                                 \
+       if (asc_dbglvl >= (lvl))                                        \
+               printk(KERN_DEBUG "%s: %s: " format, DRV_NAME,          \
+                       __FUNCTION__ , ## arg);                         \
+}
 
 #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
     { \
@@ -3656,13 +2288,6 @@ typedef struct scsi_cmnd REQ, *REQP;
         } \
     }
 
-#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
-    { \
-        if (asc_dbglvl >= (lvl)) { \
-            asc_prt_scsi_cmnd(s); \
-        } \
-    }
-
 #define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
     { \
         if (asc_dbglvl >= (lvl)) { \
@@ -3701,24 +2326,6 @@ typedef struct scsi_cmnd REQ, *REQP;
         ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
 #endif /* ADVANSYS_DEBUG */
 
-#ifndef ADVANSYS_ASSERT
-#define ASC_ASSERT(a)
-#else /* ADVANSYS_ASSERT */
-
-#define ASC_ASSERT(a) \
-    { \
-        if (!(a)) { \
-            printk("ASC_ASSERT() Failure: file %s, line %d\n", \
-                __FILE__, __LINE__); \
-        } \
-    }
-
-#endif /* ADVANSYS_ASSERT */
-
-/*
- * --- Driver Structures
- */
-
 #ifdef ADVANSYS_STATS
 
 /* Per board statistics structure */
@@ -3739,72 +2346,23 @@ struct asc_stats {
        ADV_DCNT exe_error;     /* # ASC_ERROR returns. */
        ADV_DCNT exe_unknown;   /* # unknown returns. */
        /* Data Transfer Statistics */
-       ADV_DCNT cont_cnt;      /* # non-scatter-gather I/O requests received */
-       ADV_DCNT cont_xfer;     /* # contiguous transfer 512-bytes */
-       ADV_DCNT sg_cnt;        /* # scatter-gather I/O requests received */
-       ADV_DCNT sg_elem;       /* # scatter-gather elements */
-       ADV_DCNT sg_xfer;       /* # scatter-gather transfer 512-bytes */
+       ADV_DCNT xfer_cnt;      /* # I/O requests received */
+       ADV_DCNT xfer_elem;     /* # scatter-gather elements */
+       ADV_DCNT xfer_sect;     /* # 512-byte blocks */
 };
 #endif /* ADVANSYS_STATS */
 
-/*
- * Request queuing structure
- */
-typedef struct asc_queue {
-       ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
-       REQP q_first[ADV_MAX_TID + 1];  /* first queued request */
-       REQP q_last[ADV_MAX_TID + 1];   /* last queued request */
-#ifdef ADVANSYS_STATS
-       short q_cur_cnt[ADV_MAX_TID + 1];       /* current queue count */
-       short q_max_cnt[ADV_MAX_TID + 1];       /* maximum queue count */
-       ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1];    /* total enqueue count */
-       ADV_DCNT q_tot_tim[ADV_MAX_TID + 1];    /* total time queued */
-       ushort q_max_tim[ADV_MAX_TID + 1];      /* maximum time queued */
-       ushort q_min_tim[ADV_MAX_TID + 1];      /* minimum time queued */
-#endif                         /* ADVANSYS_STATS */
-} asc_queue_t;
-
-/*
- * Adv Library Request Structures
- *
- * The following two structures are used to process Wide Board requests.
- *
- * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
- * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
- * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
- * Mid-Level SCSI request structure.
- *
- * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
- * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
- * up to 255 scatter-gather elements may be used per request or
- * ADV_SCSI_REQ_Q.
- *
- * Both structures must be 32 byte aligned.
- */
-typedef struct adv_sgblk {
-       ADV_SG_BLOCK sg_block;  /* Sgblock structure. */
-       uchar align[32];        /* Sgblock structure padding. */
-       struct adv_sgblk *next_sgblkp;  /* Next scatter-gather structure. */
-} adv_sgblk_t;
-
-typedef struct adv_req {
-       ADV_SCSI_REQ_Q scsi_req_q;      /* Adv Library request structure. */
-       uchar align[32];        /* Request structure padding. */
-       struct scsi_cmnd *cmndp;        /* Mid-Level SCSI command pointer. */
-       adv_sgblk_t *sgblkp;    /* Adv Library scatter-gather pointer. */
-       struct adv_req *next_reqp;      /* Next Request Structure. */
-} adv_req_t;
-
 /*
  * Structure allocated for each board.
  *
- * This structure is allocated by scsi_register() at the end
+ * This structure is allocated by scsi_host_alloc() at the end
  * of the 'Scsi_Host' structure starting at the 'hostdata'
  * field. It is guaranteed to be allocated from DMA-able memory.
  */
-typedef struct asc_board {
-       int id;                 /* Board Id */
+struct asc_board {
+       struct device *dev;
        uint flags;             /* Board flags */
+       unsigned int irq;
        union {
                ASC_DVC_VAR asc_dvc_var;        /* Narrow board */
                ADV_DVC_VAR adv_dvc_var;        /* Wide board */
@@ -3814,11 +2372,7 @@ typedef struct asc_board {
                ADV_DVC_CFG adv_dvc_cfg;        /* Wide board */
        } dvc_cfg;
        ushort asc_n_io_port;   /* Number I/O ports. */
-       asc_queue_t active;     /* Active command queue */
-       asc_queue_t waiting;    /* Waiting command queue */
-       asc_queue_t done;       /* Done command queue */
        ADV_SCSI_BIT_ID_TYPE init_tidmask;      /* Target init./valid mask */
-       struct scsi_device *device[ADV_MAX_TID + 1];    /* Mid-Level Scsi Device */
        ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
        ADV_SCSI_BIT_ID_TYPE queue_full;        /* Queue full mask */
        ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
@@ -3829,2413 +2383,1679 @@ typedef struct asc_board {
                ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
        } eep_config;
        ulong last_reset;       /* Saved last reset time */
-       spinlock_t lock;        /* Board spinlock */
-#ifdef CONFIG_PROC_FS
        /* /proc/scsi/advansys/[0...] */
        char *prtbuf;           /* /proc print buffer */
-#endif                         /* CONFIG_PROC_FS */
 #ifdef ADVANSYS_STATS
        struct asc_stats asc_stats;     /* Board statistics */
 #endif                         /* ADVANSYS_STATS */
        /*
         * The following fields are used only for Narrow Boards.
         */
-       /* The following three structures must be in DMA-able memory. */
-       ASC_SCSI_REQ_Q scsireqq;
-       ASC_CAP_INFO cap_info;
-       ASC_SCSI_INQUIRY inquiry;
        uchar sdtr_data[ASC_MAX_TID + 1];       /* SDTR information */
        /*
         * The following fields are used only for Wide Boards.
         */
        void __iomem *ioremap_addr;     /* I/O Memory remap address. */
        ushort ioport;          /* I/O Port address. */
-       ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
-       adv_req_t *orig_reqp;   /* adv_req_t memory block. */
        adv_req_t *adv_reqp;    /* Request structures. */
        adv_sgblk_t *adv_sgblkp;        /* Scatter-gather structures. */
        ushort bios_signature;  /* BIOS Signature. */
        ushort bios_version;    /* BIOS Version. */
        ushort bios_codeseg;    /* BIOS Code Segment. */
        ushort bios_codelen;    /* BIOS Code Segment Length. */
-} asc_board_t;
+};
 
-/*
- * PCI configuration structures
- */
-typedef struct _PCI_DATA_ {
-       uchar type;
-       uchar bus;
-       uchar slot;
-       uchar func;
-       uchar offset;
-} PCI_DATA;
-
-typedef struct _PCI_DEVICE_ {
-       ushort vendorID;
-       ushort deviceID;
-       ushort slotNumber;
-       ushort slotFound;
-       uchar busNumber;
-       uchar maxBusNumber;
-       uchar devFunc;
-       ushort startSlot;
-       ushort endSlot;
-       uchar bridge;
-       uchar type;
-} PCI_DEVICE;
-
-typedef struct _PCI_CONFIG_SPACE_ {
-       ushort vendorID;
-       ushort deviceID;
-       ushort command;
-       ushort status;
-       uchar revision;
-       uchar classCode[3];
-       uchar cacheSize;
-       uchar latencyTimer;
-       uchar headerType;
-       uchar bist;
-       ADV_PADDR baseAddress[6];
-       ushort reserved[4];
-       ADV_PADDR optionRomAddr;
-       ushort reserved2[4];
-       uchar irqLine;
-       uchar irqPin;
-       uchar minGnt;
-       uchar maxLatency;
-} PCI_CONFIG_SPACE;
+#define asc_dvc_to_board(asc_dvc) container_of(asc_dvc, struct asc_board, \
+                                                       dvc_var.asc_dvc_var)
+#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
+                                                       dvc_var.adv_dvc_var)
+#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
+
+#ifdef ADVANSYS_DEBUG
+static int asc_dbglvl = 3;
 
 /*
- * --- Driver Data
+ * asc_prt_asc_dvc_var()
  */
+static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
+{
+       printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
+
+       printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
+              "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+
+       printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
+               (unsigned)h->init_sdtr);
 
-/* Note: All driver global data should be initialized. */
+       printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
+              "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
+              (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
+              (unsigned)h->chip_no);
 
-/* Number of boards detected in system. */
-static int asc_board_count = 0;
-static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
+       printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
+              "%u,\n", (unsigned)h->queue_full_or_busy,
+              (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
 
-/* Overrun buffer used by all narrow boards. */
-static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
+       printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
+              "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
+              (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
+              (unsigned)h->in_critical_cnt);
+
+       printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
+              "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
+              (unsigned)h->init_state, (unsigned)h->no_scam,
+              (unsigned)h->pci_fix_asyn_xfer);
+
+       printk(" cfg 0x%lx\n", (ulong)h->cfg);
+}
 
 /*
- * Global structures required to issue a command.
+ * asc_prt_asc_dvc_cfg()
  */
-static ASC_SCSI_Q asc_scsi_q = { {0} };
-static ASC_SG_HEAD asc_sg_head = { 0 };
-
-/* List of supported bus types. */
-static ushort asc_bus[ASC_NUM_BUS] __initdata = {
-       ASC_IS_ISA,
-       ASC_IS_VL,
-       ASC_IS_EISA,
-       ASC_IS_PCI,
-};
-
-static int asc_iopflag = ASC_FALSE;
-static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
+{
+       printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
 
-#ifdef ADVANSYS_DEBUG
-static char *asc_bus_name[ASC_NUM_BUS] = {
-       "ASC_IS_ISA",
-       "ASC_IS_VL",
-       "ASC_IS_EISA",
-       "ASC_IS_PCI",
-};
+       printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
+              h->can_tagged_qng, h->cmd_qng_enabled);
+       printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
+              h->disc_enable, h->sdtr_enable);
 
-static int asc_dbglvl = 3;
-#endif /* ADVANSYS_DEBUG */
+       printk(" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, "
+               "chip_version %d,\n", h->chip_scsi_id, h->isa_dma_speed,
+               h->isa_dma_channel, h->chip_version);
 
-/* Declaration for Asc Library internal data referenced by driver. */
-static PortAddr _asc_def_iop_base[];
+       printk(" mcode_date 0x%x, mcode_version %d\n",
+               h->mcode_date, h->mcode_version);
+}
 
 /*
- * --- Driver Function Prototypes
+ * asc_prt_adv_dvc_var()
  *
- * advansys.h contains function prototypes for functions global to Linux.
+ * Display an ADV_DVC_VAR structure.
  */
+static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
+{
+       printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
 
-static irqreturn_t advansys_interrupt(int, void *);
-static int advansys_slave_configure(struct scsi_device *);
-static void asc_scsi_done_list(struct scsi_cmnd *);
-static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
-static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
-static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
-static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
-static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
-static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static void adv_async_callback(ADV_DVC_VAR *, uchar);
-static void asc_enqueue(asc_queue_t *, REQP, int);
-static REQP asc_dequeue(asc_queue_t *, int);
-static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
-static int asc_rmqueue(asc_queue_t *, REQP);
-static void asc_execute_queue(asc_queue_t *);
-#ifdef CONFIG_PROC_FS
-static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
-static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
-static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
-static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
-static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
-static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
-static int asc_prt_line(char *, int, char *fmt, ...);
-#endif /* CONFIG_PROC_FS */
+       printk("  iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+              (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
 
-/* Declaration for Asc Library internal functions referenced by driver. */
-static int AscFindSignature(PortAddr);
-static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+       printk("  sdtr_able 0x%x, wdtr_able 0x%x\n",
+              (unsigned)h->sdtr_able, (unsigned)h->wdtr_able);
 
-/* Statistics function prototypes. */
-#ifdef ADVANSYS_STATS
-#ifdef CONFIG_PROC_FS
-static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
-static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
-#endif /* CONFIG_PROC_FS */
-#endif /* ADVANSYS_STATS */
+       printk("  start_motor 0x%x, scsi_reset_wait 0x%x\n",
+              (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
 
-/* Debug function prototypes. */
-#ifdef ADVANSYS_DEBUG
-static void asc_prt_scsi_host(struct Scsi_Host *);
-static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
-static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
-static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
-static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
-static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
-static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
-static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
-static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
-static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
-static void asc_prt_hex(char *f, uchar *, int);
-#endif /* ADVANSYS_DEBUG */
+       printk("  max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
+              (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
+              (ulong)h->carr_freelist);
+
+       printk("  icq_sp 0x%lx, irq_sp 0x%lx\n",
+              (ulong)h->icq_sp, (ulong)h->irq_sp);
+
+       printk("  no_scam 0x%x, tagqng_able 0x%x\n",
+              (unsigned)h->no_scam, (unsigned)h->tagqng_able);
+
+       printk("  chip_scsi_id 0x%x, cfg 0x%lx\n",
+              (unsigned)h->chip_scsi_id, (ulong)h->cfg);
+}
 
-#ifdef CONFIG_PROC_FS
 /*
- * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset into a /proc/scsi/advansys/[0...] file
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written to a
- * /proc/scsi/advansys/[0...] file.
+ * asc_prt_adv_dvc_cfg()
  *
- * Note: This function uses the per board buffer 'prtbuf' which is
- * allocated when the board is initialized in advansys_detect(). The
- * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
- * used to write to the buffer. The way asc_proc_copy() is written
- * if 'prtbuf' is too small it will not be overwritten. Instead the
- * user just won't get all the available statistics.
+ * Display an ADV_DVC_CFG structure.
  */
-static int
-advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
-                  off_t offset, int length, int inout)
+static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
 {
-       struct Scsi_Host *shp;
-       asc_board_t *boardp;
-       int i;
-       char *cp;
-       int cplen;
-       int cnt;
-       int totcnt;
-       int leftlen;
-       char *curbuf;
-       off_t advoffset;
-#ifdef ADVANSYS_STATS
-       int tgt_id;
-#endif /* ADVANSYS_STATS */
+       printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
 
-       ASC_DBG(1, "advansys_proc_info: begin\n");
+       printk("  disc_enable 0x%x, termination 0x%x\n",
+              h->disc_enable, h->termination);
 
-       /*
-        * User write not supported.
-        */
-       if (inout == TRUE) {
-               return (-ENOSYS);
-       }
+       printk("  chip_version 0x%x, mcode_date 0x%x\n",
+              h->chip_version, h->mcode_date);
 
-       /*
-        * User read of /proc/scsi/advansys/[0...] file.
-        */
+       printk("  mcode_version 0x%x, control_flag 0x%x\n",
+              h->mcode_version, h->control_flag);
+}
 
-       /* Find the specified board. */
-       for (i = 0; i < asc_board_count; i++) {
-               if (asc_host[i]->host_no == shost->host_no) {
-                       break;
-               }
-       }
-       if (i == asc_board_count) {
-               return (-ENOENT);
-       }
+/*
+ * asc_prt_scsi_host()
+ */
+static void asc_prt_scsi_host(struct Scsi_Host *s)
+{
+       struct asc_board *boardp = shost_priv(s);
 
-       shp = asc_host[i];
-       boardp = ASC_BOARDP(shp);
+       printk("Scsi_Host at addr 0x%p, device %s\n", s, boardp->dev->bus_id);
+       printk(" host_busy %u, host_no %d, last_reset %d,\n",
+              s->host_busy, s->host_no, (unsigned)s->last_reset);
 
-       /* Copy read data starting at the beginning of the buffer. */
-       *start = buffer;
-       curbuf = buffer;
-       advoffset = 0;
-       totcnt = 0;
-       leftlen = length;
+       printk(" base 0x%lx, io_port 0x%lx, irq %d,\n",
+              (ulong)s->base, (ulong)s->io_port, boardp->irq);
 
-       /*
-        * Get board configuration information.
-        *
-        * advansys_info() returns the board string from its own static buffer.
-        */
-       cp = (char *)advansys_info(shp);
-       strcat(cp, "\n");
-       cplen = strlen(cp);
-       /* Copy board information. */
-       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-       totcnt += cnt;
-       leftlen -= cnt;
-       if (leftlen == 0) {
-               ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-               return totcnt;
-       }
-       advoffset += cplen;
-       curbuf += cnt;
+       printk(" dma_channel %d, this_id %d, can_queue %d,\n",
+              s->dma_channel, s->this_id, s->can_queue);
 
-       /*
-        * Display Wide Board BIOS Information.
-        */
-       if (ASC_WIDE_BOARD(boardp)) {
-               cp = boardp->prtbuf;
-               cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
-               ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-               cnt =
-                   asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
-                                 cplen);
-               totcnt += cnt;
-               leftlen -= cnt;
-               if (leftlen == 0) {
-                       ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-                       return totcnt;
-               }
-               advoffset += cplen;
-               curbuf += cnt;
+       printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+              s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+
+       if (ASC_NARROW_BOARD(boardp)) {
+               asc_prt_asc_dvc_var(&boardp->dvc_var.asc_dvc_var);
+               asc_prt_asc_dvc_cfg(&boardp->dvc_cfg.asc_dvc_cfg);
+       } else {
+               asc_prt_adv_dvc_var(&boardp->dvc_var.adv_dvc_var);
+               asc_prt_adv_dvc_cfg(&boardp->dvc_cfg.adv_dvc_cfg);
        }
-
-       /*
-        * Display driver information for each device attached to the board.
-        */
-       cp = boardp->prtbuf;
-       cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
-       ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-       totcnt += cnt;
-       leftlen -= cnt;
-       if (leftlen == 0) {
-               ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-               return totcnt;
-       }
-       advoffset += cplen;
-       curbuf += cnt;
-
-       /*
-        * Display EEPROM configuration for the board.
-        */
-       cp = boardp->prtbuf;
-       if (ASC_NARROW_BOARD(boardp)) {
-               cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
-       } else {
-               cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
-       }
-       ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-       totcnt += cnt;
-       leftlen -= cnt;
-       if (leftlen == 0) {
-               ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-               return totcnt;
-       }
-       advoffset += cplen;
-       curbuf += cnt;
-
-       /*
-        * Display driver configuration and information for the board.
-        */
-       cp = boardp->prtbuf;
-       cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
-       ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-       totcnt += cnt;
-       leftlen -= cnt;
-       if (leftlen == 0) {
-               ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-               return totcnt;
-       }
-       advoffset += cplen;
-       curbuf += cnt;
-
-#ifdef ADVANSYS_STATS
-       /*
-        * Display driver statistics for the board.
-        */
-       cp = boardp->prtbuf;
-       cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
-       ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
-       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-       totcnt += cnt;
-       leftlen -= cnt;
-       if (leftlen == 0) {
-               ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-               return totcnt;
-       }
-       advoffset += cplen;
-       curbuf += cnt;
-
-       /*
-        * Display driver statistics for each target.
-        */
-       for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
-               cp = boardp->prtbuf;
-               cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
-               ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
-               cnt =
-                   asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
-                                 cplen);
-               totcnt += cnt;
-               leftlen -= cnt;
-               if (leftlen == 0) {
-                       ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-                       return totcnt;
-               }
-               advoffset += cplen;
-               curbuf += cnt;
-       }
-#endif /* ADVANSYS_STATS */
-
-       /*
-        * Display Asc Library dynamic configuration information
-        * for the board.
-        */
-       cp = boardp->prtbuf;
-       if (ASC_NARROW_BOARD(boardp)) {
-               cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
-       } else {
-               cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
-       }
-       ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-       totcnt += cnt;
-       leftlen -= cnt;
-       if (leftlen == 0) {
-               ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-               return totcnt;
-       }
-       advoffset += cplen;
-       curbuf += cnt;
-
-       ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-
-       return totcnt;
-}
-#endif /* CONFIG_PROC_FS */
+}
 
 /*
- * advansys_info()
- *
- * Return suitable for printing on the console with the argument
- * adapter's configuration information.
+ * asc_prt_hex()
  *
- * Note: The information line should not exceed ASC_INFO_SIZE bytes,
- * otherwise the static 'info' array will be overrun.
+ * Print hexadecimal output in 4 byte groupings 32 bytes
+ * or 8 double-words per line.
  */
-static const char *advansys_info(struct Scsi_Host *shost)
+static void asc_prt_hex(char *f, uchar *s, int l)
 {
-       static char info[ASC_INFO_SIZE];
-       asc_board_t *boardp;
-       ASC_DVC_VAR *asc_dvc_varp;
-       ADV_DVC_VAR *adv_dvc_varp;
-       char *busname;
-       int iolen;
-       char *widename = NULL;
+       int i;
+       int j;
+       int k;
+       int m;
 
-       boardp = ASC_BOARDP(shost);
-       if (ASC_NARROW_BOARD(boardp)) {
-               asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-               ASC_DBG(1, "advansys_info: begin\n");
-               if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
-                       if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
-                           ASC_IS_ISAPNP) {
-                               busname = "ISA PnP";
-                       } else {
-                               busname = "ISA";
-                       }
-                       /* Don't reference 'shost->n_io_port'; It may be truncated. */
-                       sprintf(info,
-                               "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
-                               ASC_VERSION, busname,
-                               (ulong)shost->io_port,
-                               (ulong)shost->io_port + boardp->asc_n_io_port -
-                               1, shost->irq, shost->dma_channel);
+       printk("%s: (%d bytes)\n", f, l);
+
+       for (i = 0; i < l; i += 32) {
+
+               /* Display a maximum of 8 double-words per line. */
+               if ((k = (l - i) / 4) >= 8) {
+                       k = 8;
+                       m = 0;
                } else {
-                       if (asc_dvc_varp->bus_type & ASC_IS_VL) {
-                               busname = "VL";
-                       } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
-                               busname = "EISA";
-                       } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-                               if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
-                                   == ASC_IS_PCI_ULTRA) {
-                                       busname = "PCI Ultra";
-                               } else {
-                                       busname = "PCI";
-                               }
-                       } else {
-                               busname = "?";
-                               ASC_PRINT2
-                                   ("advansys_info: board %d: unknown bus type %d\n",
-                                    boardp->id, asc_dvc_varp->bus_type);
-                       }
-                       /* Don't reference 'shost->n_io_port'; It may be truncated. */
-                       sprintf(info,
-                               "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
-                               ASC_VERSION, busname,
-                               (ulong)shost->io_port,
-                               (ulong)shost->io_port + boardp->asc_n_io_port -
-                               1, shost->irq);
+                       m = (l - i) % 4;
                }
-       } else {
-               /*
-                * Wide Adapter Information
-                *
-                * Memory-mapped I/O is used instead of I/O space to access
-                * the adapter, but display the I/O Port range. The Memory
-                * I/O address is displayed through the driver /proc file.
-                */
-               adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-               if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-                       iolen = ADV_3550_IOLEN;
-                       widename = "Ultra-Wide";
-               } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-                       iolen = ADV_38C0800_IOLEN;
-                       widename = "Ultra2-Wide";
-               } else {
-                       iolen = ADV_38C1600_IOLEN;
-                       widename = "Ultra3-Wide";
+
+               for (j = 0; j < k; j++) {
+                       printk(" %2.2X%2.2X%2.2X%2.2X",
+                              (unsigned)s[i + (j * 4)],
+                              (unsigned)s[i + (j * 4) + 1],
+                              (unsigned)s[i + (j * 4) + 2],
+                              (unsigned)s[i + (j * 4) + 3]);
                }
-               sprintf(info,
-                       "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
-                       ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
-                       (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
+
+               switch (m) {
+               case 0:
+               default:
+                       break;
+               case 1:
+                       printk(" %2.2X", (unsigned)s[i + (j * 4)]);
+                       break;
+               case 2:
+                       printk(" %2.2X%2.2X",
+                              (unsigned)s[i + (j * 4)],
+                              (unsigned)s[i + (j * 4) + 1]);
+                       break;
+               case 3:
+                       printk(" %2.2X%2.2X%2.2X",
+                              (unsigned)s[i + (j * 4) + 1],
+                              (unsigned)s[i + (j * 4) + 2],
+                              (unsigned)s[i + (j * 4) + 3]);
+                       break;
+               }
+
+               printk("\n");
        }
-       ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
-       ASC_DBG(1, "advansys_info: end\n");
-       return info;
 }
 
 /*
- * advansys_queuecommand() - interrupt-driven I/O entrypoint.
- *
- * This function always returns 0. Command return status is saved
- * in the 'scp' result field.
+ * asc_prt_asc_scsi_q()
  */
-static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
+static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
 {
-       struct Scsi_Host *shost;
-       asc_board_t *boardp;
-       ulong flags;
-       struct scsi_cmnd *done_scp;
+       ASC_SG_HEAD *sgp;
+       int i;
 
-       shost = scp->device->host;
-       boardp = ASC_BOARDP(shost);
-       ASC_STATS(shost, queuecommand);
+       printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
 
-       /* host_lock taken by mid-level prior to call but need to protect */
-       /* against own ISR */
-       spin_lock_irqsave(&boardp->lock, flags);
+       printk
+           (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
+            q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
+            q->q2.tag_code);
 
-       /*
-        * Block new commands while handling a reset or abort request.
-        */
-       if (boardp->flags & ASC_HOST_IN_RESET) {
-               ASC_DBG1(1,
-                        "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
-                        (ulong)scp);
-               scp->result = HOST_BYTE(DID_RESET);
+       printk
+           (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+            (ulong)le32_to_cpu(q->q1.data_addr),
+            (ulong)le32_to_cpu(q->q1.data_cnt),
+            (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
 
-               /*
-                * Add blocked requests to the board's 'done' queue. The queued
-                * requests will be completed at the end of the abort or reset
-                * handling.
-                */
-               asc_enqueue(&boardp->done, scp, ASC_BACK);
-               spin_unlock_irqrestore(&boardp->lock, flags);
-               return 0;
-       }
+       printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
+              (ulong)q->cdbptr, q->q2.cdb_len,
+              (ulong)q->sg_head, q->q1.sg_queue_cnt);
 
-       /*
-        * Attempt to execute any waiting commands for the board.
-        */
-       if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-               ASC_DBG(1,
-                       "advansys_queuecommand: before asc_execute_queue() waiting\n");
-               asc_execute_queue(&boardp->waiting);
-       }
+       if (q->sg_head) {
+               sgp = q->sg_head;
+               printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
+               printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
+                      sgp->queue_cnt);
+               for (i = 0; i < sgp->entry_cnt; i++) {
+                       printk(" [%u]: addr 0x%lx, bytes %lu\n",
+                              i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
+                              (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
+               }
 
-       /*
-        * Save the function pointer to Linux mid-level 'done' function
-        * and attempt to execute the command.
-        *
-        * If ASC_NOERROR is returned the request has been added to the
-        * board's 'active' queue and will be completed by the interrupt
-        * handler.
-        *
-        * If ASC_BUSY is returned add the request to the board's per
-        * target waiting list. This is the first time the request has
-        * been tried. Add it to the back of the waiting list. It will be
-        * retried later.
-        *
-        * If an error occurred, the request will have been placed on the
-        * board's 'done' queue and must be completed before returning.
-        */
-       scp->scsi_done = done;
-       switch (asc_execute_scsi_cmnd(scp)) {
-       case ASC_NOERROR:
-               break;
-       case ASC_BUSY:
-               asc_enqueue(&boardp->waiting, scp, ASC_BACK);
-               break;
-       case ASC_ERROR:
-       default:
-               done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
-               /* Interrupts could be enabled here. */
-               asc_scsi_done_list(done_scp);
-               break;
        }
-       spin_unlock_irqrestore(&boardp->lock, flags);
-
-       return 0;
 }
 
 /*
- * advansys_reset()
- *
- * Reset the bus associated with the command 'scp'.
- *
- * This function runs its own thread. Interrupts must be blocked but
- * sleeping is allowed and no locking other than for host structures is
- * required. Returns SUCCESS or FAILED.
+ * asc_prt_asc_qdone_info()
  */
-static int advansys_reset(struct scsi_cmnd *scp)
+static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
 {
-       struct Scsi_Host *shost;
-       asc_board_t *boardp;
-       ASC_DVC_VAR *asc_dvc_varp;
-       ADV_DVC_VAR *adv_dvc_varp;
-       ulong flags;
-       struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
-       struct scsi_cmnd *tscp, *new_last_scp;
-       int status;
-       int ret = SUCCESS;
+       printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
+       printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
+              (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+              q->d2.tag_code);
+       printk
+           (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
+            q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
+}
 
-       ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
+/*
+ * asc_prt_adv_sgblock()
+ *
+ * Display an ADV_SG_BLOCK structure.
+ */
+static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+{
+       int i;
 
-#ifdef ADVANSYS_STATS
-       if (scp->device->host != NULL) {
-               ASC_STATS(scp->device->host, reset);
+       printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
+              (ulong)b, sgblockno);
+       printk("  sg_cnt %u, sg_ptr 0x%lx\n",
+              b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
+       BUG_ON(b->sg_cnt > NO_OF_SG_PER_BLOCK);
+       if (b->sg_ptr != 0)
+               BUG_ON(b->sg_cnt != NO_OF_SG_PER_BLOCK);
+       for (i = 0; i < b->sg_cnt; i++) {
+               printk("  [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
+                      i, (ulong)b->sg_list[i].sg_addr,
+                      (ulong)b->sg_list[i].sg_count);
        }
-#endif /* ADVANSYS_STATS */
+}
 
-       if ((shost = scp->device->host) == NULL) {
-               scp->result = HOST_BYTE(DID_ERROR);
-               return FAILED;
-       }
+/*
+ * asc_prt_adv_scsi_req_q()
+ *
+ * Display an ADV_SCSI_REQ_Q structure.
+ */
+static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
+{
+       int sg_blk_cnt;
+       struct asc_sg_block *sg_ptr;
 
-       boardp = ASC_BOARDP(shost);
+       printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
 
-       ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
-                  boardp->id);
-       /*
-        * Check for re-entrancy.
-        */
-       spin_lock_irqsave(&boardp->lock, flags);
-       if (boardp->flags & ASC_HOST_IN_RESET) {
-               spin_unlock_irqrestore(&boardp->lock, flags);
-               return FAILED;
-       }
-       boardp->flags |= ASC_HOST_IN_RESET;
-       spin_unlock_irqrestore(&boardp->lock, flags);
+       printk("  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+              q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
 
-       if (ASC_NARROW_BOARD(boardp)) {
-               /*
-                * Narrow Board
-                */
-               asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+       printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+              q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
 
-               /*
-                * Reset the chip and SCSI bus.
-                */
-               ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
-               status = AscInitAsc1000Driver(asc_dvc_varp);
+       printk("  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+              (ulong)le32_to_cpu(q->data_cnt),
+              (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
 
-               /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
-               if (asc_dvc_varp->err_code) {
-                       ASC_PRINT2
-                           ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
-                            boardp->id, asc_dvc_varp->err_code);
-                       ret = FAILED;
-               } else if (status) {
-                       ASC_PRINT2
-                           ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
-                            boardp->id, status);
-               } else {
-                       ASC_PRINT1
-                           ("advansys_reset: board %d: SCSI bus reset successful.\n",
-                            boardp->id);
-               }
+       printk
+           ("  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+            q->cdb_len, q->done_status, q->host_status, q->scsi_status);
 
-               ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-               spin_lock_irqsave(&boardp->lock, flags);
+       printk("  sg_working_ix 0x%x, target_cmd %u\n",
+              q->sg_working_ix, q->target_cmd);
 
-       } else {
-               /*
-                * Wide Board
-                *
-                * If the suggest reset bus flags are set, then reset the bus.
-                * Otherwise only reset the device.
-                */
-               adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+       printk("  scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
+              (ulong)le32_to_cpu(q->scsiq_rptr),
+              (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
 
-               /*
-                * Reset the target's SCSI bus.
-                */
-               ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
-               switch (AdvResetChipAndSB(adv_dvc_varp)) {
-               case ASC_TRUE:
-                       ASC_PRINT1
-                           ("advansys_reset: board %d: SCSI bus reset successful.\n",
-                            boardp->id);
-                       break;
-               case ASC_FALSE:
-               default:
-                       ASC_PRINT1
-                           ("advansys_reset: board %d: SCSI bus reset error.\n",
-                            boardp->id);
-                       ret = FAILED;
-                       break;
+       /* Display the request's ADV_SG_BLOCK structures. */
+       if (q->sg_list_ptr != NULL) {
+               sg_blk_cnt = 0;
+               while (1) {
+                       /*
+                        * 'sg_ptr' is a physical address. Convert it to a virtual
+                        * address by indexing 'sg_blk_cnt' into the virtual address
+                        * array 'sg_list_ptr'.
+                        *
+                        * XXX - Assumes all SG physical blocks are virtually contiguous.
+                        */
+                       sg_ptr =
+                           &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
+                       asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+                       if (sg_ptr->sg_ptr == 0) {
+                               break;
+                       }
+                       sg_blk_cnt++;
                }
-               spin_lock_irqsave(&boardp->lock, flags);
-               (void)AdvISR(adv_dvc_varp);
        }
-       /* Board lock is held. */
+}
+#endif /* ADVANSYS_DEBUG */
 
-       /*
-        * Dequeue all board 'done' requests. A pointer to the last request
-        * is returned in 'last_scp'.
-        */
-       done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
+/*
+ * The advansys chip/microcode contains a 32-bit identifier for each command
+ * known as the 'srb'.  I don't know what it stands for.  The driver used
+ * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it
+ * with bus_to_virt.  Now the driver keeps a per-host map of integers to
+ * pointers.  It auto-expands when full, unless it can't allocate memory.
+ * Note that an srb of 0 is treated specially by the chip/firmware, hence
+ * the return of i+1 in this routine, and the corresponding subtraction in
+ * the inverse routine.
+ */
+#define BAD_SRB 0
+static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr)
+{
+       int i;
+       void **new_ptr;
 
-       /*
-        * Dequeue all board 'active' requests for all devices and set
-        * the request status to DID_RESET. A pointer to the last request
-        * is returned in 'last_scp'.
-        */
-       if (done_scp == NULL) {
-               done_scp =
-                   asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
-               for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-                       tscp->result = HOST_BYTE(DID_RESET);
-               }
-       } else {
-               /* Append to 'done_scp' at the end with 'last_scp'. */
-               ASC_ASSERT(last_scp != NULL);
-               last_scp->host_scribble =
-                   (unsigned char *)asc_dequeue_list(&boardp->active,
-                                                     &new_last_scp,
-                                                     ASC_TID_ALL);
-               if (new_last_scp != NULL) {
-                       ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-                       for (tscp = REQPNEXT(last_scp); tscp;
-                            tscp = REQPNEXT(tscp)) {
-                               tscp->result = HOST_BYTE(DID_RESET);
-                       }
-                       last_scp = new_last_scp;
-               }
+       for (i = 0; i < asc_dvc->ptr_map_count; i++) {
+               if (!asc_dvc->ptr_map[i])
+                       goto out;
        }
 
-       /*
-        * Dequeue all 'waiting' requests and set the request status
-        * to DID_RESET.
-        */
-       if (done_scp == NULL) {
-               done_scp =
-                   asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
-               for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-                       tscp->result = HOST_BYTE(DID_RESET);
-               }
-       } else {
-               /* Append to 'done_scp' at the end with 'last_scp'. */
-               ASC_ASSERT(last_scp != NULL);
-               last_scp->host_scribble =
-                   (unsigned char *)asc_dequeue_list(&boardp->waiting,
-                                                     &new_last_scp,
-                                                     ASC_TID_ALL);
-               if (new_last_scp != NULL) {
-                       ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-                       for (tscp = REQPNEXT(last_scp); tscp;
-                            tscp = REQPNEXT(tscp)) {
-                               tscp->result = HOST_BYTE(DID_RESET);
-                       }
-                       last_scp = new_last_scp;
-               }
-       }
+       if (asc_dvc->ptr_map_count == 0)
+               asc_dvc->ptr_map_count = 1;
+       else
+               asc_dvc->ptr_map_count *= 2;
 
-       /* Save the time of the most recently completed reset. */
-       boardp->last_reset = jiffies;
+       new_ptr = krealloc(asc_dvc->ptr_map,
+                       asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC);
+       if (!new_ptr)
+               return BAD_SRB;
+       asc_dvc->ptr_map = new_ptr;
+ out:
+       ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i);
+       asc_dvc->ptr_map[i] = ptr;
+       return i + 1;
+}
 
-       /* Clear reset flag. */
-       boardp->flags &= ~ASC_HOST_IN_RESET;
-       spin_unlock_irqrestore(&boardp->lock, flags);
+static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb)
+{
+       void *ptr;
 
-       /*
-        * Complete all the 'done_scp' requests.
-        */
-       if (done_scp != NULL) {
-               asc_scsi_done_list(done_scp);
+       srb--;
+       if (srb >= asc_dvc->ptr_map_count) {
+               printk("advansys: bad SRB %u, max %u\n", srb,
+                                                       asc_dvc->ptr_map_count);
+               return NULL;
        }
-
-       ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
-
-       return ret;
+       ptr = asc_dvc->ptr_map[srb];
+       asc_dvc->ptr_map[srb] = NULL;
+       ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb);
+       return ptr;
 }
 
 /*
- * advansys_biosparam()
+ * advansys_info()
  *
- * Translate disk drive geometry if the "BIOS greater than 1 GB"
- * support is enabled for a drive.
+ * Return suitable for printing on the console with the argument
+ * adapter's configuration information.
  *
- * ip (information pointer) is an int array with the following definition:
- * ip[0]: heads
- * ip[1]: sectors
- * ip[2]: cylinders
+ * Note: The information line should not exceed ASC_INFO_SIZE bytes,
+ * otherwise the static 'info' array will be overrun.
  */
-static int
-advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
-                  sector_t capacity, int ip[])
+static const char *advansys_info(struct Scsi_Host *shost)
 {
-       asc_board_t *boardp;
+       static char info[ASC_INFO_SIZE];
+       struct asc_board *boardp = shost_priv(shost);
+       ASC_DVC_VAR *asc_dvc_varp;
+       ADV_DVC_VAR *adv_dvc_varp;
+       char *busname;
+       char *widename = NULL;
 
-       ASC_DBG(1, "advansys_biosparam: begin\n");
-       ASC_STATS(sdev->host, biosparam);
-       boardp = ASC_BOARDP(sdev->host);
        if (ASC_NARROW_BOARD(boardp)) {
-               if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
-                    ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
-                       ip[0] = 255;
-                       ip[1] = 63;
+               asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+               ASC_DBG(1, "begin\n");
+               if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+                       if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
+                           ASC_IS_ISAPNP) {
+                               busname = "ISA PnP";
+                       } else {
+                               busname = "ISA";
+                       }
+                       sprintf(info,
+                               "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
+                               ASC_VERSION, busname,
+                               (ulong)shost->io_port,
+                               (ulong)shost->io_port + ASC_IOADR_GAP - 1,
+                               boardp->irq, shost->dma_channel);
                } else {
-                       ip[0] = 64;
-                       ip[1] = 32;
+                       if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+                               busname = "VL";
+                       } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+                               busname = "EISA";
+                       } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+                               if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+                                   == ASC_IS_PCI_ULTRA) {
+                                       busname = "PCI Ultra";
+                               } else {
+                                       busname = "PCI";
+                               }
+                       } else {
+                               busname = "?";
+                               shost_printk(KERN_ERR, shost, "unknown bus "
+                                       "type %d\n", asc_dvc_varp->bus_type);
+                       }
+                       sprintf(info,
+                               "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
+                               ASC_VERSION, busname, (ulong)shost->io_port,
+                               (ulong)shost->io_port + ASC_IOADR_GAP - 1,
+                               boardp->irq);
                }
        } else {
-               if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
-                    BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
-                       ip[0] = 255;
-                       ip[1] = 63;
+               /*
+                * Wide Adapter Information
+                *
+                * Memory-mapped I/O is used instead of I/O space to access
+                * the adapter, but display the I/O Port range. The Memory
+                * I/O address is displayed through the driver /proc file.
+                */
+               adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+               if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+                       widename = "Ultra-Wide";
+               } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+                       widename = "Ultra2-Wide";
                } else {
-                       ip[0] = 64;
-                       ip[1] = 32;
+                       widename = "Ultra3-Wide";
                }
+               sprintf(info,
+                       "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
+                       ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
+                       (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, boardp->irq);
        }
-       ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
-       ASC_DBG(1, "advansys_biosparam: end\n");
-       return 0;
+       BUG_ON(strlen(info) >= ASC_INFO_SIZE);
+       ASC_DBG(1, "end\n");
+       return info;
 }
 
-static int __init advansys_detect(struct scsi_host_template *tpnt);
-static int advansys_release(struct Scsi_Host *shp);
-
-static struct scsi_host_template driver_template = {
-       .proc_name = "advansys",
 #ifdef CONFIG_PROC_FS
-       .proc_info = advansys_proc_info,
-#endif
-       .name = "advansys",
-       .detect = advansys_detect,
-       .release = advansys_release,
-       .info = advansys_info,
-       .queuecommand = advansys_queuecommand,
-       .eh_bus_reset_handler = advansys_reset,
-       .bios_param = advansys_biosparam,
-       .slave_configure = advansys_slave_configure,
-       /*
-        * Because the driver may control an ISA adapter 'unchecked_isa_dma'
-        * must be set. The flag will be cleared in advansys_detect for non-ISA
-        * adapters. Refer to the comment in scsi_module.c for more information.
-        */
-       .unchecked_isa_dma = 1,
-       /*
-        * All adapters controlled by this driver are capable of large
-        * scatter-gather lists. According to the mid-level SCSI documentation
-        * this obviates any performance gain provided by setting
-        * 'use_clustering'. But empirically while CPU utilization is increased
-        * by enabling clustering, I/O throughput increases as well.
-        */
-       .use_clustering = ENABLE_CLUSTERING,
-};
-
-#include "scsi_module.c"
-
 /*
- * --- Miscellaneous Driver Functions
- */
+ * asc_prt_line()
+ *
+ * If 'cp' is NULL print to the console, otherwise print to a buffer.
+ *
+ * Return 0 if printing to the console, otherwise return the number of
+ * bytes written to the buffer.
+ *
+ * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
+ * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
+ */
+static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
+{
+       va_list args;
+       int ret;
+       char s[ASC_PRTLINE_SIZE];
+
+       va_start(args, fmt);
+       ret = vsprintf(s, fmt, args);
+       BUG_ON(ret >= ASC_PRTLINE_SIZE);
+       if (buf == NULL) {
+               (void)printk(s);
+               ret = 0;
+       } else {
+               ret = min(buflen, ret);
+               memcpy(buf, s, ret);
+       }
+       va_end(args);
+       return ret;
+}
 
 /*
- * First-level interrupt handler.
+ * asc_prt_board_devices()
+ *
+ * Print driver information for devices attached to the board.
  *
- * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
- * all boards are currently checked for interrupts on each interrupt, 'dev_id'
- * is not referenced. 'dev_id' could be used to identify an interrupt passed
- * to the AdvanSys driver which is for a device sharing an interrupt with
- * an AdvanSys adapter.
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
  */
-static irqreturn_t advansys_interrupt(int irq, void *dev_id)
+static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
 {
-       ulong flags;
+       struct asc_board *boardp = shost_priv(shost);
+       int leftlen;
+       int totlen;
+       int len;
+       int chip_scsi_id;
        int i;
-       asc_board_t *boardp;
-       struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
-       struct scsi_cmnd *new_last_scp;
-       struct Scsi_Host *shost;
 
-       ASC_DBG(1, "advansys_interrupt: begin\n");
+       leftlen = cplen;
+       totlen = len = 0;
 
-       /*
-        * Check for interrupts on all boards.
-        * AscISR() will call asc_isr_callback().
-        */
-       for (i = 0; i < asc_board_count; i++) {
-               shost = asc_host[i];
-               boardp = ASC_BOARDP(shost);
-               ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
-                        i, (ulong)boardp);
-               spin_lock_irqsave(&boardp->lock, flags);
-               if (ASC_NARROW_BOARD(boardp)) {
-                       /*
-                        * Narrow Board
-                        */
-                       if (AscIsIntPending(shost->io_port)) {
-                               ASC_STATS(shost, interrupt);
-                               ASC_DBG(1,
-                                       "advansys_interrupt: before AscISR()\n");
-                               AscISR(&boardp->dvc_var.asc_dvc_var);
-                       }
-               } else {
-                       /*
-                        * Wide Board
-                        */
-                       ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
-                       if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
-                               ASC_STATS(shost, interrupt);
-                       }
-               }
+       len = asc_prt_line(cp, leftlen,
+                          "\nDevice Information for AdvanSys SCSI Host %d:\n",
+                          shost->host_no);
+       ASC_PRT_NEXT();
 
-               /*
-                * Start waiting requests and create a list of completed requests.
-                *
-                * If a reset request is being performed for the board, the reset
-                * handler will complete pending requests after it has completed.
-                */
-               if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
-                       ASC_DBG2(1,
-                                "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
-                                (ulong)done_scp, (ulong)last_scp);
-
-                       /* Start any waiting commands for the board. */
-                       if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-                               ASC_DBG(1,
-                                       "advansys_interrupt: before asc_execute_queue()\n");
-                               asc_execute_queue(&boardp->waiting);
-                       }
+       if (ASC_NARROW_BOARD(boardp)) {
+               chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+       } else {
+               chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+       }
 
-                       /*
-                        * Add to the list of requests that must be completed.
-                        *
-                        * 'done_scp' will always be NULL on the first iteration
-                        * of this loop. 'last_scp' is set at the same time as
-                        * 'done_scp'.
-                        */
-                       if (done_scp == NULL) {
-                               done_scp =
-                                   asc_dequeue_list(&boardp->done, &last_scp,
-                                                    ASC_TID_ALL);
-                       } else {
-                               ASC_ASSERT(last_scp != NULL);
-                               last_scp->host_scribble =
-                                   (unsigned char *)asc_dequeue_list(&boardp->
-                                                                     done,
-                                                                     &new_last_scp,
-                                                                     ASC_TID_ALL);
-                               if (new_last_scp != NULL) {
-                                       ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-                                       last_scp = new_last_scp;
-                               }
-                       }
+       len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
+                       len = asc_prt_line(cp, leftlen, " %X,", i);
+                       ASC_PRT_NEXT();
                }
-               spin_unlock_irqrestore(&boardp->lock, flags);
        }
+       len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
+       ASC_PRT_NEXT();
 
-       /*
-        * If interrupts were enabled on entry, then they
-        * are now enabled here.
-        *
-        * Complete all requests on the done list.
-        */
-
-       asc_scsi_done_list(done_scp);
-
-       ASC_DBG(1, "advansys_interrupt: end\n");
-       return IRQ_HANDLED;
+       return totlen;
 }
 
 /*
- * Set the number of commands to queue per device for the
- * specified host adapter.
+ * Display Wide Board BIOS Information.
  */
-static int advansys_slave_configure(struct scsi_device *device)
+static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
 {
-       asc_board_t *boardp;
+       struct asc_board *boardp = shost_priv(shost);
+       int leftlen;
+       int totlen;
+       int len;
+       ushort major, minor, letter;
+
+       leftlen = cplen;
+       totlen = len = 0;
+
+       len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
+       ASC_PRT_NEXT();
 
-       boardp = ASC_BOARDP(device->host);
-       boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
        /*
-        * Save a pointer to the device and set its initial/maximum
-        * queue depth.  Only save the pointer for a lun0 dev though.
+        * If the BIOS saved a valid signature, then fill in
+        * the BIOS code segment base address.
         */
-       if (device->lun == 0)
-               boardp->device[device->id] = device;
-       if (device->tagged_supported) {
-               if (ASC_NARROW_BOARD(boardp)) {
-                       scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
-                                               boardp->dvc_var.asc_dvc_var.
-                                               max_dvc_qng[device->id]);
-               } else {
-                       scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
-                                               boardp->dvc_var.adv_dvc_var.
-                                               max_dvc_qng);
-               }
+       if (boardp->bios_signature != 0x55AA) {
+               len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
+               ASC_PRT_NEXT();
+               len = asc_prt_line(cp, leftlen,
+                                  "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
+               ASC_PRT_NEXT();
+               len = asc_prt_line(cp, leftlen,
+                                  "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
+               ASC_PRT_NEXT();
        } else {
-               scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
-       }
-       ASC_DBG4(1,
-                "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
-                (ulong)device, (ulong)boardp, device->id, device->queue_depth);
-       return 0;
-}
-
-/*
- * Complete all requests on the singly linked list pointed
- * to by 'scp'.
- *
- * Interrupts can be enabled on entry.
- */
-static void asc_scsi_done_list(struct scsi_cmnd *scp)
-{
-       struct scsi_cmnd *tscp;
-
-       ASC_DBG(2, "asc_scsi_done_list: begin\n");
-       while (scp != NULL) {
-               asc_board_t *boardp;
-               struct device *dev;
-
-               ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
-               tscp = REQPNEXT(scp);
-               scp->host_scribble = NULL;
-
-               boardp = ASC_BOARDP(scp->device->host);
-
-               if (ASC_NARROW_BOARD(boardp))
-                       dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
-               else
-                       dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
-
-               if (scp->use_sg)
-                       dma_unmap_sg(dev,
-                                    (struct scatterlist *)scp->request_buffer,
-                                    scp->use_sg, scp->sc_data_direction);
-               else if (scp->request_bufflen)
-                       dma_unmap_single(dev, scp->SCp.dma_handle,
-                                        scp->request_bufflen,
-                                        scp->sc_data_direction);
-
-               ASC_STATS(scp->device->host, done);
-               ASC_ASSERT(scp->scsi_done != NULL);
+               major = (boardp->bios_version >> 12) & 0xF;
+               minor = (boardp->bios_version >> 8) & 0xF;
+               letter = (boardp->bios_version & 0xFF);
 
-               scp->scsi_done(scp);
+               len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
+                                  major, minor,
+                                  letter >= 26 ? '?' : letter + 'A');
+               ASC_PRT_NEXT();
 
-               scp = tscp;
+               /*
+                * Current available ROM BIOS release is 3.1I for UW
+                * and 3.2I for U2W. This code doesn't differentiate
+                * UW and U2W boards.
+                */
+               if (major < 3 || (major <= 3 && minor < 1) ||
+                   (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
+                       len = asc_prt_line(cp, leftlen,
+                                          "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
+                       ASC_PRT_NEXT();
+                       len = asc_prt_line(cp, leftlen,
+                                          "ftp://ftp.connectcom.net/pub\n");
+                       ASC_PRT_NEXT();
+               }
        }
-       ASC_DBG(2, "asc_scsi_done_list: done\n");
-       return;
+
+       return totlen;
 }
 
 /*
- * Execute a single 'Scsi_Cmnd'.
- *
- * The function 'done' is called when the request has been completed.
- *
- * Scsi_Cmnd:
- *
- *  host - board controlling device
- *  device - device to send command
- *  target - target of device
- *  lun - lun of device
- *  cmd_len - length of SCSI CDB
- *  cmnd - buffer for SCSI 8, 10, or 12 byte CDB
- *  use_sg - if non-zero indicates scatter-gather request with use_sg elements
+ * Add serial number to information bar if signature AAh
+ * is found in at bit 15-9 (7 bits) of word 1.
  *
- *  if (use_sg == 0) {
- *    request_buffer - buffer address for request
- *    request_bufflen - length of request buffer
- *  } else {
- *    request_buffer - pointer to scatterlist structure
- *  }
+ * Serial Number consists fo 12 alpha-numeric digits.
  *
- *  sense_buffer - sense command buffer
+ *       1 - Product type (A,B,C,D..)  Word0: 15-13 (3 bits)
+ *       2 - MFG Location (A,B,C,D..)  Word0: 12-10 (3 bits)
+ *     3-4 - Product ID (0-99)         Word0: 9-0 (10 bits)
+ *       5 - Product revision (A-J)    Word0:  "         "
  *
- *  result (4 bytes of an int):
- *    Byte Meaning
- *    0 SCSI Status Byte Code
- *    1 SCSI One Byte Message Code
- *    2 Host Error Code
- *    3 Mid-Level Error Code
+ *           Signature                 Word1: 15-9 (7 bits)
+ *       6 - Year (0-9)                Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
+ *     7-8 - Week of the year (1-52)   Word1: 5-0 (6 bits)
  *
- *  host driver fields:
- *    SCp - Scsi_Pointer used for command processing status
- *    scsi_done - used to save caller's done function
- *    host_scribble - used for pointer to another struct scsi_cmnd
+ *    9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
  *
- * If this function returns ASC_NOERROR the request has been enqueued
- * on the board's 'active' queue and will be completed from the
- * interrupt handler.
+ * Note 1: Only production cards will have a serial number.
  *
- * If this function returns ASC_NOERROR the request has been enqueued
- * on the board's 'done' queue and must be completed by the caller.
+ * Note 2: Signature is most significant 7 bits (0xFE).
  *
- * If ASC_BUSY is returned the request will be enqueued by the
- * caller on the target's waiting queue and re-tried later.
+ * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
  */
-static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
+static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
 {
-       asc_board_t *boardp;
-       ASC_DVC_VAR *asc_dvc_varp;
-       ADV_DVC_VAR *adv_dvc_varp;
-       ADV_SCSI_REQ_Q *adv_scsiqp;
-       struct scsi_device *device;
-       int ret;
-
-       ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
-                (ulong)scp, (ulong)scp->scsi_done);
-
-       boardp = ASC_BOARDP(scp->device->host);
-       device = boardp->device[scp->device->id];
+       ushort w, num;
 
-       if (ASC_NARROW_BOARD(boardp)) {
+       if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
+               return ASC_FALSE;
+       } else {
                /*
-                * Build and execute Narrow Board request.
+                * First word - 6 digits.
                 */
+               w = serialnum[0];
 
-               asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-
-               /*
-                * Build Asc Library request structure using the
-                * global structures 'asc_scsi_req' and 'asc_sg_head'.
-                *
-                * If an error is returned, then the request has been
-                * queued on the board done queue. It will be completed
-                * by the caller.
-                *
-                * asc_build_req() can not return ASC_BUSY.
-                */
-               if (asc_build_req(boardp, scp) == ASC_ERROR) {
-                       ASC_STATS(scp->device->host, build_error);
-                       return ASC_ERROR;
+               /* Product type - 1st digit. */
+               if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
+                       /* Product type is P=Prototype */
+                       *cp += 0x8;
                }
+               cp++;
+
+               /* Manufacturing location - 2nd digit. */
+               *cp++ = 'A' + ((w & 0x1C00) >> 10);
+
+               /* Product ID - 3rd, 4th digits. */
+               num = w & 0x3FF;
+               *cp++ = '0' + (num / 100);
+               num %= 100;
+               *cp++ = '0' + (num / 10);
+
+               /* Product revision - 5th digit. */
+               *cp++ = 'A' + (num % 10);
 
                /*
-                * Execute the command. If there is no error, add the command
-                * to the active queue.
-                */
-               switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
-               case ASC_NOERROR:
-                       ASC_STATS(scp->device->host, exe_noerror);
-                       /*
-                        * Increment monotonically increasing per device successful
-                        * request counter. Wrapping doesn't matter.
-                        */
-                       boardp->reqcnt[scp->device->id]++;
-                       asc_enqueue(&boardp->active, scp, ASC_BACK);
-                       ASC_DBG(1,
-                               "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
-                       break;
-               case ASC_BUSY:
-                       /*
-                        * Caller will enqueue request on the target's waiting queue
-                        * and retry later.
-                        */
-                       ASC_STATS(scp->device->host, exe_busy);
-                       break;
-               case ASC_ERROR:
-                       ASC_PRINT2
-                           ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
-                            boardp->id, asc_dvc_varp->err_code);
-                       ASC_STATS(scp->device->host, exe_error);
-                       scp->result = HOST_BYTE(DID_ERROR);
-                       asc_enqueue(&boardp->done, scp, ASC_BACK);
-                       break;
-               default:
-                       ASC_PRINT2
-                           ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
-                            boardp->id, asc_dvc_varp->err_code);
-                       ASC_STATS(scp->device->host, exe_unknown);
-                       scp->result = HOST_BYTE(DID_ERROR);
-                       asc_enqueue(&boardp->done, scp, ASC_BACK);
-                       break;
-               }
-       } else {
-               /*
-                * Build and execute Wide Board request.
+                * Second word
                 */
-               adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+               w = serialnum[1];
 
                /*
-                * Build and get a pointer to an Adv Library request structure.
+                * Year - 6th digit.
                 *
-                * If the request is successfully built then send it below,
-                * otherwise return with an error.
+                * If bit 15 of third word is set, then the
+                * last digit of the year is greater than 7.
                 */
-               switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
-               case ASC_NOERROR:
-                       ASC_DBG(3,
-                               "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
-                       break;
-               case ASC_BUSY:
-                       ASC_DBG(1,
-                               "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
-                       /*
-                        * If busy is returned the request has not been enqueued.
-                        * It will be enqueued by the caller on the target's waiting
-                        * queue and retried later.
-                        *
-                        * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
-                        * count wide board busy conditions. They are updated in
-                        * adv_build_req and adv_get_sglist, respectively.
-                        */
-                       return ASC_BUSY;
-               case ASC_ERROR:
-                       /* 
-                        * If an error is returned, then the request has been
-                        * queued on the board done queue. It will be completed
-                        * by the caller.
-                        */
-               default:
-                       ASC_DBG(1,
-                               "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
-                       ASC_STATS(scp->device->host, build_error);
-                       return ASC_ERROR;
+               if (serialnum[2] & 0x8000) {
+                       *cp++ = '8' + ((w & 0x1C0) >> 6);
+               } else {
+                       *cp++ = '0' + ((w & 0x1C0) >> 6);
                }
 
-               /*
-                * Execute the command. If there is no error, add the command
-                * to the active queue.
-                */
-               switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
-               case ASC_NOERROR:
-                       ASC_STATS(scp->device->host, exe_noerror);
-                       /*
-                        * Increment monotonically increasing per device successful
-                        * request counter. Wrapping doesn't matter.
-                        */
-                       boardp->reqcnt[scp->device->id]++;
-                       asc_enqueue(&boardp->active, scp, ASC_BACK);
-                       ASC_DBG(1,
-                               "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
-                       break;
-               case ASC_BUSY:
-                       /*
-                        * Caller will enqueue request on the target's waiting queue
-                        * and retry later.
-                        */
-                       ASC_STATS(scp->device->host, exe_busy);
-                       break;
-               case ASC_ERROR:
-                       ASC_PRINT2
-                           ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
-                            boardp->id, adv_dvc_varp->err_code);
-                       ASC_STATS(scp->device->host, exe_error);
-                       scp->result = HOST_BYTE(DID_ERROR);
-                       asc_enqueue(&boardp->done, scp, ASC_BACK);
-                       break;
-               default:
-                       ASC_PRINT2
-                           ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
-                            boardp->id, adv_dvc_varp->err_code);
-                       ASC_STATS(scp->device->host, exe_unknown);
-                       scp->result = HOST_BYTE(DID_ERROR);
-                       asc_enqueue(&boardp->done, scp, ASC_BACK);
-                       break;
-               }
-       }
+               /* Week of year - 7th, 8th digits. */
+               num = w & 0x003F;
+               *cp++ = '0' + num / 10;
+               num %= 10;
+               *cp++ = '0' + num;
 
-       ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
-       return ret;
+               /*
+                * Third word
+                */
+               w = serialnum[2] & 0x7FFF;
+
+               /* Serial number - 9th digit. */
+               *cp++ = 'A' + (w / 1000);
+
+               /* 10th, 11th, 12th digits. */
+               num = w % 1000;
+               *cp++ = '0' + num / 100;
+               num %= 100;
+               *cp++ = '0' + num / 10;
+               num %= 10;
+               *cp++ = '0' + num;
+
+               *cp = '\0';     /* Null Terminate the string. */
+               return ASC_TRUE;
+       }
 }
 
 /*
- * Build a request structure for the Asc Library (Narrow Board).
+ * asc_prt_asc_board_eeprom()
  *
- * The global structures 'asc_scsi_q' and 'asc_sg_head' are
- * used to build the request.
+ * Print board EEPROM configuration.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
  *
- * If an error occurs, then queue the request on the board done
- * queue and return ASC_ERROR.
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
  */
-static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
+static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
 {
-       struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+       struct asc_board *boardp = shost_priv(shost);
+       ASC_DVC_VAR *asc_dvc_varp;
+       int leftlen;
+       int totlen;
+       int len;
+       ASCEEP_CONFIG *ep;
+       int i;
+#ifdef CONFIG_ISA
+       int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+#endif /* CONFIG_ISA */
+       uchar serialstr[13];
 
-       /*
-        * Mutually exclusive access is required to 'asc_scsi_q' and
-        * 'asc_sg_head' until after the request is started.
-        */
-       memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
+       asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+       ep = &boardp->eep_config.asc_eep;
 
-       /*
-        * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
-        */
-       asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
+       leftlen = cplen;
+       totlen = len = 0;
 
-       /*
-        * Build the ASC_SCSI_Q request.
-        *
-        * For narrow boards a CDB length maximum of 12 bytes
-        * is supported.
-        */
-       if (scp->cmd_len > ASC_MAX_CDB_LEN) {
-               ASC_PRINT3
-                   ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN  %d\n",
-                    boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
-               scp->result = HOST_BYTE(DID_ERROR);
-               asc_enqueue(&boardp->done, scp, ASC_BACK);
-               return ASC_ERROR;
-       }
-       asc_scsi_q.cdbptr = &scp->cmnd[0];
-       asc_scsi_q.q2.cdb_len = scp->cmd_len;
-       asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
-       asc_scsi_q.q1.target_lun = scp->device->lun;
-       asc_scsi_q.q2.target_ix =
-           ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
-       asc_scsi_q.q1.sense_addr =
-           cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-       asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+       len = asc_prt_line(cp, leftlen,
+                          "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+                          shost->host_no);
+       ASC_PRT_NEXT();
 
-       /*
-        * If there are any outstanding requests for the current target,
-        * then every 255th request send an ORDERED request. This heuristic
-        * tries to retain the benefit of request sorting while preventing
-        * request starvation. 255 is the max number of tags or pending commands
-        * a device may have outstanding.
-        *
-        * The request count is incremented below for every successfully
-        * started request.
-        *
-        */
-       if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
-           (boardp->reqcnt[scp->device->id] % 255) == 0) {
-               asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
+       if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
+           == ASC_TRUE) {
+               len =
+                   asc_prt_line(cp, leftlen, " Serial Number: %s\n",
+                                serialstr);
+               ASC_PRT_NEXT();
        } else {
-               asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
+               if (ep->adapter_info[5] == 0xBB) {
+                       len = asc_prt_line(cp, leftlen,
+                                          " Default Settings Used for EEPROM-less Adapter.\n");
+                       ASC_PRT_NEXT();
+               } else {
+                       len = asc_prt_line(cp, leftlen,
+                                          " Serial Number Signature Not Present.\n");
+                       ASC_PRT_NEXT();
+               }
        }
 
-       /*
-        * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
-        * buffer command.
-        */
-       if (scp->use_sg == 0) {
-               /*
-                * CDB request of single contiguous buffer.
-                */
-               ASC_STATS(scp->device->host, cont_cnt);
-               scp->SCp.dma_handle = scp->request_bufflen ?
-                   dma_map_single(dev, scp->request_buffer,
-                                  scp->request_bufflen,
-                                  scp->sc_data_direction) : 0;
-               asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
-               asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
-               ASC_STATS_ADD(scp->device->host, cont_xfer,
-                             ASC_CEILING(scp->request_bufflen, 512));
-               asc_scsi_q.q1.sg_queue_cnt = 0;
-               asc_scsi_q.sg_head = NULL;
-       } else {
-               /*
-                * CDB scatter-gather request list.
-                */
-               int sgcnt;
-               int use_sg;
-               struct scatterlist *slp;
+       len = asc_prt_line(cp, leftlen,
+                          " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+                          ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
+                          ep->max_tag_qng);
+       ASC_PRT_NEXT();
 
-               slp = (struct scatterlist *)scp->request_buffer;
-               use_sg =
-                   dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+       len = asc_prt_line(cp, leftlen,
+                          " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
+       ASC_PRT_NEXT();
 
-               if (use_sg > scp->device->host->sg_tablesize) {
-                       ASC_PRINT3
-                           ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
-                            boardp->id, use_sg,
-                            scp->device->host->sg_tablesize);
-                       dma_unmap_sg(dev, slp, scp->use_sg,
-                                    scp->sc_data_direction);
-                       scp->result = HOST_BYTE(DID_ERROR);
-                       asc_enqueue(&boardp->done, scp, ASC_BACK);
-                       return ASC_ERROR;
-               }
+       len = asc_prt_line(cp, leftlen, " Target ID:           ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %d", i);
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               ASC_STATS(scp->device->host, sg_cnt);
+       len = asc_prt_line(cp, leftlen, " Disconnects:         ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (ep->
+                                   disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               /*
-                * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
-                * structure to point to it.
-                */
-               memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
+       len = asc_prt_line(cp, leftlen, " Command Queuing:     ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (ep->
+                                   use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               asc_scsi_q.q1.cntl |= QC_SG_HEAD;
-               asc_scsi_q.sg_head = &asc_sg_head;
-               asc_scsi_q.q1.data_cnt = 0;
-               asc_scsi_q.q1.data_addr = 0;
-               /* This is a byte value, otherwise it would need to be swapped. */
-               asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
-               ASC_STATS_ADD(scp->device->host, sg_elem,
-                             asc_sg_head.entry_cnt);
+       len = asc_prt_line(cp, leftlen, " Start Motor:         ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (ep->
+                                   start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               /*
-                * Convert scatter-gather list into ASC_SG_HEAD list.
-                */
-               for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
-                       asc_sg_head.sg_list[sgcnt].addr =
-                           cpu_to_le32(sg_dma_address(slp));
-                       asc_sg_head.sg_list[sgcnt].bytes =
-                           cpu_to_le32(sg_dma_len(slp));
-                       ASC_STATS_ADD(scp->device->host, sg_xfer,
-                                     ASC_CEILING(sg_dma_len(slp), 512));
-               }
+       len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (ep->
+                                   init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
        }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
-       ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+#ifdef CONFIG_ISA
+       if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+               len = asc_prt_line(cp, leftlen,
+                                  " Host ISA DMA speed:   %d MB/S\n",
+                                  isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
+               ASC_PRT_NEXT();
+       }
+#endif /* CONFIG_ISA */
 
-       return ASC_NOERROR;
+       return totlen;
 }
 
 /*
- * Build a request structure for the Adv Library (Wide Board).
+ * asc_prt_adv_board_eeprom()
  *
- * If an adv_req_t can not be allocated to issue the request,
- * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
+ * Print board EEPROM configuration.
  *
- * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
- * microcode for DMA addresses or math operations are byte swapped
- * to little-endian order.
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
  */
-static int
-adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
-             ADV_SCSI_REQ_Q **adv_scsiqpp)
+static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
 {
-       adv_req_t *reqp;
-       ADV_SCSI_REQ_Q *scsiqp;
+       struct asc_board *boardp = shost_priv(shost);
+       ADV_DVC_VAR *adv_dvc_varp;
+       int leftlen;
+       int totlen;
+       int len;
        int i;
-       int ret;
-       struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+       char *termstr;
+       uchar serialstr[13];
+       ADVEEP_3550_CONFIG *ep_3550 = NULL;
+       ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
+       ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
+       ushort word;
+       ushort *wordp;
+       ushort sdtr_speed = 0;
 
-       /*
-        * Allocate an adv_req_t structure from the board to execute
-        * the command.
-        */
-       if (boardp->adv_reqp == NULL) {
-               ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
-               ASC_STATS(scp->device->host, adv_build_noreq);
-               return ASC_BUSY;
+       adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               ep_3550 = &boardp->eep_config.adv_3550_eep;
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
        } else {
-               reqp = boardp->adv_reqp;
-               boardp->adv_reqp = reqp->next_reqp;
-               reqp->next_reqp = NULL;
+               ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
        }
 
-       /*
-        * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
-        */
-       scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
-
-       /*
-        * Initialize the structure.
-        */
-       scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
+       leftlen = cplen;
+       totlen = len = 0;
 
-       /*
-        * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
-        */
-       scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
+       len = asc_prt_line(cp, leftlen,
+                          "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+                          shost->host_no);
+       ASC_PRT_NEXT();
 
-       /*
-        * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
-        */
-       reqp->cmndp = scp;
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               wordp = &ep_3550->serial_number_word1;
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               wordp = &ep_38C0800->serial_number_word1;
+       } else {
+               wordp = &ep_38C1600->serial_number_word1;
+       }
 
-       /*
-        * Build the ADV_SCSI_REQ_Q request.
-        */
+       if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
+               len =
+                   asc_prt_line(cp, leftlen, " Serial Number: %s\n",
+                                serialstr);
+               ASC_PRT_NEXT();
+       } else {
+               len = asc_prt_line(cp, leftlen,
+                                  " Serial Number Signature Not Present.\n");
+               ASC_PRT_NEXT();
+       }
 
-       /*
-        * Set CDB length and copy it to the request structure.
-        * For wide  boards a CDB length maximum of 16 bytes
-        * is supported.
-        */
-       if (scp->cmd_len > ADV_MAX_CDB_LEN) {
-               ASC_PRINT3
-                   ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN  %d\n",
-                    boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
-               scp->result = HOST_BYTE(DID_ERROR);
-               asc_enqueue(&boardp->done, scp, ASC_BACK);
-               return ASC_ERROR;
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               len = asc_prt_line(cp, leftlen,
+                                  " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+                                  ep_3550->adapter_scsi_id,
+                                  ep_3550->max_host_qng, ep_3550->max_dvc_qng);
+               ASC_PRT_NEXT();
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               len = asc_prt_line(cp, leftlen,
+                                  " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+                                  ep_38C0800->adapter_scsi_id,
+                                  ep_38C0800->max_host_qng,
+                                  ep_38C0800->max_dvc_qng);
+               ASC_PRT_NEXT();
+       } else {
+               len = asc_prt_line(cp, leftlen,
+                                  " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+                                  ep_38C1600->adapter_scsi_id,
+                                  ep_38C1600->max_host_qng,
+                                  ep_38C1600->max_dvc_qng);
+               ASC_PRT_NEXT();
        }
-       scsiqp->cdb_len = scp->cmd_len;
-       /* Copy first 12 CDB bytes to cdb[]. */
-       for (i = 0; i < scp->cmd_len && i < 12; i++) {
-               scsiqp->cdb[i] = scp->cmnd[i];
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               word = ep_3550->termination;
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               word = ep_38C0800->termination_lvd;
+       } else {
+               word = ep_38C1600->termination_lvd;
        }
-       /* Copy last 4 CDB bytes, if present, to cdb16[]. */
-       for (; i < scp->cmd_len; i++) {
-               scsiqp->cdb16[i - 12] = scp->cmnd[i];
+       switch (word) {
+       case 1:
+               termstr = "Low Off/High Off";
+               break;
+       case 2:
+               termstr = "Low Off/High On";
+               break;
+       case 3:
+               termstr = "Low On/High On";
+               break;
+       default:
+       case 0:
+               termstr = "Automatic";
+               break;
        }
 
-       scsiqp->target_id = scp->device->id;
-       scsiqp->target_lun = scp->device->lun;
-
-       scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-       scsiqp->sense_len = sizeof(scp->sense_buffer);
-
-       /*
-        * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
-        * buffer command.
-        */
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               len = asc_prt_line(cp, leftlen,
+                                  " termination: %u (%s), bios_ctrl: 0x%x\n",
+                                  ep_3550->termination, termstr,
+                                  ep_3550->bios_ctrl);
+               ASC_PRT_NEXT();
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               len = asc_prt_line(cp, leftlen,
+                                  " termination: %u (%s), bios_ctrl: 0x%x\n",
+                                  ep_38C0800->termination_lvd, termstr,
+                                  ep_38C0800->bios_ctrl);
+               ASC_PRT_NEXT();
+       } else {
+               len = asc_prt_line(cp, leftlen,
+                                  " termination: %u (%s), bios_ctrl: 0x%x\n",
+                                  ep_38C1600->termination_lvd, termstr,
+                                  ep_38C1600->bios_ctrl);
+               ASC_PRT_NEXT();
+       }
 
-       scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-       scsiqp->vdata_addr = scp->request_buffer;
-       scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
+       len = asc_prt_line(cp, leftlen, " Target ID:           ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %X", i);
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       if (scp->use_sg == 0) {
-               /*
-                * CDB request of single contiguous buffer.
-                */
-               reqp->sgblkp = NULL;
-               scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-               if (scp->request_bufflen) {
-                       scsiqp->vdata_addr = scp->request_buffer;
-                       scp->SCp.dma_handle =
-                           dma_map_single(dev, scp->request_buffer,
-                                          scp->request_bufflen,
-                                          scp->sc_data_direction);
-               } else {
-                       scsiqp->vdata_addr = NULL;
-                       scp->SCp.dma_handle = 0;
-               }
-               scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
-               scsiqp->sg_list_ptr = NULL;
-               scsiqp->sg_real_addr = 0;
-               ASC_STATS(scp->device->host, cont_cnt);
-               ASC_STATS_ADD(scp->device->host, cont_xfer,
-                             ASC_CEILING(scp->request_bufflen, 512));
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               word = ep_3550->disc_enable;
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               word = ep_38C0800->disc_enable;
        } else {
-               /*
-                * CDB scatter-gather request list.
-                */
-               struct scatterlist *slp;
-               int use_sg;
-
-               slp = (struct scatterlist *)scp->request_buffer;
-               use_sg =
-                   dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+               word = ep_38C1600->disc_enable;
+       }
+       len = asc_prt_line(cp, leftlen, " Disconnects:         ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               if (use_sg > ADV_MAX_SG_LIST) {
-                       ASC_PRINT3
-                           ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
-                            boardp->id, use_sg,
-                            scp->device->host->sg_tablesize);
-                       dma_unmap_sg(dev, slp, scp->use_sg,
-                                    scp->sc_data_direction);
-                       scp->result = HOST_BYTE(DID_ERROR);
-                       asc_enqueue(&boardp->done, scp, ASC_BACK);
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               word = ep_3550->tagqng_able;
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               word = ep_38C0800->tagqng_able;
+       } else {
+               word = ep_38C1600->tagqng_able;
+       }
+       len = asc_prt_line(cp, leftlen, " Command Queuing:     ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-                       /*
-                        * Free the 'adv_req_t' structure by adding it back to the
-                        * board free list.
-                        */
-                       reqp->next_reqp = boardp->adv_reqp;
-                       boardp->adv_reqp = reqp;
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               word = ep_3550->start_motor;
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               word = ep_38C0800->start_motor;
+       } else {
+               word = ep_38C1600->start_motor;
+       }
+       len = asc_prt_line(cp, leftlen, " Start Motor:         ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-                       return ASC_ERROR;
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+               ASC_PRT_NEXT();
+               for (i = 0; i <= ADV_MAX_TID; i++) {
+                       len = asc_prt_line(cp, leftlen, " %c",
+                                          (ep_3550->
+                                           sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
+                                          'Y' : 'N');
+                       ASC_PRT_NEXT();
                }
+               len = asc_prt_line(cp, leftlen, "\n");
+               ASC_PRT_NEXT();
+       }
 
-               if ((ret =
-                    adv_get_sglist(boardp, reqp, scp,
-                                   use_sg)) != ADV_SUCCESS) {
-                       /*
-                        * Free the adv_req_t structure by adding it back to the
-                        * board free list.
-                        */
-                       reqp->next_reqp = boardp->adv_reqp;
-                       boardp->adv_reqp = reqp;
-
-                       return ret;
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               len = asc_prt_line(cp, leftlen, " Ultra Transfer:      ");
+               ASC_PRT_NEXT();
+               for (i = 0; i <= ADV_MAX_TID; i++) {
+                       len = asc_prt_line(cp, leftlen, " %c",
+                                          (ep_3550->
+                                           ultra_able & ADV_TID_TO_TIDMASK(i))
+                                          ? 'Y' : 'N');
+                       ASC_PRT_NEXT();
                }
-
-               ASC_STATS(scp->device->host, sg_cnt);
-               ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
+               len = asc_prt_line(cp, leftlen, "\n");
+               ASC_PRT_NEXT();
        }
 
-       ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
-       ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
-
-       *adv_scsiqpp = scsiqp;
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+               word = ep_3550->wdtr_able;
+       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+               word = ep_38C0800->wdtr_able;
+       } else {
+               word = ep_38C1600->wdtr_able;
+       }
+       len = asc_prt_line(cp, leftlen, " Wide Transfer:       ");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               len = asc_prt_line(cp, leftlen, " %c",
+                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       return ASC_NOERROR;
-}
+       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
+           adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
+               len = asc_prt_line(cp, leftlen,
+                                  " Synchronous Transfer Speed (Mhz):\n  ");
+               ASC_PRT_NEXT();
+               for (i = 0; i <= ADV_MAX_TID; i++) {
+                       char *speed_str;
 
-/*
- * Build scatter-gather list for Adv Library (Wide Board).
- *
- * Additional ADV_SG_BLOCK structures will need to be allocated
- * if the total number of scatter-gather elements exceeds
- * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
- * assumed to be physically contiguous.
- *
- * Return:
- *      ADV_SUCCESS(1) - SG List successfully created
- *      ADV_ERROR(-1) - SG List creation failed
- */
-static int
-adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
-              int use_sg)
-{
-       adv_sgblk_t *sgblkp;
-       ADV_SCSI_REQ_Q *scsiqp;
-       struct scatterlist *slp;
-       int sg_elem_cnt;
-       ADV_SG_BLOCK *sg_block, *prev_sg_block;
-       ADV_PADDR sg_block_paddr;
-       int i;
+                       if (i == 0) {
+                               sdtr_speed = adv_dvc_varp->sdtr_speed1;
+                       } else if (i == 4) {
+                               sdtr_speed = adv_dvc_varp->sdtr_speed2;
+                       } else if (i == 8) {
+                               sdtr_speed = adv_dvc_varp->sdtr_speed3;
+                       } else if (i == 12) {
+                               sdtr_speed = adv_dvc_varp->sdtr_speed4;
+                       }
+                       switch (sdtr_speed & ADV_MAX_TID) {
+                       case 0:
+                               speed_str = "Off";
+                               break;
+                       case 1:
+                               speed_str = "  5";
+                               break;
+                       case 2:
+                               speed_str = " 10";
+                               break;
+                       case 3:
+                               speed_str = " 20";
+                               break;
+                       case 4:
+                               speed_str = " 40";
+                               break;
+                       case 5:
+                               speed_str = " 80";
+                               break;
+                       default:
+                               speed_str = "Unk";
+                               break;
+                       }
+                       len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
+                       ASC_PRT_NEXT();
+                       if (i == 7) {
+                               len = asc_prt_line(cp, leftlen, "\n  ");
+                               ASC_PRT_NEXT();
+                       }
+                       sdtr_speed >>= 4;
+               }
+               len = asc_prt_line(cp, leftlen, "\n");
+               ASC_PRT_NEXT();
+       }
 
-       scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
-       slp = (struct scatterlist *)scp->request_buffer;
-       sg_elem_cnt = use_sg;
-       prev_sg_block = NULL;
-       reqp->sgblkp = NULL;
+       return totlen;
+}
 
-       do {
-               /*
-                * Allocate a 'adv_sgblk_t' structure from the board free
-                * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
-                * (15) scatter-gather elements.
-                */
-               if ((sgblkp = boardp->adv_sgblkp) == NULL) {
-                       ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
-                       ASC_STATS(scp->device->host, adv_build_nosg);
+/*
+ * asc_prt_driver_conf()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
+{
+       struct asc_board *boardp = shost_priv(shost);
+       int leftlen;
+       int totlen;
+       int len;
+       int chip_scsi_id;
 
-                       /*
-                        * Allocation failed. Free 'adv_sgblk_t' structures already
-                        * allocated for the request.
-                        */
-                       while ((sgblkp = reqp->sgblkp) != NULL) {
-                               /* Remove 'sgblkp' from the request list. */
-                               reqp->sgblkp = sgblkp->next_sgblkp;
+       leftlen = cplen;
+       totlen = len = 0;
 
-                               /* Add 'sgblkp' to the board free list. */
-                               sgblkp->next_sgblkp = boardp->adv_sgblkp;
-                               boardp->adv_sgblkp = sgblkp;
-                       }
-                       return ASC_BUSY;
-               } else {
-                       /* Complete 'adv_sgblk_t' board allocation. */
-                       boardp->adv_sgblkp = sgblkp->next_sgblkp;
-                       sgblkp->next_sgblkp = NULL;
+       len = asc_prt_line(cp, leftlen,
+                          "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+                          shost->host_no);
+       ASC_PRT_NEXT();
 
-                       /*
-                        * Get 8 byte aligned virtual and physical addresses for
-                        * the allocated ADV_SG_BLOCK structure.
-                        */
-                       sg_block =
-                           (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
-                       sg_block_paddr = virt_to_bus(sg_block);
+       len = asc_prt_line(cp, leftlen,
+                          " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
+                          shost->host_busy, shost->last_reset, shost->max_id,
+                          shost->max_lun, shost->max_channel);
+       ASC_PRT_NEXT();
 
-                       /*
-                        * Check if this is the first 'adv_sgblk_t' for the request.
-                        */
-                       if (reqp->sgblkp == NULL) {
-                               /* Request's first scatter-gather block. */
-                               reqp->sgblkp = sgblkp;
+       len = asc_prt_line(cp, leftlen,
+                          " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+                          shost->unique_id, shost->can_queue, shost->this_id,
+                          shost->sg_tablesize, shost->cmd_per_lun);
+       ASC_PRT_NEXT();
 
-                               /*
-                                * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
-                                * address pointers.
-                                */
-                               scsiqp->sg_list_ptr = sg_block;
-                               scsiqp->sg_real_addr =
-                                   cpu_to_le32(sg_block_paddr);
-                       } else {
-                               /* Request's second or later scatter-gather block. */
-                               sgblkp->next_sgblkp = reqp->sgblkp;
-                               reqp->sgblkp = sgblkp;
+       len = asc_prt_line(cp, leftlen,
+                          " unchecked_isa_dma %d, use_clustering %d\n",
+                          shost->unchecked_isa_dma, shost->use_clustering);
+       ASC_PRT_NEXT();
 
-                               /*
-                                * Point the previous ADV_SG_BLOCK structure to
-                                * the newly allocated ADV_SG_BLOCK structure.
-                                */
-                               ASC_ASSERT(prev_sg_block != NULL);
-                               prev_sg_block->sg_ptr =
-                                   cpu_to_le32(sg_block_paddr);
-                       }
-               }
+       len = asc_prt_line(cp, leftlen,
+                          " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
+                          boardp->flags, boardp->last_reset, jiffies,
+                          boardp->asc_n_io_port);
+       ASC_PRT_NEXT();
 
-               for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
-                       sg_block->sg_list[i].sg_addr =
-                           cpu_to_le32(sg_dma_address(slp));
-                       sg_block->sg_list[i].sg_count =
-                           cpu_to_le32(sg_dma_len(slp));
-                       ASC_STATS_ADD(scp->device->host, sg_xfer,
-                                     ASC_CEILING(sg_dma_len(slp), 512));
+       len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
+       ASC_PRT_NEXT();
 
-                       if (--sg_elem_cnt == 0) {       /* Last ADV_SG_BLOCK and scatter-gather entry. */
-                               sg_block->sg_cnt = i + 1;
-                               sg_block->sg_ptr = 0L;  /* Last ADV_SG_BLOCK in list. */
-                               return ADV_SUCCESS;
-                       }
-                       slp++;
-               }
-               sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
-               prev_sg_block = sg_block;
+       if (ASC_NARROW_BOARD(boardp)) {
+               chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+       } else {
+               chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
        }
-       while (1);
-       /* NOTREACHED */
+
+       return totlen;
 }
 
 /*
- * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ * asc_prt_asc_board_info()
  *
- * Interrupt callback function for the Narrow SCSI Asc Library.
+ * Print dynamic board configuration information.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
  */
-static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
 {
-       asc_board_t *boardp;
-       struct scsi_cmnd *scp;
-       struct Scsi_Host *shost;
+       struct asc_board *boardp = shost_priv(shost);
+       int chip_scsi_id;
+       int leftlen;
+       int totlen;
+       int len;
+       ASC_DVC_VAR *v;
+       ASC_DVC_CFG *c;
        int i;
+       int renegotiate = 0;
 
-       ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
-                (ulong)asc_dvc_varp, (ulong)qdonep);
-       ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+       v = &boardp->dvc_var.asc_dvc_var;
+       c = &boardp->dvc_cfg.asc_dvc_cfg;
+       chip_scsi_id = c->chip_scsi_id;
 
-       /*
-        * Get the struct scsi_cmnd structure and Scsi_Host structure for the
-        * command that has been completed.
-        */
-       scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
-       ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
+       leftlen = cplen;
+       totlen = len = 0;
 
-       if (scp == NULL) {
-               ASC_PRINT("asc_isr_callback: scp is NULL\n");
-               return;
-       }
-       ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+       len = asc_prt_line(cp, leftlen,
+                          "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+                          shost->host_no);
+       ASC_PRT_NEXT();
 
-       /*
-        * If the request's host pointer is not valid, display a
-        * message and return.
-        */
-       shost = scp->device->host;
-       for (i = 0; i < asc_board_count; i++) {
-               if (asc_host[i] == shost) {
-                       break;
-               }
-       }
-       if (i == asc_board_count) {
-               ASC_PRINT2
-                   ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
-                    (ulong)scp, (ulong)shost);
-               return;
-       }
+       len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
+                          "mcode_version 0x%x, err_code %u\n",
+                          c->chip_version, c->mcode_date, c->mcode_version,
+                          v->err_code);
+       ASC_PRT_NEXT();
 
-       ASC_STATS(shost, callback);
-       ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
+       /* Current number of commands waiting for the host. */
+       len = asc_prt_line(cp, leftlen,
+                          " Total Command Pending: %d\n", v->cur_total_qng);
+       ASC_PRT_NEXT();
 
-       /*
-        * If the request isn't found on the active queue, it may
-        * have been removed to handle a reset request.
-        * Display a message and return.
-        */
-       boardp = ASC_BOARDP(shost);
-       ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
-       if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-               ASC_PRINT2
-                   ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
-                    boardp->id, (ulong)scp);
-               return;
+       len = asc_prt_line(cp, leftlen, " Command Queuing:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
+               len = asc_prt_line(cp, leftlen, " %X:%c",
+                                  i,
+                                  (v->
+                                   use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
+                                  'Y' : 'N');
+               ASC_PRT_NEXT();
        }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       /*
-        * 'qdonep' contains the command's ending status.
-        */
-       switch (qdonep->d3.done_stat) {
-       case QD_NO_ERROR:
-               ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
-               scp->result = 0;
-
-               /*
-                * If an INQUIRY command completed successfully, then call
-                * the AscInquiryHandling() function to set-up the device.
-                */
-               if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
-                   (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
-                       AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
-                                          (ASC_SCSI_INQUIRY *)scp->
-                                          request_buffer);
+       /* Current number of commands waiting for a device. */
+       len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
                }
+               len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               /*
-                * Check for an underrun condition.
-                *
-                * If there was no error and an underrun condition, then
-                * then return the number of underrun bytes.
-                */
-               if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
-                   qdonep->remain_bytes <= scp->request_bufflen) {
-                       ASC_DBG1(1,
-                                "asc_isr_callback: underrun condition %u bytes\n",
-                                (unsigned)qdonep->remain_bytes);
-                       scp->resid = qdonep->remain_bytes;
+       /* Current limit on number of commands that can be sent to a device. */
+       len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
                }
-               break;
-
-       case QD_WITH_ERROR:
-               ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
-               switch (qdonep->d3.host_stat) {
-               case QHSTA_NO_ERROR:
-                       if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
-                               ASC_DBG(2,
-                                       "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
-                               ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                                                 sizeof(scp->sense_buffer));
-                               /*
-                                * Note: The 'status_byte()' macro used by target drivers
-                                * defined in scsi.h shifts the status byte returned by
-                                * host drivers right by 1 bit. This is why target drivers
-                                * also use right shifted status byte definitions. For
-                                * instance target drivers use CHECK_CONDITION, defined to
-                                * 0x1, instead of the SCSI defined check condition value
-                                * of 0x2. Host drivers are supposed to return the status
-                                * byte as it is defined by SCSI.
-                                */
-                               scp->result = DRIVER_BYTE(DRIVER_SENSE) |
-                                   STATUS_BYTE(qdonep->d3.scsi_stat);
-                       } else {
-                               scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
-                       }
-                       break;
+               len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               default:
-                       /* QHSTA error occurred */
-                       ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
-                                qdonep->d3.host_stat);
-                       scp->result = HOST_BYTE(DID_BAD_TARGET);
-                       break;
+       /* Indicate whether the device has returned queue full status. */
+       len = asc_prt_line(cp, leftlen, " Command Queue Full:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
                }
-               break;
-
-       case QD_ABORTED_BY_HOST:
-               ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
-               scp->result =
-                   HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
-                                                   scsi_msg) |
-                   STATUS_BYTE(qdonep->d3.scsi_stat);
-               break;
+               if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
+                       len = asc_prt_line(cp, leftlen, " %X:Y-%d",
+                                          i, boardp->queue_full_cnt[i]);
+               } else {
+                       len = asc_prt_line(cp, leftlen, " %X:N", i);
+               }
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       default:
-               ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
-                        qdonep->d3.done_stat);
-               scp->result =
-                   HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
-                                                   scsi_msg) |
-                   STATUS_BYTE(qdonep->d3.scsi_stat);
-               break;
+       len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
+               len = asc_prt_line(cp, leftlen, " %X:%c",
+                                  i,
+                                  (v->
+                                   sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
        }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       /*
-        * If the 'init_tidmask' bit isn't already set for the target and the
-        * current request finished normally, then set the bit for the target
-        * to indicate that a device is present.
-        */
-       if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
-           qdonep->d3.done_stat == QD_NO_ERROR &&
-           qdonep->d3.host_stat == QHSTA_NO_ERROR) {
-               boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               uchar syn_period_ix;
+
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+                   ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
+
+               len = asc_prt_line(cp, leftlen, "  %X:", i);
+               ASC_PRT_NEXT();
+
+               if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
+                       len = asc_prt_line(cp, leftlen, " Asynchronous");
+                       ASC_PRT_NEXT();
+               } else {
+                       syn_period_ix =
+                           (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
+                                                          1);
+
+                       len = asc_prt_line(cp, leftlen,
+                                          " Transfer Period Factor: %d (%d.%d Mhz),",
+                                          v->sdtr_period_tbl[syn_period_ix],
+                                          250 /
+                                          v->sdtr_period_tbl[syn_period_ix],
+                                          ASC_TENTHS(250,
+                                                     v->
+                                                     sdtr_period_tbl
+                                                     [syn_period_ix]));
+                       ASC_PRT_NEXT();
+
+                       len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                                          boardp->
+                                          sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+                       ASC_PRT_NEXT();
+               }
+
+               if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+                       len = asc_prt_line(cp, leftlen, "*\n");
+                       renegotiate = 1;
+               } else {
+                       len = asc_prt_line(cp, leftlen, "\n");
+               }
+               ASC_PRT_NEXT();
        }
 
-       /*
-        * Because interrupts may be enabled by the 'struct scsi_cmnd' done
-        * function, add the command to the end of the board's done queue.
-        * The done function for the command will be called from
-        * advansys_interrupt().
-        */
-       asc_enqueue(&boardp->done, scp, ASC_BACK);
+       if (renegotiate) {
+               len = asc_prt_line(cp, leftlen,
+                                  " * = Re-negotiation pending before next command.\n");
+               ASC_PRT_NEXT();
+       }
 
-       return;
+       return totlen;
 }
 
 /*
- * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ * asc_prt_adv_board_info()
  *
- * Callback function for the Wide SCSI Adv Library.
+ * Print dynamic board configuration information.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
  */
-static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
 {
-       asc_board_t *boardp;
-       adv_req_t *reqp;
-       adv_sgblk_t *sgblkp;
-       struct scsi_cmnd *scp;
-       struct Scsi_Host *shost;
+       struct asc_board *boardp = shost_priv(shost);
+       int leftlen;
+       int totlen;
+       int len;
        int i;
-       ADV_DCNT resid_cnt;
+       ADV_DVC_VAR *v;
+       ADV_DVC_CFG *c;
+       AdvPortAddr iop_base;
+       ushort chip_scsi_id;
+       ushort lramword;
+       uchar lrambyte;
+       ushort tagqng_able;
+       ushort sdtr_able, wdtr_able;
+       ushort wdtr_done, sdtr_done;
+       ushort period = 0;
+       int renegotiate = 0;
 
-       ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
-                (ulong)adv_dvc_varp, (ulong)scsiqp);
-       ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+       v = &boardp->dvc_var.adv_dvc_var;
+       c = &boardp->dvc_cfg.adv_dvc_cfg;
+       iop_base = v->iop_base;
+       chip_scsi_id = v->chip_scsi_id;
 
-       /*
-        * Get the adv_req_t structure for the command that has been
-        * completed. The adv_req_t structure actually contains the
-        * completed ADV_SCSI_REQ_Q structure.
-        */
-       reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
-       ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
-       if (reqp == NULL) {
-               ASC_PRINT("adv_isr_callback: reqp is NULL\n");
-               return;
-       }
+       leftlen = cplen;
+       totlen = len = 0;
 
-       /*
-        * Get the struct scsi_cmnd structure and Scsi_Host structure for the
-        * command that has been completed.
-        *
-        * Note: The adv_req_t request structure and adv_sgblk_t structure,
-        * if any, are dropped, because a board structure pointer can not be
-        * determined.
-        */
-       scp = reqp->cmndp;
-       ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
-       if (scp == NULL) {
-               ASC_PRINT
-                   ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
-               return;
-       }
-       ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+       len = asc_prt_line(cp, leftlen,
+                          "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+                          shost->host_no);
+       ASC_PRT_NEXT();
 
-       /*
-        * If the request's host pointer is not valid, display a message
-        * and return.
-        */
-       shost = scp->device->host;
-       for (i = 0; i < asc_board_count; i++) {
-               if (asc_host[i] == shost) {
-                       break;
+       len = asc_prt_line(cp, leftlen,
+                          " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
+                          v->iop_base,
+                          AdvReadWordRegister(iop_base,
+                                              IOPW_SCSI_CFG1) & CABLE_DETECT,
+                          v->err_code);
+       ASC_PRT_NEXT();
+
+       len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
+                          "mcode_version 0x%x\n", c->chip_version,
+                          c->mcode_date, c->mcode_version);
+       ASC_PRT_NEXT();
+
+       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+       len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
                }
+
+               len = asc_prt_line(cp, leftlen, " %X:%c",
+                                  i,
+                                  (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
        }
-       /*
-        * Note: If the host structure is not found, the adv_req_t request
-        * structure and adv_sgblk_t structure, if any, is dropped.
-        */
-       if (i == asc_board_count) {
-               ASC_PRINT2
-                   ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
-                    (ulong)scp, (ulong)shost);
-               return;
-       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       ASC_STATS(shost, callback);
-       ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
+       len = asc_prt_line(cp, leftlen, " Queue Limit:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
 
-       /*
-        * If the request isn't found on the active queue, it may have been
-        * removed to handle a reset request. Display a message and return.
-        *
-        * Note: Because the structure may still be in use don't attempt
-        * to free the adv_req_t and adv_sgblk_t, if any, structures.
-        */
-       boardp = ASC_BOARDP(shost);
-       ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
-       if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-               ASC_PRINT2
-                   ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
-                    boardp->id, (ulong)scp);
-               return;
-       }
+               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
+                               lrambyte);
 
-       /*
-        * 'done_status' contains the command's ending status.
-        */
-       switch (scsiqp->done_status) {
-       case QD_NO_ERROR:
-               ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
-               scp->result = 0;
+               len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-               /*
-                * Check for an underrun condition.
-                *
-                * If there was no error and an underrun condition, then
-                * then return the number of underrun bytes.
-                */
-               resid_cnt = le32_to_cpu(scsiqp->data_cnt);
-               if (scp->request_bufflen != 0 && resid_cnt != 0 &&
-                   resid_cnt <= scp->request_bufflen) {
-                       ASC_DBG1(1,
-                                "adv_isr_callback: underrun condition %lu bytes\n",
-                                (ulong)resid_cnt);
-                       scp->resid = resid_cnt;
+       len = asc_prt_line(cp, leftlen, " Command Pending:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
                }
-               break;
 
-       case QD_WITH_ERROR:
-               ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
-               switch (scsiqp->host_status) {
-               case QHSTA_NO_ERROR:
-                       if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
-                               ASC_DBG(2,
-                                       "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
-                               ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                                                 sizeof(scp->sense_buffer));
-                               /*
-                                * Note: The 'status_byte()' macro used by target drivers
-                                * defined in scsi.h shifts the status byte returned by
-                                * host drivers right by 1 bit. This is why target drivers
-                                * also use right shifted status byte definitions. For
-                                * instance target drivers use CHECK_CONDITION, defined to
-                                * 0x1, instead of the SCSI defined check condition value
-                                * of 0x2. Host drivers are supposed to return the status
-                                * byte as it is defined by SCSI.
-                                */
-                               scp->result = DRIVER_BYTE(DRIVER_SENSE) |
-                                   STATUS_BYTE(scsiqp->scsi_status);
-                       } else {
-                               scp->result = STATUS_BYTE(scsiqp->scsi_status);
-                       }
-                       break;
+               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
+                               lrambyte);
 
-               default:
-                       /* Some other QHSTA error occurred. */
-                       ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
-                                scsiqp->host_status);
-                       scp->result = HOST_BYTE(DID_BAD_TARGET);
-                       break;
-               }
-               break;
+               len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       case QD_ABORTED_BY_HOST:
-               ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
-               scp->result =
-                   HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
-               break;
+       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+       len = asc_prt_line(cp, leftlen, " Wide Enabled:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
 
-       default:
-               ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
-                        scsiqp->done_status);
-               scp->result =
-                   HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
-               break;
+               len = asc_prt_line(cp, leftlen, " %X:%c",
+                                  i,
+                                  (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
        }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       /*
-        * If the 'init_tidmask' bit isn't already set for the target and the
-        * current request finished normally, then set the bit for the target
-        * to indicate that a device is present.
-        */
-       if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
-           scsiqp->done_status == QD_NO_ERROR &&
-           scsiqp->host_status == QHSTA_NO_ERROR) {
-               boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
-       }
+       AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
+       len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
 
-       /*
-        * Because interrupts may be enabled by the 'struct scsi_cmnd' done
-        * function, add the command to the end of the board's done queue.
-        * The done function for the command will be called from
-        * advansys_interrupt().
-        */
-       asc_enqueue(&boardp->done, scp, ASC_BACK);
+               AdvReadWordLram(iop_base,
+                               ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+                               lramword);
 
-       /*
-        * Free all 'adv_sgblk_t' structures allocated for the request.
-        */
-       while ((sgblkp = reqp->sgblkp) != NULL) {
-               /* Remove 'sgblkp' from the request list. */
-               reqp->sgblkp = sgblkp->next_sgblkp;
+               len = asc_prt_line(cp, leftlen, " %X:%d",
+                                  i, (lramword & 0x8000) ? 16 : 8);
+               ASC_PRT_NEXT();
 
-               /* Add 'sgblkp' to the board free list. */
-               sgblkp->next_sgblkp = boardp->adv_sgblkp;
-               boardp->adv_sgblkp = sgblkp;
+               if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
+                   (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+                       len = asc_prt_line(cp, leftlen, "*");
+                       ASC_PRT_NEXT();
+                       renegotiate = 1;
+               }
        }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       /*
-        * Free the adv_req_t structure used with the command by adding
-        * it back to the board free list.
-        */
-       reqp->next_reqp = boardp->adv_reqp;
-       boardp->adv_reqp = reqp;
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+       len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
+       ASC_PRT_NEXT();
+       for (i = 0; i <= ADV_MAX_TID; i++) {
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
+
+               len = asc_prt_line(cp, leftlen, " %X:%c",
+                                  i,
+                                  (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+                                  'N');
+               ASC_PRT_NEXT();
+       }
+       len = asc_prt_line(cp, leftlen, "\n");
+       ASC_PRT_NEXT();
 
-       ASC_DBG(1, "adv_isr_callback: done\n");
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
+       for (i = 0; i <= ADV_MAX_TID; i++) {
 
-       return;
-}
+               AdvReadWordLram(iop_base,
+                               ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+                               lramword);
+               lramword &= ~0x8000;
 
-/*
- * adv_async_callback() - Adv Library asynchronous event callback function.
- */
-static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
-{
-       switch (code) {
-       case ADV_ASYNC_SCSI_BUS_RESET_DET:
-               /*
-                * The firmware detected a SCSI Bus reset.
-                */
-               ASC_DBG(0,
-                       "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
-               break;
+               if ((chip_scsi_id == i) ||
+                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+                   ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
+                       continue;
+               }
 
-       case ADV_ASYNC_RDMA_FAILURE:
-               /*
-                * Handle RDMA failure by resetting the SCSI Bus and
-                * possibly the chip if it is unresponsive. Log the error
-                * with a unique code.
-                */
-               ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
-               AdvResetChipAndSB(adv_dvc_varp);
-               break;
+               len = asc_prt_line(cp, leftlen, "  %X:", i);
+               ASC_PRT_NEXT();
 
-       case ADV_HOST_SCSI_BUS_RESET:
-               /*
-                * Host generated SCSI bus reset occurred.
-                */
-               ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
-               break;
+               if ((lramword & 0x1F) == 0) {   /* Check for REQ/ACK Offset 0. */
+                       len = asc_prt_line(cp, leftlen, " Asynchronous");
+                       ASC_PRT_NEXT();
+               } else {
+                       len =
+                           asc_prt_line(cp, leftlen,
+                                        " Transfer Period Factor: ");
+                       ASC_PRT_NEXT();
 
-       default:
-               ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
-               break;
-       }
-}
+                       if ((lramword & 0x1F00) == 0x1100) {    /* 80 Mhz */
+                               len =
+                                   asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
+                               ASC_PRT_NEXT();
+                       } else if ((lramword & 0x1F00) == 0x1000) {     /* 40 Mhz */
+                               len =
+                                   asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
+                               ASC_PRT_NEXT();
+                       } else {        /* 20 Mhz or below. */
 
-/*
- * Add a 'REQP' to the end of specified queue. Set 'tidmask'
- * to indicate a command is queued for the device.
- *
- * 'flag' may be either ASC_FRONT or ASC_BACK.
- *
- * 'REQPNEXT(reqp)' returns reqp's next pointer.
- */
-static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
-{
-       int tid;
-
-       ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
-                (ulong)ascq, (ulong)reqp, flag);
-       ASC_ASSERT(reqp != NULL);
-       ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
-       tid = REQPTID(reqp);
-       ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-       if (flag == ASC_FRONT) {
-               reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
-               ascq->q_first[tid] = reqp;
-               /* If the queue was empty, set the last pointer. */
-               if (ascq->q_last[tid] == NULL) {
-                       ascq->q_last[tid] = reqp;
-               }
-       } else {                /* ASC_BACK */
-               if (ascq->q_last[tid] != NULL) {
-                       ascq->q_last[tid]->host_scribble =
-                           (unsigned char *)reqp;
+                               period = (((lramword >> 8) * 25) + 50) / 4;
+
+                               if (period == 0) {      /* Should never happen. */
+                                       len =
+                                           asc_prt_line(cp, leftlen,
+                                                        "%d (? Mhz), ");
+                                       ASC_PRT_NEXT();
+                               } else {
+                                       len = asc_prt_line(cp, leftlen,
+                                                          "%d (%d.%d Mhz),",
+                                                          period, 250 / period,
+                                                          ASC_TENTHS(250,
+                                                                     period));
+                                       ASC_PRT_NEXT();
+                               }
+                       }
+
+                       len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                                          lramword & 0x1F);
+                       ASC_PRT_NEXT();
                }
-               ascq->q_last[tid] = reqp;
-               reqp->host_scribble = NULL;
-               /* If the queue was empty, set the first pointer. */
-               if (ascq->q_first[tid] == NULL) {
-                       ascq->q_first[tid] = reqp;
+
+               if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+                       len = asc_prt_line(cp, leftlen, "*\n");
+                       renegotiate = 1;
+               } else {
+                       len = asc_prt_line(cp, leftlen, "\n");
                }
+               ASC_PRT_NEXT();
        }
-       /* The queue has at least one entry, set its bit. */
-       ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
-       /* Maintain request queue statistics. */
-       ascq->q_tot_cnt[tid]++;
-       ascq->q_cur_cnt[tid]++;
-       if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
-               ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
-               ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
-                        tid, ascq->q_max_cnt[tid]);
-       }
-       REQPTIME(reqp) = REQTIMESTAMP();
-#endif /* ADVANSYS_STATS */
-       ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
-       return;
-}
 
-/*
- * Return first queued 'REQP' on the specified queue for
- * the specified target device. Clear the 'tidmask' bit for
- * the device if no more commands are left queued for it.
- *
- * 'REQPNEXT(reqp)' returns reqp's next pointer.
- */
-static REQP asc_dequeue(asc_queue_t *ascq, int tid)
-{
-       REQP reqp;
-
-       ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
-       ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-       if ((reqp = ascq->q_first[tid]) != NULL) {
-               ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
-               ascq->q_first[tid] = REQPNEXT(reqp);
-               /* If the queue is empty, clear its bit and the last pointer. */
-               if (ascq->q_first[tid] == NULL) {
-                       ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-                       ASC_ASSERT(ascq->q_last[tid] == reqp);
-                       ascq->q_last[tid] = NULL;
-               }
-#ifdef ADVANSYS_STATS
-               /* Maintain request queue statistics. */
-               ascq->q_cur_cnt[tid]--;
-               ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
-               REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
-#endif /* ADVANSYS_STATS */
+       if (renegotiate) {
+               len = asc_prt_line(cp, leftlen,
+                                  " * = Re-negotiation pending before next command.\n");
+               ASC_PRT_NEXT();
        }
-       ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
-       return reqp;
+
+       return totlen;
 }
 
 /*
- * Return a pointer to a singly linked list of all the requests queued
- * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
- *
- * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
- * the last request returned in the singly linked list.
- *
- * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
- * then all queued requests are concatenated into one list and
- * returned.
- *
- * Note: If 'lastpp' is used to append a new list to the end of
- * an old list, only change the old list last pointer if '*lastpp'
- * (or the function return value) is not NULL, i.e. use a temporary
- * variable for 'lastpp' and check its value after the function return
- * before assigning it to the list last pointer.
+ * asc_proc_copy()
  *
- * Unfortunately collecting queuing time statistics adds overhead to
- * the function that isn't inherent to the function's algorithm.
+ * Copy proc information to a read buffer taking into account the current
+ * read offset in the file and the remaining space in the read buffer.
  */
-static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+static int
+asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
+             char *cp, int cplen)
 {
-       REQP firstp, lastp;
-       int i;
-
-       ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
-       ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
+       int cnt = 0;
 
-       /*
-        * If 'tid' is not ASC_TID_ALL, return requests only for
-        * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
-        * requests for all tids.
-        */
-       if (tid != ASC_TID_ALL) {
-               /* Return all requests for the specified 'tid'. */
-               if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
-                       /* List is empty; Set first and last return pointers to NULL. */
-                       firstp = lastp = NULL;
-               } else {
-                       firstp = ascq->q_first[tid];
-                       lastp = ascq->q_last[tid];
-                       ascq->q_first[tid] = ascq->q_last[tid] = NULL;
-                       ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
-                       {
-                               REQP reqp;
-                               ascq->q_cur_cnt[tid] = 0;
-                               for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
-                                       REQTIMESTAT("asc_dequeue_list", ascq,
-                                                   reqp, tid);
-                               }
-                       }
-#endif /* ADVANSYS_STATS */
-               }
-       } else {
-               /* Return all requests for all tids. */
-               firstp = lastp = NULL;
-               for (i = 0; i <= ADV_MAX_TID; i++) {
-                       if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
-                               if (firstp == NULL) {
-                                       firstp = ascq->q_first[i];
-                                       lastp = ascq->q_last[i];
-                               } else {
-                                       ASC_ASSERT(lastp != NULL);
-                                       lastp->host_scribble =
-                                           (unsigned char *)ascq->q_first[i];
-                                       lastp = ascq->q_last[i];
-                               }
-                               ascq->q_first[i] = ascq->q_last[i] = NULL;
-                               ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-#ifdef ADVANSYS_STATS
-                               ascq->q_cur_cnt[i] = 0;
-#endif /* ADVANSYS_STATS */
-                       }
-               }
-#ifdef ADVANSYS_STATS
-               {
-                       REQP reqp;
-                       for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
-                               REQTIMESTAT("asc_dequeue_list", ascq, reqp,
-                                           reqp->device->id);
-                       }
-               }
-#endif /* ADVANSYS_STATS */
-       }
-       if (lastpp) {
-               *lastpp = lastp;
+       ASC_DBG(2, "offset %d, advoffset %d, cplen %d\n",
+                (unsigned)offset, (unsigned)advoffset, cplen);
+       if (offset <= advoffset) {
+               /* Read offset below current offset, copy everything. */
+               cnt = min(cplen, leftlen);
+               ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+                        (ulong)curbuf, (ulong)cp, cnt);
+               memcpy(curbuf, cp, cnt);
+       } else if (offset < advoffset + cplen) {
+               /* Read offset within current range, partial copy. */
+               cnt = (advoffset + cplen) - offset;
+               cp = (cp + cplen) - cnt;
+               cnt = min(cnt, leftlen);
+               ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+                        (ulong)curbuf, (ulong)cp, cnt);
+               memcpy(curbuf, cp, cnt);
        }
-       ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
-       return firstp;
+       return cnt;
 }
 
-/*
- * Remove the specified 'REQP' from the specified queue for
- * the specified target device. Clear the 'tidmask' bit for the
- * device if no more commands are left queued for it.
- *
- * 'REQPNEXT(reqp)' returns reqp's the next pointer.
- *
- * Return ASC_TRUE if the command was found and removed,
- * otherwise return ASC_FALSE.
- */
-static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
-{
-       REQP currp, prevp;
-       int tid;
-       int ret = ASC_FALSE;
-
-       ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
-                (ulong)ascq, (ulong)reqp);
-       ASC_ASSERT(reqp != NULL);
-
-       tid = REQPTID(reqp);
-       ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-
-       /*
-        * Handle the common case of 'reqp' being the first
-        * entry on the queue.
-        */
-       if (reqp == ascq->q_first[tid]) {
-               ret = ASC_TRUE;
-               ascq->q_first[tid] = REQPNEXT(reqp);
-               /* If the queue is now empty, clear its bit and the last pointer. */
-               if (ascq->q_first[tid] == NULL) {
-                       ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-                       ASC_ASSERT(ascq->q_last[tid] == reqp);
-                       ascq->q_last[tid] = NULL;
-               }
-       } else if (ascq->q_first[tid] != NULL) {
-               ASC_ASSERT(ascq->q_last[tid] != NULL);
-               /*
-                * Because the case of 'reqp' being the first entry has been
-                * handled above and it is known the queue is not empty, if
-                * 'reqp' is found on the queue it is guaranteed the queue will
-                * not become empty and that 'q_first[tid]' will not be changed.
-                *
-                * Set 'prevp' to the first entry, 'currp' to the second entry,
-                * and search for 'reqp'.
-                */
-               for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
-                    currp; prevp = currp, currp = REQPNEXT(currp)) {
-                       if (currp == reqp) {
-                               ret = ASC_TRUE;
-                               prevp->host_scribble =
-                                   (unsigned char *)REQPNEXT(currp);
-                               reqp->host_scribble = NULL;
-                               if (ascq->q_last[tid] == reqp) {
-                                       ascq->q_last[tid] = prevp;
-                               }
-                               break;
-                       }
-               }
-       }
 #ifdef ADVANSYS_STATS
-       /* Maintain request queue statistics. */
-       if (ret == ASC_TRUE) {
-               ascq->q_cur_cnt[tid]--;
-               REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
-       }
-       ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
-#endif /* ADVANSYS_STATS */
-       ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
-       return ret;
-}
-
-/*
- * Execute as many queued requests as possible for the specified queue.
- *
- * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
- */
-static void asc_execute_queue(asc_queue_t *ascq)
-{
-       ADV_SCSI_BIT_ID_TYPE scan_tidmask;
-       REQP reqp;
-       int i;
-
-       ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
-       /*
-        * Execute queued commands for devices attached to
-        * the current board in round-robin fashion.
-        */
-       scan_tidmask = ascq->q_tidmask;
-       do {
-               for (i = 0; i <= ADV_MAX_TID; i++) {
-                       if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
-                               if ((reqp = asc_dequeue(ascq, i)) == NULL) {
-                                       scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-                               } else
-                                   if (asc_execute_scsi_cmnd
-                                       ((struct scsi_cmnd *)reqp)
-                                       == ASC_BUSY) {
-                                       scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-                                       /*
-                                        * The request returned ASC_BUSY. Enqueue at the front of
-                                        * target's waiting list to maintain correct ordering.
-                                        */
-                                       asc_enqueue(ascq, reqp, ASC_FRONT);
-                               }
-                       }
-               }
-       } while (scan_tidmask);
-       return;
-}
-
-#ifdef CONFIG_PROC_FS
 /*
- * asc_prt_board_devices()
- *
- * Print driver information for devices attached to the board.
+ * asc_prt_board_stats()
  *
  * Note: no single line should be greater than ASC_PRTLINE_SIZE,
  * cf. asc_prt_line().
@@ -6243,10624 +4063,8194 @@ static void asc_execute_queue(asc_queue_t *ascq)
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
+static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
 {
-       asc_board_t *boardp;
-       int leftlen;
-       int totlen;
-       int len;
-       int chip_scsi_id;
-       int i;
+       struct asc_board *boardp = shost_priv(shost);
+       struct asc_stats *s = &boardp->asc_stats;
 
-       boardp = ASC_BOARDP(shost);
-       leftlen = cplen;
-       totlen = len = 0;
+       int leftlen = cplen;
+       int len, totlen = 0;
 
        len = asc_prt_line(cp, leftlen,
-                          "\nDevice Information for AdvanSys SCSI Host %d:\n",
+                          "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
                           shost->host_no);
        ASC_PRT_NEXT();
 
-       if (ASC_NARROW_BOARD(boardp)) {
-               chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
-       } else {
-               chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
-       }
-
-       len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
-                       len = asc_prt_line(cp, leftlen, " %X,", i);
-                       ASC_PRT_NEXT();
-               }
-       }
-       len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
+       len = asc_prt_line(cp, leftlen,
+                          " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
+                          s->queuecommand, s->reset, s->biosparam,
+                          s->interrupt);
        ASC_PRT_NEXT();
 
-       return totlen;
-}
-
-/*
- * Display Wide Board BIOS Information.
- */
-static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
-{
-       asc_board_t *boardp;
-       int leftlen;
-       int totlen;
-       int len;
-       ushort major, minor, letter;
-
-       boardp = ASC_BOARDP(shost);
-       leftlen = cplen;
-       totlen = len = 0;
+       len = asc_prt_line(cp, leftlen,
+                          " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
+                          s->callback, s->done, s->build_error,
+                          s->adv_build_noreq, s->adv_build_nosg);
+       ASC_PRT_NEXT();
 
-       len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
+       len = asc_prt_line(cp, leftlen,
+                          " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+                          s->exe_noerror, s->exe_busy, s->exe_error,
+                          s->exe_unknown);
        ASC_PRT_NEXT();
 
        /*
-        * If the BIOS saved a valid signature, then fill in
-        * the BIOS code segment base address.
+        * Display data transfer statistics.
         */
-       if (boardp->bios_signature != 0x55AA) {
-               len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
+       if (s->xfer_cnt > 0) {
+               len = asc_prt_line(cp, leftlen, " xfer_cnt %lu, xfer_elem %lu, ",
+                                  s->xfer_cnt, s->xfer_elem);
                ASC_PRT_NEXT();
-               len = asc_prt_line(cp, leftlen,
-                                  "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
+
+               len = asc_prt_line(cp, leftlen, "xfer_bytes %lu.%01lu kb\n",
+                                  s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2));
                ASC_PRT_NEXT();
-               len = asc_prt_line(cp, leftlen,
-                                  "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
+
+               /* Scatter gather transfer statistics */
+               len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
+                                  s->xfer_elem / s->xfer_cnt,
+                                  ASC_TENTHS(s->xfer_elem, s->xfer_cnt));
                ASC_PRT_NEXT();
-       } else {
-               major = (boardp->bios_version >> 12) & 0xF;
-               minor = (boardp->bios_version >> 8) & 0xF;
-               letter = (boardp->bios_version & 0xFF);
 
-               len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
-                                  major, minor,
-                                  letter >= 26 ? '?' : letter + 'A');
+               len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
+                                  (s->xfer_sect / 2) / s->xfer_elem,
+                                  ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem));
                ASC_PRT_NEXT();
 
-               /*
-                * Current available ROM BIOS release is 3.1I for UW
-                * and 3.2I for U2W. This code doesn't differentiate
-                * UW and U2W boards.
-                */
-               if (major < 3 || (major <= 3 && minor < 1) ||
-                   (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
-                       len = asc_prt_line(cp, leftlen,
-                                          "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
-                       ASC_PRT_NEXT();
-                       len = asc_prt_line(cp, leftlen,
-                                          "ftp://ftp.connectcom.net/pub\n");
-                       ASC_PRT_NEXT();
-               }
+               len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
+                                  (s->xfer_sect / 2) / s->xfer_cnt,
+                                  ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt));
+               ASC_PRT_NEXT();
        }
 
        return totlen;
 }
+#endif /* ADVANSYS_STATS */
 
 /*
- * Add serial number to information bar if signature AAh
- * is found in at bit 15-9 (7 bits) of word 1.
- *
- * Serial Number consists fo 12 alpha-numeric digits.
- *
- *       1 - Product type (A,B,C,D..)  Word0: 15-13 (3 bits)
- *       2 - MFG Location (A,B,C,D..)  Word0: 12-10 (3 bits)
- *     3-4 - Product ID (0-99)         Word0: 9-0 (10 bits)
- *       5 - Product revision (A-J)    Word0:  "         "
- *
- *           Signature                 Word1: 15-9 (7 bits)
- *       6 - Year (0-9)                Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
- *     7-8 - Week of the year (1-52)   Word1: 5-0 (6 bits)
- *
- *    9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
+ * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
  *
- * Note 1: Only production cards will have a serial number.
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset into a /proc/scsi/advansys/[0...] file
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
  *
- * Note 2: Signature is most significant 7 bits (0xFE).
+ * Return the number of bytes read from or written to a
+ * /proc/scsi/advansys/[0...] file.
  *
- * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
+ * Note: This function uses the per board buffer 'prtbuf' which is
+ * allocated when the board is initialized in advansys_detect(). The
+ * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
+ * used to write to the buffer. The way asc_proc_copy() is written
+ * if 'prtbuf' is too small it will not be overwritten. Instead the
+ * user just won't get all the available statistics.
  */
-static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
+static int
+advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+                  off_t offset, int length, int inout)
 {
-       ushort w, num;
-
-       if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
-               return ASC_FALSE;
-       } else {
-               /*
-                * First word - 6 digits.
-                */
-               w = serialnum[0];
-
-               /* Product type - 1st digit. */
-               if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
-                       /* Product type is P=Prototype */
-                       *cp += 0x8;
-               }
-               cp++;
+       struct asc_board *boardp = shost_priv(shost);
+       char *cp;
+       int cplen;
+       int cnt;
+       int totcnt;
+       int leftlen;
+       char *curbuf;
+       off_t advoffset;
 
-               /* Manufacturing location - 2nd digit. */
-               *cp++ = 'A' + ((w & 0x1C00) >> 10);
+       ASC_DBG(1, "begin\n");
 
-               /* Product ID - 3rd, 4th digits. */
-               num = w & 0x3FF;
-               *cp++ = '0' + (num / 100);
-               num %= 100;
-               *cp++ = '0' + (num / 10);
+       /*
+        * User write not supported.
+        */
+       if (inout == TRUE)
+               return -ENOSYS;
 
-               /* Product revision - 5th digit. */
-               *cp++ = 'A' + (num % 10);
+       /*
+        * User read of /proc/scsi/advansys/[0...] file.
+        */
 
-               /*
-                * Second word
-                */
-               w = serialnum[1];
+       /* Copy read data starting at the beginning of the buffer. */
+       *start = buffer;
+       curbuf = buffer;
+       advoffset = 0;
+       totcnt = 0;
+       leftlen = length;
 
-               /*
-                * Year - 6th digit.
-                *
-                * If bit 15 of third word is set, then the
-                * last digit of the year is greater than 7.
-                */
-               if (serialnum[2] & 0x8000) {
-                       *cp++ = '8' + ((w & 0x1C0) >> 6);
-               } else {
-                       *cp++ = '0' + ((w & 0x1C0) >> 6);
+       /*
+        * Get board configuration information.
+        *
+        * advansys_info() returns the board string from its own static buffer.
+        */
+       cp = (char *)advansys_info(shost);
+       strcat(cp, "\n");
+       cplen = strlen(cp);
+       /* Copy board information. */
+       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+       totcnt += cnt;
+       leftlen -= cnt;
+       if (leftlen == 0) {
+               ASC_DBG(1, "totcnt %d\n", totcnt);
+               return totcnt;
+       }
+       advoffset += cplen;
+       curbuf += cnt;
+
+       /*
+        * Display Wide Board BIOS Information.
+        */
+       if (!ASC_NARROW_BOARD(boardp)) {
+               cp = boardp->prtbuf;
+               cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
+               BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+               cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
+                                 cplen);
+               totcnt += cnt;
+               leftlen -= cnt;
+               if (leftlen == 0) {
+                       ASC_DBG(1, "totcnt %d\n", totcnt);
+                       return totcnt;
                }
+               advoffset += cplen;
+               curbuf += cnt;
+       }
 
-               /* Week of year - 7th, 8th digits. */
-               num = w & 0x003F;
-               *cp++ = '0' + num / 10;
-               num %= 10;
-               *cp++ = '0' + num;
+       /*
+        * Display driver information for each device attached to the board.
+        */
+       cp = boardp->prtbuf;
+       cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
+       BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+       totcnt += cnt;
+       leftlen -= cnt;
+       if (leftlen == 0) {
+               ASC_DBG(1, "totcnt %d\n", totcnt);
+               return totcnt;
+       }
+       advoffset += cplen;
+       curbuf += cnt;
 
-               /*
-                * Third word
-                */
-               w = serialnum[2] & 0x7FFF;
+       /*
+        * Display EEPROM configuration for the board.
+        */
+       cp = boardp->prtbuf;
+       if (ASC_NARROW_BOARD(boardp)) {
+               cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
+       } else {
+               cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
+       }
+       BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+       totcnt += cnt;
+       leftlen -= cnt;
+       if (leftlen == 0) {
+               ASC_DBG(1, "totcnt %d\n", totcnt);
+               return totcnt;
+       }
+       advoffset += cplen;
+       curbuf += cnt;
 
-               /* Serial number - 9th digit. */
-               *cp++ = 'A' + (w / 1000);
+       /*
+        * Display driver configuration and information for the board.
+        */
+       cp = boardp->prtbuf;
+       cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
+       BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+       totcnt += cnt;
+       leftlen -= cnt;
+       if (leftlen == 0) {
+               ASC_DBG(1, "totcnt %d\n", totcnt);
+               return totcnt;
+       }
+       advoffset += cplen;
+       curbuf += cnt;
 
-               /* 10th, 11th, 12th digits. */
-               num = w % 1000;
-               *cp++ = '0' + num / 100;
-               num %= 100;
-               *cp++ = '0' + num / 10;
-               num %= 10;
-               *cp++ = '0' + num;
+#ifdef ADVANSYS_STATS
+       /*
+        * Display driver statistics for the board.
+        */
+       cp = boardp->prtbuf;
+       cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
+       BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+       totcnt += cnt;
+       leftlen -= cnt;
+       if (leftlen == 0) {
+               ASC_DBG(1, "totcnt %d\n", totcnt);
+               return totcnt;
+       }
+       advoffset += cplen;
+       curbuf += cnt;
+#endif /* ADVANSYS_STATS */
 
-               *cp = '\0';     /* Null Terminate the string. */
-               return ASC_TRUE;
+       /*
+        * Display Asc Library dynamic configuration information
+        * for the board.
+        */
+       cp = boardp->prtbuf;
+       if (ASC_NARROW_BOARD(boardp)) {
+               cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
+       } else {
+               cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
        }
-}
+       BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+       cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+       totcnt += cnt;
+       leftlen -= cnt;
+       if (leftlen == 0) {
+               ASC_DBG(1, "totcnt %d\n", totcnt);
+               return totcnt;
+       }
+       advoffset += cplen;
+       curbuf += cnt;
 
-/*
- * asc_prt_asc_board_eeprom()
- *
- * Print board EEPROM configuration.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
-static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
-{
-       asc_board_t *boardp;
-       ASC_DVC_VAR *asc_dvc_varp;
-       int leftlen;
-       int totlen;
-       int len;
-       ASCEEP_CONFIG *ep;
-       int i;
-#ifdef CONFIG_ISA
-       int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
-#endif /* CONFIG_ISA */
-       uchar serialstr[13];
+       ASC_DBG(1, "totcnt %d\n", totcnt);
 
-       boardp = ASC_BOARDP(shost);
-       asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-       ep = &boardp->eep_config.asc_eep;
+       return totcnt;
+}
+#endif /* CONFIG_PROC_FS */
 
-       leftlen = cplen;
-       totlen = len = 0;
+static void asc_scsi_done(struct scsi_cmnd *scp)
+{
+       scsi_dma_unmap(scp);
+       ASC_STATS(scp->device->host, done);
+       scp->scsi_done(scp);
+}
 
-       len = asc_prt_line(cp, leftlen,
-                          "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
-                          shost->host_no);
-       ASC_PRT_NEXT();
+static void AscSetBank(PortAddr iop_base, uchar bank)
+{
+       uchar val;
 
-       if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
-           == ASC_TRUE) {
-               len =
-                   asc_prt_line(cp, leftlen, " Serial Number: %s\n",
-                                serialstr);
-               ASC_PRT_NEXT();
+       val = AscGetChipControl(iop_base) &
+           (~
+            (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
+             CC_CHIP_RESET));
+       if (bank == 1) {
+               val |= CC_BANK_ONE;
+       } else if (bank == 2) {
+               val |= CC_DIAG | CC_BANK_ONE;
        } else {
-               if (ep->adapter_info[5] == 0xBB) {
-                       len = asc_prt_line(cp, leftlen,
-                                          " Default Settings Used for EEPROM-less Adapter.\n");
-                       ASC_PRT_NEXT();
-               } else {
-                       len = asc_prt_line(cp, leftlen,
-                                          " Serial Number Signature Not Present.\n");
-                       ASC_PRT_NEXT();
-               }
+               val &= ~CC_BANK_ONE;
        }
+       AscSetChipControl(iop_base, val);
+}
 
-       len = asc_prt_line(cp, leftlen,
-                          " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-                          ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
-                          ep->max_tag_qng);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
-       ASC_PRT_NEXT();
+static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
+{
+       AscSetBank(iop_base, 1);
+       AscWriteChipIH(iop_base, ins_code);
+       AscSetBank(iop_base, 0);
+}
 
-       len = asc_prt_line(cp, leftlen, " Target ID:           ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %d", i);
-               ASC_PRT_NEXT();
+static int AscStartChip(PortAddr iop_base)
+{
+       AscSetChipControl(iop_base, 0);
+       if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+               return (0);
        }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+       return (1);
+}
 
-       len = asc_prt_line(cp, leftlen, " Disconnects:         ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (ep->
-                                   disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+static int AscStopChip(PortAddr iop_base)
+{
+       uchar cc_val;
 
-       len = asc_prt_line(cp, leftlen, " Command Queuing:     ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (ep->
-                                   use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
+       cc_val =
+           AscGetChipControl(iop_base) &
+           (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+       AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
+       AscSetChipIH(iop_base, INS_HALT);
+       AscSetChipIH(iop_base, INS_RFLAG_WTM);
+       if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+               return (0);
        }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+       return (1);
+}
 
-       len = asc_prt_line(cp, leftlen, " Start Motor:         ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (ep->
-                                   start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
+static int AscIsChipHalted(PortAddr iop_base)
+{
+       if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+               if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+                       return (1);
+               }
        }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+       return (0);
+}
 
-       len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (ep->
-                                   init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
+static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
+{
+       PortAddr iop_base;
+       int i = 10;
+
+       iop_base = asc_dvc->iop_base;
+       while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
+              && (i-- > 0)) {
+               mdelay(100);
        }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+       AscStopChip(iop_base);
+       AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+       udelay(60);
+       AscSetChipIH(iop_base, INS_RFLAG_WTM);
+       AscSetChipIH(iop_base, INS_HALT);
+       AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+       AscSetChipControl(iop_base, CC_HALT);
+       mdelay(200);
+       AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+       AscSetChipStatus(iop_base, 0);
+       return (AscIsChipHalted(iop_base));
+}
 
-#ifdef CONFIG_ISA
-       if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
-               len = asc_prt_line(cp, leftlen,
-                                  " Host ISA DMA speed:   %d MB/S\n",
-                                  isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
-               ASC_PRT_NEXT();
+static int AscFindSignature(PortAddr iop_base)
+{
+       ushort sig_word;
+
+       ASC_DBG(1, "AscGetChipSignatureByte(0x%x) 0x%x\n",
+                iop_base, AscGetChipSignatureByte(iop_base));
+       if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
+               ASC_DBG(1, "AscGetChipSignatureWord(0x%x) 0x%x\n",
+                        iop_base, AscGetChipSignatureWord(iop_base));
+               sig_word = AscGetChipSignatureWord(iop_base);
+               if ((sig_word == (ushort)ASC_1000_ID0W) ||
+                   (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
+                       return (1);
+               }
        }
-#endif /* CONFIG_ISA */
+       return (0);
+}
 
-       return totlen;
+static void AscEnableInterrupt(PortAddr iop_base)
+{
+       ushort cfg;
+
+       cfg = AscGetChipCfgLsw(iop_base);
+       AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
 }
 
-/*
- * asc_prt_adv_board_eeprom()
- *
- * Print board EEPROM configuration.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
-static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
+static void AscDisableInterrupt(PortAddr iop_base)
 {
-       asc_board_t *boardp;
-       ADV_DVC_VAR *adv_dvc_varp;
-       int leftlen;
-       int totlen;
-       int len;
-       int i;
-       char *termstr;
-       uchar serialstr[13];
-       ADVEEP_3550_CONFIG *ep_3550 = NULL;
-       ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
-       ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
-       ushort word;
-       ushort *wordp;
-       ushort sdtr_speed = 0;
+       ushort cfg;
 
-       boardp = ASC_BOARDP(shost);
-       adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               ep_3550 = &boardp->eep_config.adv_3550_eep;
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+       cfg = AscGetChipCfgLsw(iop_base);
+       AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+}
+
+static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
+{
+       unsigned char byte_data;
+       unsigned short word_data;
+
+       if (isodd_word(addr)) {
+               AscSetChipLramAddr(iop_base, addr - 1);
+               word_data = AscGetChipLramData(iop_base);
+               byte_data = (word_data >> 8) & 0xFF;
        } else {
-               ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+               AscSetChipLramAddr(iop_base, addr);
+               word_data = AscGetChipLramData(iop_base);
+               byte_data = word_data & 0xFF;
        }
+       return byte_data;
+}
 
-       leftlen = cplen;
-       totlen = len = 0;
+static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
+{
+       ushort word_data;
 
-       len = asc_prt_line(cp, leftlen,
-                          "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
-                          shost->host_no);
-       ASC_PRT_NEXT();
+       AscSetChipLramAddr(iop_base, addr);
+       word_data = AscGetChipLramData(iop_base);
+       return (word_data);
+}
 
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               wordp = &ep_3550->serial_number_word1;
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               wordp = &ep_38C0800->serial_number_word1;
-       } else {
-               wordp = &ep_38C1600->serial_number_word1;
-       }
+#if CC_VERY_LONG_SG_LIST
+static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
+{
+       ushort val_low, val_high;
+       ASC_DCNT dword_data;
 
-       if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
-               len =
-                   asc_prt_line(cp, leftlen, " Serial Number: %s\n",
-                                serialstr);
-               ASC_PRT_NEXT();
-       } else {
-               len = asc_prt_line(cp, leftlen,
-                                  " Serial Number Signature Not Present.\n");
-               ASC_PRT_NEXT();
-       }
+       AscSetChipLramAddr(iop_base, addr);
+       val_low = AscGetChipLramData(iop_base);
+       val_high = AscGetChipLramData(iop_base);
+       dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
+       return (dword_data);
+}
+#endif /* CC_VERY_LONG_SG_LIST */
 
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               len = asc_prt_line(cp, leftlen,
-                                  " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-                                  ep_3550->adapter_scsi_id,
-                                  ep_3550->max_host_qng, ep_3550->max_dvc_qng);
-               ASC_PRT_NEXT();
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               len = asc_prt_line(cp, leftlen,
-                                  " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-                                  ep_38C0800->adapter_scsi_id,
-                                  ep_38C0800->max_host_qng,
-                                  ep_38C0800->max_dvc_qng);
-               ASC_PRT_NEXT();
-       } else {
-               len = asc_prt_line(cp, leftlen,
-                                  " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-                                  ep_38C1600->adapter_scsi_id,
-                                  ep_38C1600->max_host_qng,
-                                  ep_38C1600->max_dvc_qng);
-               ASC_PRT_NEXT();
-       }
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               word = ep_3550->termination;
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               word = ep_38C0800->termination_lvd;
-       } else {
-               word = ep_38C1600->termination_lvd;
-       }
-       switch (word) {
-       case 1:
-               termstr = "Low Off/High Off";
-               break;
-       case 2:
-               termstr = "Low Off/High On";
-               break;
-       case 3:
-               termstr = "Low On/High On";
-               break;
-       default:
-       case 0:
-               termstr = "Automatic";
-               break;
-       }
+static void
+AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
+{
+       int i;
 
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               len = asc_prt_line(cp, leftlen,
-                                  " termination: %u (%s), bios_ctrl: 0x%x\n",
-                                  ep_3550->termination, termstr,
-                                  ep_3550->bios_ctrl);
-               ASC_PRT_NEXT();
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               len = asc_prt_line(cp, leftlen,
-                                  " termination: %u (%s), bios_ctrl: 0x%x\n",
-                                  ep_38C0800->termination_lvd, termstr,
-                                  ep_38C0800->bios_ctrl);
-               ASC_PRT_NEXT();
-       } else {
-               len = asc_prt_line(cp, leftlen,
-                                  " termination: %u (%s), bios_ctrl: 0x%x\n",
-                                  ep_38C1600->termination_lvd, termstr,
-                                  ep_38C1600->bios_ctrl);
-               ASC_PRT_NEXT();
+       AscSetChipLramAddr(iop_base, s_addr);
+       for (i = 0; i < words; i++) {
+               AscSetChipLramData(iop_base, set_wval);
        }
+}
 
-       len = asc_prt_line(cp, leftlen, " Target ID:           ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %X", i);
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
+{
+       AscSetChipLramAddr(iop_base, addr);
+       AscSetChipLramData(iop_base, word_val);
+}
 
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               word = ep_3550->disc_enable;
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               word = ep_38C0800->disc_enable;
+static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
+{
+       ushort word_data;
+
+       if (isodd_word(addr)) {
+               addr--;
+               word_data = AscReadLramWord(iop_base, addr);
+               word_data &= 0x00FF;
+               word_data |= (((ushort)byte_val << 8) & 0xFF00);
        } else {
-               word = ep_38C1600->disc_enable;
-       }
-       len = asc_prt_line(cp, leftlen, " Disconnects:         ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               word = ep_3550->tagqng_able;
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               word = ep_38C0800->tagqng_able;
-       } else {
-               word = ep_38C1600->tagqng_able;
-       }
-       len = asc_prt_line(cp, leftlen, " Command Queuing:     ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               word = ep_3550->start_motor;
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               word = ep_38C0800->start_motor;
-       } else {
-               word = ep_38C1600->start_motor;
-       }
-       len = asc_prt_line(cp, leftlen, " Start Motor:         ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
-               ASC_PRT_NEXT();
-               for (i = 0; i <= ADV_MAX_TID; i++) {
-                       len = asc_prt_line(cp, leftlen, " %c",
-                                          (ep_3550->
-                                           sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
-                                          'Y' : 'N');
-                       ASC_PRT_NEXT();
-               }
-               len = asc_prt_line(cp, leftlen, "\n");
-               ASC_PRT_NEXT();
-       }
-
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               len = asc_prt_line(cp, leftlen, " Ultra Transfer:      ");
-               ASC_PRT_NEXT();
-               for (i = 0; i <= ADV_MAX_TID; i++) {
-                       len = asc_prt_line(cp, leftlen, " %c",
-                                          (ep_3550->
-                                           ultra_able & ADV_TID_TO_TIDMASK(i))
-                                          ? 'Y' : 'N');
-                       ASC_PRT_NEXT();
-               }
-               len = asc_prt_line(cp, leftlen, "\n");
-               ASC_PRT_NEXT();
-       }
-
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-               word = ep_3550->wdtr_able;
-       } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-               word = ep_38C0800->wdtr_able;
-       } else {
-               word = ep_38C1600->wdtr_able;
-       }
-       len = asc_prt_line(cp, leftlen, " Wide Transfer:       ");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               len = asc_prt_line(cp, leftlen, " %c",
-                                  (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-               ASC_PRT_NEXT();
+               word_data = AscReadLramWord(iop_base, addr);
+               word_data &= 0xFF00;
+               word_data |= ((ushort)byte_val & 0x00FF);
        }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+       AscWriteLramWord(iop_base, addr, word_data);
+}
 
-       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
-           adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
-               len = asc_prt_line(cp, leftlen,
-                                  " Synchronous Transfer Speed (Mhz):\n  ");
-               ASC_PRT_NEXT();
-               for (i = 0; i <= ADV_MAX_TID; i++) {
-                       char *speed_str;
+/*
+ * Copy 2 bytes to LRAM.
+ *
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when written to LRAM.
+ */
+static void
+AscMemWordCopyPtrToLram(PortAddr iop_base,
+                       ushort s_addr, uchar *s_buffer, int words)
+{
+       int i;
 
-                       if (i == 0) {
-                               sdtr_speed = adv_dvc_varp->sdtr_speed1;
-                       } else if (i == 4) {
-                               sdtr_speed = adv_dvc_varp->sdtr_speed2;
-                       } else if (i == 8) {
-                               sdtr_speed = adv_dvc_varp->sdtr_speed3;
-                       } else if (i == 12) {
-                               sdtr_speed = adv_dvc_varp->sdtr_speed4;
-                       }
-                       switch (sdtr_speed & ADV_MAX_TID) {
-                       case 0:
-                               speed_str = "Off";
-                               break;
-                       case 1:
-                               speed_str = "  5";
-                               break;
-                       case 2:
-                               speed_str = " 10";
-                               break;
-                       case 3:
-                               speed_str = " 20";
-                               break;
-                       case 4:
-                               speed_str = " 40";
-                               break;
-                       case 5:
-                               speed_str = " 80";
-                               break;
-                       default:
-                               speed_str = "Unk";
-                               break;
-                       }
-                       len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
-                       ASC_PRT_NEXT();
-                       if (i == 7) {
-                               len = asc_prt_line(cp, leftlen, "\n  ");
-                               ASC_PRT_NEXT();
-                       }
-                       sdtr_speed >>= 4;
-               }
-               len = asc_prt_line(cp, leftlen, "\n");
-               ASC_PRT_NEXT();
+       AscSetChipLramAddr(iop_base, s_addr);
+       for (i = 0; i < 2 * words; i += 2) {
+               /*
+                * On a little-endian system the second argument below
+                * produces a little-endian ushort which is written to
+                * LRAM in little-endian order. On a big-endian system
+                * the second argument produces a big-endian ushort which
+                * is "transparently" byte-swapped by outpw() and written
+                * in little-endian order to LRAM.
+                */
+               outpw(iop_base + IOP_RAM_DATA,
+                     ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
        }
-
-       return totlen;
 }
 
 /*
- * asc_prt_driver_conf()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
+ * Copy 4 bytes to LRAM.
  *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when writen to LRAM.
  */
-static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
+static void
+AscMemDWordCopyPtrToLram(PortAddr iop_base,
+                        ushort s_addr, uchar *s_buffer, int dwords)
 {
-       asc_board_t *boardp;
-       int leftlen;
-       int totlen;
-       int len;
-       int chip_scsi_id;
-
-       boardp = ASC_BOARDP(shost);
-
-       leftlen = cplen;
-       totlen = len = 0;
-
-       len = asc_prt_line(cp, leftlen,
-                          "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
-                          shost->host_no);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
-                          shost->host_busy, shost->last_reset, shost->max_id,
-                          shost->max_lun, shost->max_channel);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
-                          shost->unique_id, shost->can_queue, shost->this_id,
-                          shost->sg_tablesize, shost->cmd_per_lun);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " unchecked_isa_dma %d, use_clustering %d\n",
-                          shost->unchecked_isa_dma, shost->use_clustering);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
-                          boardp->flags, boardp->last_reset, jiffies,
-                          boardp->asc_n_io_port);
-       ASC_PRT_NEXT();
-
-       /* 'shost->n_io_port' may be truncated because it is only one byte. */
-       len = asc_prt_line(cp, leftlen,
-                          " io_port 0x%x, n_io_port 0x%x\n",
-                          shost->io_port, shost->n_io_port);
-       ASC_PRT_NEXT();
+       int i;
 
-       if (ASC_NARROW_BOARD(boardp)) {
-               chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
-       } else {
-               chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+       AscSetChipLramAddr(iop_base, s_addr);
+       for (i = 0; i < 4 * dwords; i += 4) {
+               outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);   /* LSW */
+               outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]);       /* MSW */
        }
-
-       return totlen;
 }
 
 /*
- * asc_prt_asc_board_info()
- *
- * Print dynamic board configuration information.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
+ * Copy 2 bytes from LRAM.
  *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
+ * The source data is assumed to be in little-endian order in LRAM
+ * and is maintained in little-endian order when written to memory.
  */
-static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
+static void
+AscMemWordCopyPtrFromLram(PortAddr iop_base,
+                         ushort s_addr, uchar *d_buffer, int words)
 {
-       asc_board_t *boardp;
-       int chip_scsi_id;
-       int leftlen;
-       int totlen;
-       int len;
-       ASC_DVC_VAR *v;
-       ASC_DVC_CFG *c;
        int i;
-       int renegotiate = 0;
+       ushort word;
 
-       boardp = ASC_BOARDP(shost);
-       v = &boardp->dvc_var.asc_dvc_var;
-       c = &boardp->dvc_cfg.asc_dvc_cfg;
-       chip_scsi_id = c->chip_scsi_id;
-
-       leftlen = cplen;
-       totlen = len = 0;
-
-       len = asc_prt_line(cp, leftlen,
-                          "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
-                          shost->host_no);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
-                          c->chip_version, c->lib_version, c->lib_serial_no,
-                          c->mcode_date);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " mcode_version 0x%x, err_code %u\n",
-                          c->mcode_version, v->err_code);
-       ASC_PRT_NEXT();
-
-       /* Current number of commands waiting for the host. */
-       len = asc_prt_line(cp, leftlen,
-                          " Total Command Pending: %d\n", v->cur_total_qng);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen, " Command Queuing:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-               len = asc_prt_line(cp, leftlen, " %X:%c",
-                                  i,
-                                  (v->
-                                   use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
-                                  'Y' : 'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       /* Current number of commands waiting for a device. */
-       len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-               len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       /* Current limit on number of commands that can be sent to a device. */
-       len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-               len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
-               ASC_PRT_NEXT();
+       AscSetChipLramAddr(iop_base, s_addr);
+       for (i = 0; i < 2 * words; i += 2) {
+               word = inpw(iop_base + IOP_RAM_DATA);
+               d_buffer[i] = word & 0xff;
+               d_buffer[i + 1] = (word >> 8) & 0xff;
        }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+}
 
-       /* Indicate whether the device has returned queue full status. */
-       len = asc_prt_line(cp, leftlen, " Command Queue Full:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-               if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
-                       len = asc_prt_line(cp, leftlen, " %X:Y-%d",
-                                          i, boardp->queue_full_cnt[i]);
-               } else {
-                       len = asc_prt_line(cp, leftlen, " %X:N", i);
-               }
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
+{
+       ASC_DCNT sum;
+       int i;
 
-       len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-               len = asc_prt_line(cp, leftlen, " %X:%c",
-                                  i,
-                                  (v->
-                                   sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
+       sum = 0L;
+       for (i = 0; i < words; i++, s_addr += 2) {
+               sum += AscReadLramWord(iop_base, s_addr);
        }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               uchar syn_period_ix;
-
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
-                   ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-
-               len = asc_prt_line(cp, leftlen, "  %X:", i);
-               ASC_PRT_NEXT();
-
-               if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
-                       len = asc_prt_line(cp, leftlen, " Asynchronous");
-                       ASC_PRT_NEXT();
-               } else {
-                       syn_period_ix =
-                           (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
-                                                          1);
-
-                       len = asc_prt_line(cp, leftlen,
-                                          " Transfer Period Factor: %d (%d.%d Mhz),",
-                                          v->sdtr_period_tbl[syn_period_ix],
-                                          250 /
-                                          v->sdtr_period_tbl[syn_period_ix],
-                                          ASC_TENTHS(250,
-                                                     v->
-                                                     sdtr_period_tbl
-                                                     [syn_period_ix]));
-                       ASC_PRT_NEXT();
+       return (sum);
+}
 
-                       len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
-                                          boardp->
-                                          sdtr_data[i] & ASC_SYN_MAX_OFFSET);
-                       ASC_PRT_NEXT();
-               }
+static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
+{
+       uchar i;
+       ushort s_addr;
+       PortAddr iop_base;
+       ushort warn_code;
 
-               if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-                       len = asc_prt_line(cp, leftlen, "*\n");
-                       renegotiate = 1;
-               } else {
-                       len = asc_prt_line(cp, leftlen, "\n");
-               }
-               ASC_PRT_NEXT();
+       iop_base = asc_dvc->iop_base;
+       warn_code = 0;
+       AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+                         (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
+                                   64) >> 1));
+       i = ASC_MIN_ACTIVE_QNO;
+       s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+                        (uchar)(i + 1));
+       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+                        (uchar)(asc_dvc->max_total_qng));
+       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+                        (uchar)i);
+       i++;
+       s_addr += ASC_QBLK_SIZE;
+       for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+               AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+                                (uchar)(i + 1));
+               AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+                                (uchar)(i - 1));
+               AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+                                (uchar)i);
        }
-
-       if (renegotiate) {
-               len = asc_prt_line(cp, leftlen,
-                                  " * = Re-negotiation pending before next command.\n");
-               ASC_PRT_NEXT();
+       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+                        (uchar)ASC_QLINK_END);
+       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+                        (uchar)(asc_dvc->max_total_qng - 1));
+       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+                        (uchar)asc_dvc->max_total_qng);
+       i++;
+       s_addr += ASC_QBLK_SIZE;
+       for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
+            i++, s_addr += ASC_QBLK_SIZE) {
+               AscWriteLramByte(iop_base,
+                                (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
+               AscWriteLramByte(iop_base,
+                                (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
+               AscWriteLramByte(iop_base,
+                                (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
        }
-
-       return totlen;
+       return warn_code;
 }
 
-/*
- * asc_prt_adv_board_info()
- *
- * Print dynamic board configuration information.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
-static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
+static ASC_DCNT
+AscLoadMicroCode(PortAddr iop_base,
+                ushort s_addr, uchar *mcode_buf, ushort mcode_size)
 {
-       asc_board_t *boardp;
-       int leftlen;
-       int totlen;
-       int len;
-       int i;
-       ADV_DVC_VAR *v;
-       ADV_DVC_CFG *c;
-       AdvPortAddr iop_base;
-       ushort chip_scsi_id;
-       ushort lramword;
-       uchar lrambyte;
-       ushort tagqng_able;
-       ushort sdtr_able, wdtr_able;
-       ushort wdtr_done, sdtr_done;
-       ushort period = 0;
-       int renegotiate = 0;
-
-       boardp = ASC_BOARDP(shost);
-       v = &boardp->dvc_var.adv_dvc_var;
-       c = &boardp->dvc_cfg.adv_dvc_cfg;
-       iop_base = v->iop_base;
-       chip_scsi_id = v->chip_scsi_id;
-
-       leftlen = cplen;
-       totlen = len = 0;
+       ASC_DCNT chksum;
+       ushort mcode_word_size;
+       ushort mcode_chksum;
 
-       len = asc_prt_line(cp, leftlen,
-                          "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
-                          shost->host_no);
-       ASC_PRT_NEXT();
+       /* Write the microcode buffer starting at LRAM address 0. */
+       mcode_word_size = (ushort)(mcode_size >> 1);
+       AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+       AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
 
-       len = asc_prt_line(cp, leftlen,
-                          " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
-                          v->iop_base,
-                          AdvReadWordRegister(iop_base,
-                                              IOPW_SCSI_CFG1) & CABLE_DETECT,
-                          v->err_code);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
-                          c->chip_version, c->lib_version, c->mcode_date,
-                          c->mcode_version);
-       ASC_PRT_NEXT();
-
-       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-       len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-
-               len = asc_prt_line(cp, leftlen, " %X:%c",
-                                  i,
-                                  (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen, " Queue Limit:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-
-               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
-                               lrambyte);
-
-               len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen, " Command Pending:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
+       chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+       ASC_DBG(1, "chksum 0x%lx\n", (ulong)chksum);
+       mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
+                                                (ushort)ASC_CODE_SEC_BEG,
+                                                (ushort)((mcode_size -
+                                                          s_addr - (ushort)
+                                                          ASC_CODE_SEC_BEG) /
+                                                         2));
+       ASC_DBG(1, "mcode_chksum 0x%lx\n", (ulong)mcode_chksum);
+       AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+       AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+       return chksum;
+}
 
-               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
-                               lrambyte);
+/* Microcode buffer is kept after initialization for error recovery. */
+static uchar _asc_mcode_buf[] = {
+       0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05,
+       0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04,
+       0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
+       0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
+       0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98,
+       0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
+       0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
+       0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
+       0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
+       0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04,
+       0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
+       0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
+       0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
+       0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
+       0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
+       0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
+       0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01,
+       0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
+       0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
+       0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
+       0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
+       0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
+       0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
+       0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
+       0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
+       0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23,
+       0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
+       0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
+       0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
+       0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
+       0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
+       0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
+       0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
+       0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46,
+       0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
+       0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
+       0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02,
+       0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82,
+       0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
+       0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
+       0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02,
+       0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
+       0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
+       0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
+       0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
+       0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02,
+       0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
+       0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
+       0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01,
+       0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
+       0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
+       0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
+       0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39,
+       0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
+       0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
+       0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
+       0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
+       0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01,
+       0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
+       0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
+       0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33,
+       0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83,
+       0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
+       0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
+       0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
+       0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
+       0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
+       0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
+       0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
+       0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+       0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
+       0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+       0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
+       0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84,
+       0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
+       0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
+       0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95,
+       0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
+       0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
+       0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
+       0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
+       0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
+       0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
+       0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
+       0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2,
+       0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
+       0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
+       0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
+       0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04,
+       0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
+       0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
+       0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
+       0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
+       0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
+       0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
+       0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
+       0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC,
+       0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95,
+       0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
+       0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
+       0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01,
+       0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
+       0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
+       0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
+       0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
+       0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05,
+       0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
+       0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
+       0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85,
+       0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63,
+       0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
+       0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
+       0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85,
+       0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
+       0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
+       0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
+       0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
+       0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87,
+       0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
+       0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
+       0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33,
+       0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60,
+       0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
+       0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
+       0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA,
+       0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
+       0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
+       0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
+       0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
+       0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
+       0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
+       0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
+       0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6,
+       0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06,
+       0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
+       0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
+       0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03,
+       0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
+       0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
+       0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
+       0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
+       0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88,
+       0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
+       0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
+       0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07,
+       0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84,
+       0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
+       0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
+       0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04,
+       0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
+       0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
+       0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
+       0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
+       0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04,
+       0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
+       0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
+       0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05,
+       0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23,
+       0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
+       0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
+       0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
+       0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
+       0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
+       0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
+       0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
+       0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01,
+       0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
+       0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
+       0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95,
+       0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88,
+       0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
+       0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
+       0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09,
+       0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
+       0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
+       0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
+       0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
+       0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73,
+       0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
+       0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
+       0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77,
+       0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23,
+       0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
+};
 
-               len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+static unsigned short _asc_mcode_size = sizeof(_asc_mcode_buf);
+static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
 
-       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-       len = asc_prt_line(cp, leftlen, " Wide Enabled:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc3550_buf[] = {
+       0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
+       0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00,
+       0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7,
+       0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
+       0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
+       0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54,
+       0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01,
+       0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
+       0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
+       0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+       0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
+       0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
+       0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
+       0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
+       0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a,
+       0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
+       0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
+       0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00,
+       0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c,
+       0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
+       0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
+       0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10,
+       0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56,
+       0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
+       0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
+       0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
+       0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10,
+       0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
+       0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
+       0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55,
+       0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0,
+       0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
+       0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
+       0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01,
+       0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02,
+       0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
+       0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
+       0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13,
+       0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18,
+       0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
+       0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
+       0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90,
+       0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10,
+       0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
+       0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+       0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00,
+       0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+       0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
+       0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+       0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe,
+       0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02,
+       0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
+       0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
+       0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe,
+       0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
+       0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
+       0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
+       0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02,
+       0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02,
+       0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
+       0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
+       0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10,
+       0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d,
+       0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
+       0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+       0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0,
+       0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe,
+       0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
+       0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
+       0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d,
+       0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a,
+       0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
+       0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+       0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03,
+       0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe,
+       0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
+       0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
+       0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0,
+       0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f,
+       0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
+       0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
+       0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2,
+       0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11,
+       0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
+       0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
+       0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe,
+       0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1,
+       0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
+       0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
+       0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28,
+       0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02,
+       0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
+       0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+       0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04,
+       0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe,
+       0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
+       0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
+       0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c,
+       0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe,
+       0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
+       0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
+       0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90,
+       0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67,
+       0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
+       0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
+       0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2,
+       0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04,
+       0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
+       0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
+       0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05,
+       0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1,
+       0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
+       0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
+       0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d,
+       0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b,
+       0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
+       0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
+       0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19,
+       0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05,
+       0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
+       0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
+       0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48,
+       0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d,
+       0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
+       0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
+       0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4,
+       0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87,
+       0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
+       0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
+       0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a,
+       0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
+       0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
+       0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
+       0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
+       0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02,
+       0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
+       0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
+       0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25,
+       0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c,
+       0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
+       0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+       0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a,
+       0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80,
+       0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
+       0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
+       0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
+       0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52,
+       0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
+       0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
+       0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18,
+       0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58,
+       0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
+       0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
+       0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35,
+       0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0,
+       0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
+       0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
+       0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10,
+       0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61,
+       0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
+       0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
+       0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe,
+       0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10,
+       0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
+       0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
+       0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+       0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d,
+       0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
+       0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
+       0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01,
+       0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02,
+       0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
+       0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
+       0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
+       0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77,
+       0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
+       0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
+       0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05,
+       0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56,
+       0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
+       0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
+       0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59,
+       0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00,
+       0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
+       0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
+       0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a,
+       0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d,
+       0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
+       0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
+       0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe,
+       0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51,
+       0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
+       0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+       0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00,
+       0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33,
+       0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
+       0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
+       0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe,
+       0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93,
+       0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
+       0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
+       0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0,
+       0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9,
+       0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
+       0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
+       0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd,
+       0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f,
+       0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
+       0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
+       0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54,
+       0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01,
+       0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
+       0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
+       0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e,
+       0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01,
+       0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
+       0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
+       0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02,
+       0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe,
+       0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
+       0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
+       0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35,
+       0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f,
+       0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
+       0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
+       0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b,
+       0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea,
+       0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
+       0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
+       0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47,
+       0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38,
+       0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
+       0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
+       0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe,
+       0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce,
+       0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
+       0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
+       0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe,
+       0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe,
+       0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
+       0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
+       0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4,
+       0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe,
+       0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
+       0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
+       0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11,
+       0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12,
+       0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
+       0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
+       0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc,
+       0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23,
+       0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
+       0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+       0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe,
+       0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+       0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
+       0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
+       0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01,
+       0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+       0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
+       0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+       0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76,
+       0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+       0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
+       0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+       0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48,
+       0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08,
+       0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
+       0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
+       0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0,
+       0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+       0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
+       0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
+       0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a,
+       0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
+       0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
+       0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
+       0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03,
+       0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe,
+       0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
+       0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
+       0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30,
+       0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16,
+       0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
+       0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
+       0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01,
+       0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe,
+       0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
+       0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
+       0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77,
+       0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c,
+       0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
+       0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
+       0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40,
+       0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1,
+       0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
+       0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
+       0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe,
+       0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
+       0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
+       0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
+       0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5,
+       0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c,
+       0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
+       0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
+       0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19,
+       0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e,
+       0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
+       0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
+       0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49,
+       0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f,
+       0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
+       0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
+       0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe,
+       0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c,
+       0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
+       0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
+       0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14,
+       0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a,
+       0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
+       0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
+       0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe,
+       0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc,
+       0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
+       0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+       0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13,
+       0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56,
+       0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+       0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
+       0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c,
+       0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00,
+       0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
+       0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
+       0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01,
+       0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f,
+       0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
+       0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
+       0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2,
+       0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78,
+       0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
+       0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
+       0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00,
+       0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28,
+       0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
+       0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
+       0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4,
+       0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe,
+       0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
+       0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
+       0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe,
+       0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23,
+       0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
+       0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
+       0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26,
+       0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08,
+       0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
+       0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
+       0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44,
+       0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e,
+       0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
+       0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
+       0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03,
+       0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01,
+       0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
+       0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
+       0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03,
+       0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10,
+       0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
+       0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
+       0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01,
+       0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f,
+       0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
+       0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
+       0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90,
+       0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe,
+       0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
+       0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
+       0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
+       0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10,
+       0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
+       0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
+       0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f,
+       0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14,
+       0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
+       0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
+       0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe,
+       0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe,
+       0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
+       0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
+       0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17,
+       0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71,
+       0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
+       0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
+       0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0,
+       0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
+       0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
+       0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
+       0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c,
+       0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17,
+       0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
+       0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
+       0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73,
+       0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e,
+       0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
+       0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
+       0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18,
+       0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2,
+       0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
+       0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
+       0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe,
+       0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12,
+       0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
+       0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+       0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26,
+       0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93,
+       0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
+       0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
+       0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6,
+       0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
+};
 
-               len = asc_prt_line(cp, leftlen, " %X:%c",
-                                  i,
-                                  (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
+static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf);    /* 0x13AD */
+static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL;    /* Expanded little-endian checksum. */
 
-       AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
-       len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-
-               AdvReadWordLram(iop_base,
-                               ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
-                               lramword);
-
-               len = asc_prt_line(cp, leftlen, " %X:%d",
-                                  i, (lramword & 0x8000) ? 16 : 8);
-               ASC_PRT_NEXT();
-
-               if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
-                   (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-                       len = asc_prt_line(cp, leftlen, "*");
-                       ASC_PRT_NEXT();
-                       renegotiate = 1;
-               }
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-       len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
-       ASC_PRT_NEXT();
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-
-               len = asc_prt_line(cp, leftlen, " %X:%c",
-                                  i,
-                                  (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
-                                  'N');
-               ASC_PRT_NEXT();
-       }
-       len = asc_prt_line(cp, leftlen, "\n");
-       ASC_PRT_NEXT();
-
-       AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
-       for (i = 0; i <= ADV_MAX_TID; i++) {
-
-               AdvReadWordLram(iop_base,
-                               ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
-                               lramword);
-               lramword &= ~0x8000;
-
-               if ((chip_scsi_id == i) ||
-                   ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
-                   ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                       continue;
-               }
-
-               len = asc_prt_line(cp, leftlen, "  %X:", i);
-               ASC_PRT_NEXT();
-
-               if ((lramword & 0x1F) == 0) {   /* Check for REQ/ACK Offset 0. */
-                       len = asc_prt_line(cp, leftlen, " Asynchronous");
-                       ASC_PRT_NEXT();
-               } else {
-                       len =
-                           asc_prt_line(cp, leftlen,
-                                        " Transfer Period Factor: ");
-                       ASC_PRT_NEXT();
-
-                       if ((lramword & 0x1F00) == 0x1100) {    /* 80 Mhz */
-                               len =
-                                   asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
-                               ASC_PRT_NEXT();
-                       } else if ((lramword & 0x1F00) == 0x1000) {     /* 40 Mhz */
-                               len =
-                                   asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
-                               ASC_PRT_NEXT();
-                       } else {        /* 20 Mhz or below. */
-
-                               period = (((lramword >> 8) * 25) + 50) / 4;
-
-                               if (period == 0) {      /* Should never happen. */
-                                       len =
-                                           asc_prt_line(cp, leftlen,
-                                                        "%d (? Mhz), ");
-                                       ASC_PRT_NEXT();
-                               } else {
-                                       len = asc_prt_line(cp, leftlen,
-                                                          "%d (%d.%d Mhz),",
-                                                          period, 250 / period,
-                                                          ASC_TENTHS(250,
-                                                                     period));
-                                       ASC_PRT_NEXT();
-                               }
-                       }
-
-                       len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
-                                          lramword & 0x1F);
-                       ASC_PRT_NEXT();
-               }
-
-               if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-                       len = asc_prt_line(cp, leftlen, "*\n");
-                       renegotiate = 1;
-               } else {
-                       len = asc_prt_line(cp, leftlen, "\n");
-               }
-               ASC_PRT_NEXT();
-       }
-
-       if (renegotiate) {
-               len = asc_prt_line(cp, leftlen,
-                                  " * = Re-negotiation pending before next command.\n");
-               ASC_PRT_NEXT();
-       }
-
-       return totlen;
-}
-
-/*
- * asc_proc_copy()
- *
- * Copy proc information to a read buffer taking into account the current
- * read offset in the file and the remaining space in the read buffer.
- */
-static int
-asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
-             char *cp, int cplen)
-{
-       int cnt = 0;
-
-       ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
-                (unsigned)offset, (unsigned)advoffset, cplen);
-       if (offset <= advoffset) {
-               /* Read offset below current offset, copy everything. */
-               cnt = min(cplen, leftlen);
-               ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
-                        (ulong)curbuf, (ulong)cp, cnt);
-               memcpy(curbuf, cp, cnt);
-       } else if (offset < advoffset + cplen) {
-               /* Read offset within current range, partial copy. */
-               cnt = (advoffset + cplen) - offset;
-               cp = (cp + cplen) - cnt;
-               cnt = min(cnt, leftlen);
-               ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
-                        (ulong)curbuf, (ulong)cp, cnt);
-               memcpy(curbuf, cp, cnt);
-       }
-       return cnt;
-}
-
-/*
- * asc_prt_line()
- *
- * If 'cp' is NULL print to the console, otherwise print to a buffer.
- *
- * Return 0 if printing to the console, otherwise return the number of
- * bytes written to the buffer.
- *
- * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
- * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
- */
-static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
-{
-       va_list args;
-       int ret;
-       char s[ASC_PRTLINE_SIZE];
-
-       va_start(args, fmt);
-       ret = vsprintf(s, fmt, args);
-       ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
-       if (buf == NULL) {
-               (void)printk(s);
-               ret = 0;
-       } else {
-               ret = min(buflen, ret);
-               memcpy(buf, s, ret);
-       }
-       va_end(args);
-       return ret;
-}
-#endif /* CONFIG_PROC_FS */
-
-/*
- * --- Functions Required by the Asc Library
- */
-
-/*
- * Delay for 'n' milliseconds. Don't use the 'jiffies'
- * global variable which is incremented once every 5 ms
- * from a timer interrupt, because this function may be
- * called when interrupts are disabled.
- */
-static void DvcSleepMilliSecond(ADV_DCNT n)
-{
-       ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
-       mdelay(n);
-}
-
-/*
- * Currently and inline noop but leave as a placeholder.
- * Leave DvcEnterCritical() as a noop placeholder.
- */
-static inline ulong DvcEnterCritical(void)
-{
-       return 0;
-}
-
-/*
- * Critical sections are all protected by the board spinlock.
- * Leave DvcLeaveCritical() as a noop placeholder.
- */
-static inline void DvcLeaveCritical(ulong flags)
-{
-       return;
-}
-
-/*
- * void
- * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
- *
- * Calling/Exit State:
- *    none
- *
- * Description:
- *     Output an ASC_SCSI_Q structure to the chip
- */
-static void
-DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
-{
-       int i;
-
-       ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
-       AscSetChipLramAddr(iop_base, s_addr);
-       for (i = 0; i < 2 * words; i += 2) {
-               if (i == 4 || i == 20) {
-                       continue;
-               }
-               outpw(iop_base + IOP_RAM_DATA,
-                     ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
-       }
-}
-
-/*
- * void
- * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
- *
- * Calling/Exit State:
- *    none
- *
- * Description:
- *     Input an ASC_QDONE_INFO structure from the chip
- */
-static void
-DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
-{
-       int i;
-       ushort word;
-
-       AscSetChipLramAddr(iop_base, s_addr);
-       for (i = 0; i < 2 * words; i += 2) {
-               if (i == 10) {
-                       continue;
-               }
-               word = inpw(iop_base + IOP_RAM_DATA);
-               inbuf[i] = word & 0xff;
-               inbuf[i + 1] = (word >> 8) & 0xff;
-       }
-       ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
-}
-
-/*
- * Read a PCI configuration byte.
- */
-static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
-{
-#ifdef CONFIG_PCI
-       uchar byte_data;
-       pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
-       return byte_data;
-#else /* !defined(CONFIG_PCI) */
-       return 0;
-#endif /* !defined(CONFIG_PCI) */
-}
-
-/*
- * Write a PCI configuration byte.
- */
-static void __init
-DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
-{
-#ifdef CONFIG_PCI
-       pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
-#endif /* CONFIG_PCI */
-}
-
-/*
- * Return the BIOS address of the adapter at the specified
- * I/O port and with the specified bus type.
- */
-static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
-{
-       ushort cfg_lsw;
-       ushort bios_addr;
-
-       /*
-        * The PCI BIOS is re-located by the motherboard BIOS. Because
-        * of this the driver can not determine where a PCI BIOS is
-        * loaded and executes.
-        */
-       if (bus_type & ASC_IS_PCI) {
-               return (0);
-       }
-#ifdef CONFIG_ISA
-       if ((bus_type & ASC_IS_EISA) != 0) {
-               cfg_lsw = AscGetEisaChipCfg(iop_base);
-               cfg_lsw &= 0x000F;
-               bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
-                                    (cfg_lsw * ASC_BIOS_BANK_SIZE));
-               return (bios_addr);
-       }                       /* if */
-#endif /* CONFIG_ISA */
-
-       cfg_lsw = AscGetChipCfgLsw(iop_base);
-
-       /*
-        *  ISA PnP uses the top bit as the 32K BIOS flag
-        */
-       if (bus_type == ASC_IS_ISAPNP) {
-               cfg_lsw &= 0x7FFF;
-       }
-       /* if */
-       bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
-                            ASC_BIOS_MIN_ADDR);
-       return (bios_addr);
-}
-
-/*
- * --- Functions Required by the Adv Library
- */
-
-/*
- * DvcGetPhyAddr()
- *
- * Return the physical address of 'vaddr' and set '*lenp' to the
- * number of physically contiguous bytes that follow 'vaddr'.
- * 'flag' indicates the type of structure whose physical address
- * is being translated.
- *
- * Note: Because Linux currently doesn't page the kernel and all
- * kernel buffers are physically contiguous, leave '*lenp' unchanged.
- */
-ADV_PADDR
-DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
-             uchar *vaddr, ADV_SDCNT *lenp, int flag)
-{
-       ADV_PADDR paddr;
-
-       paddr = virt_to_bus(vaddr);
-
-       ASC_DBG4(4,
-                "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
-                (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
-                (ulong)paddr);
-
-       return paddr;
-}
-
-/*
- * Read a PCI configuration byte.
- */
-static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
-{
-#ifdef CONFIG_PCI
-       uchar byte_data;
-       pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
-       return byte_data;
-#else /* CONFIG_PCI */
-       return 0;
-#endif /* CONFIG_PCI */
-}
-
-/*
- * Write a PCI configuration byte.
- */
-static void __init
-DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
-{
-#ifdef CONFIG_PCI
-       pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
-#else /* CONFIG_PCI */
-       return;
-#endif /* CONFIG_PCI */
-}
-
-/*
- * --- Tracing and Debugging Functions
- */
-
-#ifdef ADVANSYS_STATS
-#ifdef CONFIG_PROC_FS
-/*
- * asc_prt_board_stats()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
-static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
-{
-       int leftlen;
-       int totlen;
-       int len;
-       struct asc_stats *s;
-       asc_board_t *boardp;
-
-       leftlen = cplen;
-       totlen = len = 0;
-
-       boardp = ASC_BOARDP(shost);
-       s = &boardp->asc_stats;
-
-       len = asc_prt_line(cp, leftlen,
-                          "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
-                          shost->host_no);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
-                          s->queuecommand, s->reset, s->biosparam,
-                          s->interrupt);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
-                          s->callback, s->done, s->build_error,
-                          s->adv_build_noreq, s->adv_build_nosg);
-       ASC_PRT_NEXT();
-
-       len = asc_prt_line(cp, leftlen,
-                          " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
-                          s->exe_noerror, s->exe_busy, s->exe_error,
-                          s->exe_unknown);
-       ASC_PRT_NEXT();
-
-       /*
-        * Display data transfer statistics.
-        */
-       if (s->cont_cnt > 0) {
-               len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
-               ASC_PRT_NEXT();
-
-               len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
-                                  s->cont_xfer / 2,
-                                  ASC_TENTHS(s->cont_xfer, 2));
-               ASC_PRT_NEXT();
-
-               /* Contiguous transfer average size */
-               len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
-                                  (s->cont_xfer / 2) / s->cont_cnt,
-                                  ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
-               ASC_PRT_NEXT();
-       }
-
-       if (s->sg_cnt > 0) {
-
-               len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
-                                  s->sg_cnt, s->sg_elem);
-               ASC_PRT_NEXT();
-
-               len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
-                                  s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
-               ASC_PRT_NEXT();
-
-               /* Scatter gather transfer statistics */
-               len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
-                                  s->sg_elem / s->sg_cnt,
-                                  ASC_TENTHS(s->sg_elem, s->sg_cnt));
-               ASC_PRT_NEXT();
-
-               len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
-                                  (s->sg_xfer / 2) / s->sg_elem,
-                                  ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
-               ASC_PRT_NEXT();
-
-               len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
-                                  (s->sg_xfer / 2) / s->sg_cnt,
-                                  ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
-               ASC_PRT_NEXT();
-       }
-
-       /*
-        * Display request queuing statistics.
-        */
-       len = asc_prt_line(cp, leftlen,
-                          " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
-                          HZ);
-       ASC_PRT_NEXT();
-
-       return totlen;
-}
-
-/*
- * asc_prt_target_stats()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * This is separated from asc_prt_board_stats because a full set
- * of targets will overflow ASC_PRTBUF_SIZE.
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
-static int
-asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
-{
-       int leftlen;
-       int totlen;
-       int len;
-       struct asc_stats *s;
-       ushort chip_scsi_id;
-       asc_board_t *boardp;
-       asc_queue_t *active;
-       asc_queue_t *waiting;
-
-       leftlen = cplen;
-       totlen = len = 0;
-
-       boardp = ASC_BOARDP(shost);
-       s = &boardp->asc_stats;
-
-       active = &ASC_BOARDP(shost)->active;
-       waiting = &ASC_BOARDP(shost)->waiting;
-
-       if (ASC_NARROW_BOARD(boardp)) {
-               chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
-       } else {
-               chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
-       }
-
-       if ((chip_scsi_id == tgt_id) ||
-           ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
-               return 0;
-       }
-
-       do {
-               if (active->q_tot_cnt[tgt_id] > 0
-                   || waiting->q_tot_cnt[tgt_id] > 0) {
-                       len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
-                       ASC_PRT_NEXT();
-
-                       len = asc_prt_line(cp, leftlen,
-                                          "   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
-                                          active->q_cur_cnt[tgt_id],
-                                          active->q_max_cnt[tgt_id],
-                                          active->q_tot_cnt[tgt_id],
-                                          active->q_min_tim[tgt_id],
-                                          active->q_max_tim[tgt_id],
-                                          (active->q_tot_cnt[tgt_id] ==
-                                           0) ? 0 : (active->
-                                                     q_tot_tim[tgt_id] /
-                                                     active->
-                                                     q_tot_cnt[tgt_id]),
-                                          (active->q_tot_cnt[tgt_id] ==
-                                           0) ? 0 : ASC_TENTHS(active->
-                                                               q_tot_tim
-                                                               [tgt_id],
-                                                               active->
-                                                               q_tot_cnt
-                                                               [tgt_id]));
-                       ASC_PRT_NEXT();
-
-                       len = asc_prt_line(cp, leftlen,
-                                          "   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
-                                          waiting->q_cur_cnt[tgt_id],
-                                          waiting->q_max_cnt[tgt_id],
-                                          waiting->q_tot_cnt[tgt_id],
-                                          waiting->q_min_tim[tgt_id],
-                                          waiting->q_max_tim[tgt_id],
-                                          (waiting->q_tot_cnt[tgt_id] ==
-                                           0) ? 0 : (waiting->
-                                                     q_tot_tim[tgt_id] /
-                                                     waiting->
-                                                     q_tot_cnt[tgt_id]),
-                                          (waiting->q_tot_cnt[tgt_id] ==
-                                           0) ? 0 : ASC_TENTHS(waiting->
-                                                               q_tot_tim
-                                                               [tgt_id],
-                                                               waiting->
-                                                               q_tot_cnt
-                                                               [tgt_id]));
-                       ASC_PRT_NEXT();
-               }
-       } while (0);
-
-       return totlen;
-}
-#endif /* CONFIG_PROC_FS */
-#endif /* ADVANSYS_STATS */
-
-#ifdef ADVANSYS_DEBUG
-/*
- * asc_prt_scsi_host()
- */
-static void asc_prt_scsi_host(struct Scsi_Host *s)
-{
-       asc_board_t *boardp;
-
-       boardp = ASC_BOARDP(s);
-
-       printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
-       printk(" host_busy %u, host_no %d, last_reset %d,\n",
-              s->host_busy, s->host_no, (unsigned)s->last_reset);
-
-       printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
-              (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
-
-       printk(" dma_channel %d, this_id %d, can_queue %d,\n",
-              s->dma_channel, s->this_id, s->can_queue);
-
-       printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
-              s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
-
-       if (ASC_NARROW_BOARD(boardp)) {
-               asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
-               asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
-       } else {
-               asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
-               asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
-       }
-}
-
-/*
- * asc_prt_scsi_cmnd()
- */
-static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
-{
-       printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
-
-       printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
-              (ulong)s->device->host, (ulong)s->device, s->device->id,
-              s->device->lun, s->device->channel);
-
-       asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
-
-       printk("sc_data_direction %u, resid %d\n",
-              s->sc_data_direction, s->resid);
-
-       printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
-
-       printk(" serial_number 0x%x, retries %d, allowed %d\n",
-              (unsigned)s->serial_number, s->retries, s->allowed);
-
-       printk(" timeout_per_command %d\n", s->timeout_per_command);
-
-       printk
-           (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
-            (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
-            s->result);
-
-       printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
-}
-
-/*
- * asc_prt_asc_dvc_var()
- */
-static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
-{
-       printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
-
-       printk
-           (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
-            h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
-
-       printk
-           (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
-            h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
-            (unsigned)h->init_sdtr);
-
-       printk
-           (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
-            (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
-            (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
-
-       printk
-           (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
-            (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
-            (unsigned)h->scsi_reset_wait);
-
-       printk
-           (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
-            (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
-            (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
-
-       printk
-           (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
-            (unsigned)h->last_q_shortage, (unsigned)h->init_state,
-            (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
-
-       printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
-}
-
-/*
- * asc_prt_asc_dvc_cfg()
- */
-static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
-{
-       printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
-
-       printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
-              h->can_tagged_qng, h->cmd_qng_enabled);
-       printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
-              h->disc_enable, h->sdtr_enable);
-
-       printk
-           (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
-            h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
-            h->chip_version);
-
-       printk
-           (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
-            to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
-            h->mcode_date);
-
-       printk(" mcode_version %d, overrun_buf 0x%lx\n",
-              h->mcode_version, (ulong)h->overrun_buf);
-}
-
-/*
- * asc_prt_asc_scsi_q()
- */
-static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
-{
-       ASC_SG_HEAD *sgp;
-       int i;
-
-       printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
-
-       printk
-           (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
-            q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
-            q->q2.tag_code);
-
-       printk
-           (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
-            (ulong)le32_to_cpu(q->q1.data_addr),
-            (ulong)le32_to_cpu(q->q1.data_cnt),
-            (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
-
-       printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
-              (ulong)q->cdbptr, q->q2.cdb_len,
-              (ulong)q->sg_head, q->q1.sg_queue_cnt);
-
-       if (q->sg_head) {
-               sgp = q->sg_head;
-               printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
-               printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
-                      sgp->queue_cnt);
-               for (i = 0; i < sgp->entry_cnt; i++) {
-                       printk(" [%u]: addr 0x%lx, bytes %lu\n",
-                              i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
-                              (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
-               }
-
-       }
-}
-
-/*
- * asc_prt_asc_qdone_info()
- */
-static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
-{
-       printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
-       printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
-              (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
-              q->d2.tag_code);
-       printk
-           (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
-            q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
-}
-
-/*
- * asc_prt_adv_dvc_var()
- *
- * Display an ADV_DVC_VAR structure.
- */
-static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
-{
-       printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
-
-       printk("  iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
-              (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
-
-       printk("  isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
-              (ulong)h->isr_callback, (unsigned)h->sdtr_able,
-              (unsigned)h->wdtr_able);
-
-       printk("  start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
-              (unsigned)h->start_motor,
-              (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
-
-       printk("  max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
-              (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
-              (ulong)h->carr_freelist);
-
-       printk("  icq_sp 0x%lx, irq_sp 0x%lx\n",
-              (ulong)h->icq_sp, (ulong)h->irq_sp);
-
-       printk("  no_scam 0x%x, tagqng_able 0x%x\n",
-              (unsigned)h->no_scam, (unsigned)h->tagqng_able);
-
-       printk("  chip_scsi_id 0x%x, cfg 0x%lx\n",
-              (unsigned)h->chip_scsi_id, (ulong)h->cfg);
-}
-
-/*
- * asc_prt_adv_dvc_cfg()
- *
- * Display an ADV_DVC_CFG structure.
- */
-static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
-{
-       printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
-
-       printk("  disc_enable 0x%x, termination 0x%x\n",
-              h->disc_enable, h->termination);
-
-       printk("  chip_version 0x%x, mcode_date 0x%x\n",
-              h->chip_version, h->mcode_date);
-
-       printk("  mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
-              h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
-
-       printk("  control_flag 0x%x, pci_slot_info 0x%x\n",
-              h->control_flag, h->pci_slot_info);
-}
-
-/*
- * asc_prt_adv_scsi_req_q()
- *
- * Display an ADV_SCSI_REQ_Q structure.
- */
-static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
-{
-       int sg_blk_cnt;
-       struct asc_sg_block *sg_ptr;
-
-       printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
-
-       printk("  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
-              q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
-
-       printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
-              q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
-
-       printk("  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
-              (ulong)le32_to_cpu(q->data_cnt),
-              (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
-
-       printk
-           ("  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
-            q->cdb_len, q->done_status, q->host_status, q->scsi_status);
-
-       printk("  sg_working_ix 0x%x, target_cmd %u\n",
-              q->sg_working_ix, q->target_cmd);
-
-       printk("  scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
-              (ulong)le32_to_cpu(q->scsiq_rptr),
-              (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
-
-       /* Display the request's ADV_SG_BLOCK structures. */
-       if (q->sg_list_ptr != NULL) {
-               sg_blk_cnt = 0;
-               while (1) {
-                       /*
-                        * 'sg_ptr' is a physical address. Convert it to a virtual
-                        * address by indexing 'sg_blk_cnt' into the virtual address
-                        * array 'sg_list_ptr'.
-                        *
-                        * XXX - Assumes all SG physical blocks are virtually contiguous.
-                        */
-                       sg_ptr =
-                           &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
-                       asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
-                       if (sg_ptr->sg_ptr == 0) {
-                               break;
-                       }
-                       sg_blk_cnt++;
-               }
-       }
-}
-
-/*
- * asc_prt_adv_sgblock()
- *
- * Display an ADV_SG_BLOCK structure.
- */
-static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
-{
-       int i;
-
-       printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
-              (ulong)b, sgblockno);
-       printk("  sg_cnt %u, sg_ptr 0x%lx\n",
-              b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
-       ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
-       if (b->sg_ptr != 0) {
-               ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
-       }
-       for (i = 0; i < b->sg_cnt; i++) {
-               printk("  [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
-                      i, (ulong)b->sg_list[i].sg_addr,
-                      (ulong)b->sg_list[i].sg_count);
-       }
-}
-
-/*
- * asc_prt_hex()
- *
- * Print hexadecimal output in 4 byte groupings 32 bytes
- * or 8 double-words per line.
- */
-static void asc_prt_hex(char *f, uchar *s, int l)
-{
-       int i;
-       int j;
-       int k;
-       int m;
-
-       printk("%s: (%d bytes)\n", f, l);
-
-       for (i = 0; i < l; i += 32) {
-
-               /* Display a maximum of 8 double-words per line. */
-               if ((k = (l - i) / 4) >= 8) {
-                       k = 8;
-                       m = 0;
-               } else {
-                       m = (l - i) % 4;
-               }
-
-               for (j = 0; j < k; j++) {
-                       printk(" %2.2X%2.2X%2.2X%2.2X",
-                              (unsigned)s[i + (j * 4)],
-                              (unsigned)s[i + (j * 4) + 1],
-                              (unsigned)s[i + (j * 4) + 2],
-                              (unsigned)s[i + (j * 4) + 3]);
-               }
-
-               switch (m) {
-               case 0:
-               default:
-                       break;
-               case 1:
-                       printk(" %2.2X", (unsigned)s[i + (j * 4)]);
-                       break;
-               case 2:
-                       printk(" %2.2X%2.2X",
-                              (unsigned)s[i + (j * 4)],
-                              (unsigned)s[i + (j * 4) + 1]);
-                       break;
-               case 3:
-                       printk(" %2.2X%2.2X%2.2X",
-                              (unsigned)s[i + (j * 4) + 1],
-                              (unsigned)s[i + (j * 4) + 2],
-                              (unsigned)s[i + (j * 4) + 3]);
-                       break;
-               }
-
-               printk("\n");
-       }
-}
-#endif /* ADVANSYS_DEBUG */
-
-/*
- * --- Asc Library Functions
- */
-
-static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
-{
-       PortAddr eisa_cfg_iop;
-
-       eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
-           (PortAddr) (ASC_EISA_CFG_IOP_MASK);
-       return (inpw(eisa_cfg_iop));
-}
-
-static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
-{
-       ushort cfg_lsw;
-
-       if (AscGetChipScsiID(iop_base) == new_host_id) {
-               return (new_host_id);
-       }
-       cfg_lsw = AscGetChipCfgLsw(iop_base);
-       cfg_lsw &= 0xF8FF;
-       cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
-       AscSetChipCfgLsw(iop_base, cfg_lsw);
-       return (AscGetChipScsiID(iop_base));
-}
-
-static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
-{
-       uchar sc;
-
-       AscSetBank(iop_base, 1);
-       sc = inp(iop_base + IOP_REG_SC);
-       AscSetBank(iop_base, 0);
-       return (sc);
-}
-
-static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
-{
-       if ((bus_type & ASC_IS_EISA) != 0) {
-               PortAddr eisa_iop;
-               uchar revision;
-               eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
-                   (PortAddr) ASC_EISA_REV_IOP_MASK;
-               revision = inp(eisa_iop);
-               return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
-       }
-       return (AscGetChipVerNo(iop_base));
-}
-
-static ushort __init AscGetChipBusType(PortAddr iop_base)
-{
-       ushort chip_ver;
-
-       chip_ver = AscGetChipVerNo(iop_base);
-       if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
-           && (chip_ver <= ASC_CHIP_MAX_VER_VL)
-           ) {
-               if (((iop_base & 0x0C30) == 0x0C30)
-                   || ((iop_base & 0x0C50) == 0x0C50)
-                   ) {
-                       return (ASC_IS_EISA);
-               }
-               return (ASC_IS_VL);
-       }
-       if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
-           (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
-               if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
-                       return (ASC_IS_ISAPNP);
-               }
-               return (ASC_IS_ISA);
-       } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
-                  (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
-               return (ASC_IS_PCI);
-       }
-       return (0);
-}
-
-static ASC_DCNT
-AscLoadMicroCode(PortAddr iop_base,
-                ushort s_addr, uchar *mcode_buf, ushort mcode_size)
-{
-       ASC_DCNT chksum;
-       ushort mcode_word_size;
-       ushort mcode_chksum;
-
-       /* Write the microcode buffer starting at LRAM address 0. */
-       mcode_word_size = (ushort)(mcode_size >> 1);
-       AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
-       AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
-
-       chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
-       ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
-       mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
-                                                (ushort)ASC_CODE_SEC_BEG,
-                                                (ushort)((mcode_size -
-                                                          s_addr - (ushort)
-                                                          ASC_CODE_SEC_BEG) /
-                                                         2));
-       ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
-                (ulong)mcode_chksum);
-       AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
-       AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
-       return (chksum);
-}
-
-static int AscFindSignature(PortAddr iop_base)
-{
-       ushort sig_word;
-
-       ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
-                iop_base, AscGetChipSignatureByte(iop_base));
-       if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
-               ASC_DBG2(1,
-                        "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
-                        iop_base, AscGetChipSignatureWord(iop_base));
-               sig_word = AscGetChipSignatureWord(iop_base);
-               if ((sig_word == (ushort)ASC_1000_ID0W) ||
-                   (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
-                       return (1);
-               }
-       }
-       return (0);
-}
-
-static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
-       0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
-       ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
-};
-
-#ifdef CONFIG_ISA
-static uchar _isa_pnp_inited __initdata = 0;
-
-static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
-{
-       if (bus_type & ASC_IS_VL) {
-               while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
-                       if (AscGetChipVersion(iop_beg, bus_type) <=
-                           ASC_CHIP_MAX_VER_VL) {
-                               return (iop_beg);
-                       }
-               }
-               return (0);
-       }
-       if (bus_type & ASC_IS_ISA) {
-               if (_isa_pnp_inited == 0) {
-                       AscSetISAPNPWaitForKey();
-                       _isa_pnp_inited++;
-               }
-               while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
-                       if ((AscGetChipVersion(iop_beg, bus_type) &
-                            ASC_CHIP_VER_ISA_BIT) != 0) {
-                               return (iop_beg);
-                       }
-               }
-               return (0);
-       }
-       if (bus_type & ASC_IS_EISA) {
-               if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
-                       return (iop_beg);
-               }
-               return (0);
-       }
-       return (0);
-}
-
-static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
-{
-       int i;
-       PortAddr iop_base;
-
-       for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
-               if (_asc_def_iop_base[i] > s_addr) {
-                       break;
-               }
-       }
-       for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
-               iop_base = _asc_def_iop_base[i];
-               if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
-                       ASC_DBG1(1,
-                                "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
-                                iop_base);
-                       continue;
-               }
-               ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
-                        iop_base);
-               release_region(iop_base, ASC_IOADR_GAP);
-               if (AscFindSignature(iop_base)) {
-                       return (iop_base);
-               }
-       }
-       return (0);
-}
-
-static void __init AscSetISAPNPWaitForKey(void)
-{
-       outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
-       outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
-       return;
-}
-#endif /* CONFIG_ISA */
-
-static void __init AscToggleIRQAct(PortAddr iop_base)
-{
-       AscSetChipStatus(iop_base, CIW_IRQ_ACT);
-       AscSetChipStatus(iop_base, 0);
-       return;
-}
-
-static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
-{
-       ushort cfg_lsw;
-       uchar chip_irq;
-
-       if ((bus_type & ASC_IS_EISA) != 0) {
-               cfg_lsw = AscGetEisaChipCfg(iop_base);
-               chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
-               if ((chip_irq == 13) || (chip_irq > 15)) {
-                       return (0);
-               }
-               return (chip_irq);
-       }
-       if ((bus_type & ASC_IS_VL) != 0) {
-               cfg_lsw = AscGetChipCfgLsw(iop_base);
-               chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
-               if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
-                       return (0);
-               }
-               return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
-       }
-       cfg_lsw = AscGetChipCfgLsw(iop_base);
-       chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
-       if (chip_irq == 3)
-               chip_irq += (uchar)2;
-       return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
-}
-
-static uchar __init
-AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
-{
-       ushort cfg_lsw;
-
-       if ((bus_type & ASC_IS_VL) != 0) {
-               if (irq_no != 0) {
-                       if ((irq_no < ASC_MIN_IRQ_NO)
-                           || (irq_no > ASC_MAX_IRQ_NO)) {
-                               irq_no = 0;
-                       } else {
-                               irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
-                       }
-               }
-               cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
-               cfg_lsw |= (ushort)0x0010;
-               AscSetChipCfgLsw(iop_base, cfg_lsw);
-               AscToggleIRQAct(iop_base);
-               cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
-               cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
-               AscSetChipCfgLsw(iop_base, cfg_lsw);
-               AscToggleIRQAct(iop_base);
-               return (AscGetChipIRQ(iop_base, bus_type));
-       }
-       if ((bus_type & (ASC_IS_ISA)) != 0) {
-               if (irq_no == 15)
-                       irq_no -= (uchar)2;
-               irq_no -= (uchar)ASC_MIN_IRQ_NO;
-               cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
-               cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
-               AscSetChipCfgLsw(iop_base, cfg_lsw);
-               return (AscGetChipIRQ(iop_base, bus_type));
-       }
-       return (0);
-}
-
-#ifdef CONFIG_ISA
-static void __init AscEnableIsaDma(uchar dma_channel)
-{
-       if (dma_channel < 4) {
-               outp(0x000B, (ushort)(0xC0 | dma_channel));
-               outp(0x000A, dma_channel);
-       } else if (dma_channel < 8) {
-               outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
-               outp(0x00D4, (ushort)(dma_channel - 4));
-       }
-       return;
-}
-#endif /* CONFIG_ISA */
-
-static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
-{
-       EXT_MSG ext_msg;
-       EXT_MSG out_msg;
-       ushort halt_q_addr;
-       int sdtr_accept;
-       ushort int_halt_code;
-       ASC_SCSI_BIT_ID_TYPE scsi_busy;
-       ASC_SCSI_BIT_ID_TYPE target_id;
-       PortAddr iop_base;
-       uchar tag_code;
-       uchar q_status;
-       uchar halt_qp;
-       uchar sdtr_data;
-       uchar target_ix;
-       uchar q_cntl, tid_no;
-       uchar cur_dvc_qng;
-       uchar asyn_sdtr;
-       uchar scsi_status;
-       asc_board_t *boardp;
-
-       ASC_ASSERT(asc_dvc->drv_ptr != NULL);
-       boardp = asc_dvc->drv_ptr;
-
-       iop_base = asc_dvc->iop_base;
-       int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
-
-       halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
-       halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
-       target_ix = AscReadLramByte(iop_base,
-                                   (ushort)(halt_q_addr +
-                                            (ushort)ASC_SCSIQ_B_TARGET_IX));
-       q_cntl =
-           AscReadLramByte(iop_base,
-                           (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
-       tid_no = ASC_TIX_TO_TID(target_ix);
-       target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
-       if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-               asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
-       } else {
-               asyn_sdtr = 0;
-       }
-       if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
-               if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-                       AscSetChipSDTR(iop_base, 0, tid_no);
-                       boardp->sdtr_data[tid_no] = 0;
-               }
-               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-               return (0);
-       } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
-               if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-                       AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-                       boardp->sdtr_data[tid_no] = asyn_sdtr;
-               }
-               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-               return (0);
-       } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
-
-               AscMemWordCopyPtrFromLram(iop_base,
-                                         ASCV_MSGIN_BEG,
-                                         (uchar *)&ext_msg,
-                                         sizeof(EXT_MSG) >> 1);
-
-               if (ext_msg.msg_type == MS_EXTEND &&
-                   ext_msg.msg_req == MS_SDTR_CODE &&
-                   ext_msg.msg_len == MS_SDTR_LEN) {
-                       sdtr_accept = TRUE;
-                       if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
-
-                               sdtr_accept = FALSE;
-                               ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
-                       }
-                       if ((ext_msg.xfer_period <
-                            asc_dvc->sdtr_period_tbl[asc_dvc->
-                                                     host_init_sdtr_index])
-                           || (ext_msg.xfer_period >
-                               asc_dvc->sdtr_period_tbl[asc_dvc->
-                                                        max_sdtr_index])) {
-                               sdtr_accept = FALSE;
-                               ext_msg.xfer_period =
-                                   asc_dvc->sdtr_period_tbl[asc_dvc->
-                                                            host_init_sdtr_index];
-                       }
-                       if (sdtr_accept) {
-                               sdtr_data =
-                                   AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
-                                                  ext_msg.req_ack_offset);
-                               if ((sdtr_data == 0xFF)) {
-
-                                       q_cntl |= QC_MSG_OUT;
-                                       asc_dvc->init_sdtr &= ~target_id;
-                                       asc_dvc->sdtr_done &= ~target_id;
-                                       AscSetChipSDTR(iop_base, asyn_sdtr,
-                                                      tid_no);
-                                       boardp->sdtr_data[tid_no] = asyn_sdtr;
-                               }
-                       }
-                       if (ext_msg.req_ack_offset == 0) {
-
-                               q_cntl &= ~QC_MSG_OUT;
-                               asc_dvc->init_sdtr &= ~target_id;
-                               asc_dvc->sdtr_done &= ~target_id;
-                               AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-                       } else {
-                               if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
-
-                                       q_cntl &= ~QC_MSG_OUT;
-                                       asc_dvc->sdtr_done |= target_id;
-                                       asc_dvc->init_sdtr |= target_id;
-                                       asc_dvc->pci_fix_asyn_xfer &=
-                                           ~target_id;
-                                       sdtr_data =
-                                           AscCalSDTRData(asc_dvc,
-                                                          ext_msg.xfer_period,
-                                                          ext_msg.
-                                                          req_ack_offset);
-                                       AscSetChipSDTR(iop_base, sdtr_data,
-                                                      tid_no);
-                                       boardp->sdtr_data[tid_no] = sdtr_data;
-                               } else {
-
-                                       q_cntl |= QC_MSG_OUT;
-                                       AscMsgOutSDTR(asc_dvc,
-                                                     ext_msg.xfer_period,
-                                                     ext_msg.req_ack_offset);
-                                       asc_dvc->pci_fix_asyn_xfer &=
-                                           ~target_id;
-                                       sdtr_data =
-                                           AscCalSDTRData(asc_dvc,
-                                                          ext_msg.xfer_period,
-                                                          ext_msg.
-                                                          req_ack_offset);
-                                       AscSetChipSDTR(iop_base, sdtr_data,
-                                                      tid_no);
-                                       boardp->sdtr_data[tid_no] = sdtr_data;
-                                       asc_dvc->sdtr_done |= target_id;
-                                       asc_dvc->init_sdtr |= target_id;
-                               }
-                       }
-
-                       AscWriteLramByte(iop_base,
-                                        (ushort)(halt_q_addr +
-                                                 (ushort)ASC_SCSIQ_B_CNTL),
-                                        q_cntl);
-                       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-                       return (0);
-               } else if (ext_msg.msg_type == MS_EXTEND &&
-                          ext_msg.msg_req == MS_WDTR_CODE &&
-                          ext_msg.msg_len == MS_WDTR_LEN) {
-
-                       ext_msg.wdtr_width = 0;
-                       AscMemWordCopyPtrToLram(iop_base,
-                                               ASCV_MSGOUT_BEG,
-                                               (uchar *)&ext_msg,
-                                               sizeof(EXT_MSG) >> 1);
-                       q_cntl |= QC_MSG_OUT;
-                       AscWriteLramByte(iop_base,
-                                        (ushort)(halt_q_addr +
-                                                 (ushort)ASC_SCSIQ_B_CNTL),
-                                        q_cntl);
-                       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-                       return (0);
-               } else {
-
-                       ext_msg.msg_type = MESSAGE_REJECT;
-                       AscMemWordCopyPtrToLram(iop_base,
-                                               ASCV_MSGOUT_BEG,
-                                               (uchar *)&ext_msg,
-                                               sizeof(EXT_MSG) >> 1);
-                       q_cntl |= QC_MSG_OUT;
-                       AscWriteLramByte(iop_base,
-                                        (ushort)(halt_q_addr +
-                                                 (ushort)ASC_SCSIQ_B_CNTL),
-                                        q_cntl);
-                       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-                       return (0);
-               }
-       } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
-
-               q_cntl |= QC_REQ_SENSE;
-
-               if ((asc_dvc->init_sdtr & target_id) != 0) {
-
-                       asc_dvc->sdtr_done &= ~target_id;
-
-                       sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-                       q_cntl |= QC_MSG_OUT;
-                       AscMsgOutSDTR(asc_dvc,
-                                     asc_dvc->
-                                     sdtr_period_tbl[(sdtr_data >> 4) &
-                                                     (uchar)(asc_dvc->
-                                                             max_sdtr_index -
-                                                             1)],
-                                     (uchar)(sdtr_data & (uchar)
-                                             ASC_SYN_MAX_OFFSET));
-               }
-
-               AscWriteLramByte(iop_base,
-                                (ushort)(halt_q_addr +
-                                         (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
-
-               tag_code = AscReadLramByte(iop_base,
-                                          (ushort)(halt_q_addr + (ushort)
-                                                   ASC_SCSIQ_B_TAG_CODE));
-               tag_code &= 0xDC;
-               if ((asc_dvc->pci_fix_asyn_xfer & target_id)
-                   && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
-                   ) {
-
-                       tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
-                                    | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
-
-               }
-               AscWriteLramByte(iop_base,
-                                (ushort)(halt_q_addr +
-                                         (ushort)ASC_SCSIQ_B_TAG_CODE),
-                                tag_code);
-
-               q_status = AscReadLramByte(iop_base,
-                                          (ushort)(halt_q_addr + (ushort)
-                                                   ASC_SCSIQ_B_STATUS));
-               q_status |= (QS_READY | QS_BUSY);
-               AscWriteLramByte(iop_base,
-                                (ushort)(halt_q_addr +
-                                         (ushort)ASC_SCSIQ_B_STATUS),
-                                q_status);
-
-               scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
-               scsi_busy &= ~target_id;
-               AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
-
-               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-               return (0);
-       } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
-
-               AscMemWordCopyPtrFromLram(iop_base,
-                                         ASCV_MSGOUT_BEG,
-                                         (uchar *)&out_msg,
-                                         sizeof(EXT_MSG) >> 1);
-
-               if ((out_msg.msg_type == MS_EXTEND) &&
-                   (out_msg.msg_len == MS_SDTR_LEN) &&
-                   (out_msg.msg_req == MS_SDTR_CODE)) {
-
-                       asc_dvc->init_sdtr &= ~target_id;
-                       asc_dvc->sdtr_done &= ~target_id;
-                       AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-                       boardp->sdtr_data[tid_no] = asyn_sdtr;
-               }
-               q_cntl &= ~QC_MSG_OUT;
-               AscWriteLramByte(iop_base,
-                                (ushort)(halt_q_addr +
-                                         (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
-               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-               return (0);
-       } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
-
-               scsi_status = AscReadLramByte(iop_base,
-                                             (ushort)((ushort)halt_q_addr +
-                                                      (ushort)
-                                                      ASC_SCSIQ_SCSI_STATUS));
-               cur_dvc_qng =
-                   AscReadLramByte(iop_base,
-                                   (ushort)((ushort)ASC_QADR_BEG +
-                                            (ushort)target_ix));
-               if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
-
-                       scsi_busy = AscReadLramByte(iop_base,
-                                                   (ushort)ASCV_SCSIBUSY_B);
-                       scsi_busy |= target_id;
-                       AscWriteLramByte(iop_base,
-                                        (ushort)ASCV_SCSIBUSY_B, scsi_busy);
-                       asc_dvc->queue_full_or_busy |= target_id;
-
-                       if (scsi_status == SAM_STAT_TASK_SET_FULL) {
-                               if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
-                                       cur_dvc_qng -= 1;
-                                       asc_dvc->max_dvc_qng[tid_no] =
-                                           cur_dvc_qng;
-
-                                       AscWriteLramByte(iop_base,
-                                                        (ushort)((ushort)
-                                                                 ASCV_MAX_DVC_QNG_BEG
-                                                                 + (ushort)
-                                                                 tid_no),
-                                                        cur_dvc_qng);
-
-                                       /*
-                                        * Set the device queue depth to the number of
-                                        * active requests when the QUEUE FULL condition
-                                        * was encountered.
-                                        */
-                                       boardp->queue_full |= target_id;
-                                       boardp->queue_full_cnt[tid_no] =
-                                           cur_dvc_qng;
-                               }
-                       }
-               }
-               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-               return (0);
-       }
-#if CC_VERY_LONG_SG_LIST
-       else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
-               uchar q_no;
-               ushort q_addr;
-               uchar sg_wk_q_no;
-               uchar first_sg_wk_q_no;
-               ASC_SCSI_Q *scsiq;      /* Ptr to driver request. */
-               ASC_SG_HEAD *sg_head;   /* Ptr to driver SG request. */
-               ASC_SG_LIST_Q scsi_sg_q;        /* Structure written to queue. */
-               ushort sg_list_dwords;
-               ushort sg_entry_cnt;
-               uchar next_qp;
-               int i;
-
-               q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
-               if (q_no == ASC_QLINK_END) {
-                       return (0);
-               }
-
-               q_addr = ASC_QNO_TO_QADDR(q_no);
-
-               /*
-                * Convert the request's SRB pointer to a host ASC_SCSI_REQ
-                * structure pointer using a macro provided by the driver.
-                * The ASC_SCSI_REQ pointer provides a pointer to the
-                * host ASC_SG_HEAD structure.
-                */
-               /* Read request's SRB pointer. */
-               scsiq = (ASC_SCSI_Q *)
-                   ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
-                                                                   (ushort)
-                                                                   (q_addr +
-                                                                    ASC_SCSIQ_D_SRBPTR))));
-
-               /*
-                * Get request's first and working SG queue.
-                */
-               sg_wk_q_no = AscReadLramByte(iop_base,
-                                            (ushort)(q_addr +
-                                                     ASC_SCSIQ_B_SG_WK_QP));
-
-               first_sg_wk_q_no = AscReadLramByte(iop_base,
-                                                  (ushort)(q_addr +
-                                                           ASC_SCSIQ_B_FIRST_SG_WK_QP));
-
-               /*
-                * Reset request's working SG queue back to the
-                * first SG queue.
-                */
-               AscWriteLramByte(iop_base,
-                                (ushort)(q_addr +
-                                         (ushort)ASC_SCSIQ_B_SG_WK_QP),
-                                first_sg_wk_q_no);
-
-               sg_head = scsiq->sg_head;
-
-               /*
-                * Set sg_entry_cnt to the number of SG elements
-                * that will be completed on this interrupt.
-                *
-                * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
-                * SG elements. The data_cnt and data_addr fields which
-                * add 1 to the SG element capacity are not used when
-                * restarting SG handling after a halt.
-                */
-               if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
-                       sg_entry_cnt = ASC_MAX_SG_LIST - 1;
-
-                       /*
-                        * Keep track of remaining number of SG elements that will
-                        * need to be handled on the next interrupt.
-                        */
-                       scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
-               } else {
-                       sg_entry_cnt = scsiq->remain_sg_entry_cnt;
-                       scsiq->remain_sg_entry_cnt = 0;
-               }
-
-               /*
-                * Copy SG elements into the list of allocated SG queues.
-                *
-                * Last index completed is saved in scsiq->next_sg_index.
-                */
-               next_qp = first_sg_wk_q_no;
-               q_addr = ASC_QNO_TO_QADDR(next_qp);
-               scsi_sg_q.sg_head_qp = q_no;
-               scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
-               for (i = 0; i < sg_head->queue_cnt; i++) {
-                       scsi_sg_q.seq_no = i + 1;
-                       if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
-                               sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
-                               sg_entry_cnt -= ASC_SG_LIST_PER_Q;
-                               /*
-                                * After very first SG queue RISC FW uses next
-                                * SG queue first element then checks sg_list_cnt
-                                * against zero and then decrements, so set
-                                * sg_list_cnt 1 less than number of SG elements
-                                * in each SG queue.
-                                */
-                               scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
-                               scsi_sg_q.sg_cur_list_cnt =
-                                   ASC_SG_LIST_PER_Q - 1;
-                       } else {
-                               /*
-                                * This is the last SG queue in the list of
-                                * allocated SG queues. If there are more
-                                * SG elements than will fit in the allocated
-                                * queues, then set the QCSG_SG_XFER_MORE flag.
-                                */
-                               if (scsiq->remain_sg_entry_cnt != 0) {
-                                       scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
-                               } else {
-                                       scsi_sg_q.cntl |= QCSG_SG_XFER_END;
-                               }
-                               /* equals sg_entry_cnt * 2 */
-                               sg_list_dwords = sg_entry_cnt << 1;
-                               scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
-                               scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
-                               sg_entry_cnt = 0;
-                       }
-
-                       scsi_sg_q.q_no = next_qp;
-                       AscMemWordCopyPtrToLram(iop_base,
-                                               q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
-                                               (uchar *)&scsi_sg_q,
-                                               sizeof(ASC_SG_LIST_Q) >> 1);
-
-                       AscMemDWordCopyPtrToLram(iop_base,
-                                                q_addr + ASC_SGQ_LIST_BEG,
-                                                (uchar *)&sg_head->
-                                                sg_list[scsiq->next_sg_index],
-                                                sg_list_dwords);
-
-                       scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
-
-                       /*
-                        * If the just completed SG queue contained the
-                        * last SG element, then no more SG queues need
-                        * to be written.
-                        */
-                       if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
-                               break;
-                       }
-
-                       next_qp = AscReadLramByte(iop_base,
-                                                 (ushort)(q_addr +
-                                                          ASC_SCSIQ_B_FWD));
-                       q_addr = ASC_QNO_TO_QADDR(next_qp);
-               }
-
-               /*
-                * Clear the halt condition so the RISC will be restarted
-                * after the return.
-                */
-               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-               return (0);
-       }
-#endif /* CC_VERY_LONG_SG_LIST */
-       return (0);
-}
-
-static uchar
-_AscCopyLramScsiDoneQ(PortAddr iop_base,
-                     ushort q_addr,
-                     ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
-{
-       ushort _val;
-       uchar sg_queue_cnt;
-
-       DvcGetQinfo(iop_base,
-                   q_addr + ASC_SCSIQ_DONE_INFO_BEG,
-                   (uchar *)scsiq,
-                   (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
-
-       _val = AscReadLramWord(iop_base,
-                              (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
-       scsiq->q_status = (uchar)_val;
-       scsiq->q_no = (uchar)(_val >> 8);
-       _val = AscReadLramWord(iop_base,
-                              (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
-       scsiq->cntl = (uchar)_val;
-       sg_queue_cnt = (uchar)(_val >> 8);
-       _val = AscReadLramWord(iop_base,
-                              (ushort)(q_addr +
-                                       (ushort)ASC_SCSIQ_B_SENSE_LEN));
-       scsiq->sense_len = (uchar)_val;
-       scsiq->extra_bytes = (uchar)(_val >> 8);
-
-       /*
-        * Read high word of remain bytes from alternate location.
-        */
-       scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
-                                                         (ushort)(q_addr +
-                                                                  (ushort)
-                                                                  ASC_SCSIQ_W_ALT_DC1)))
-                              << 16);
-       /*
-        * Read low word of remain bytes from original location.
-        */
-       scsiq->remain_bytes += AscReadLramWord(iop_base,
-                                              (ushort)(q_addr + (ushort)
-                                                       ASC_SCSIQ_DW_REMAIN_XFER_CNT));
-
-       scsiq->remain_bytes &= max_dma_count;
-       return (sg_queue_cnt);
-}
-
-static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
-{
-       uchar next_qp;
-       uchar n_q_used;
-       uchar sg_list_qp;
-       uchar sg_queue_cnt;
-       uchar q_cnt;
-       uchar done_q_tail;
-       uchar tid_no;
-       ASC_SCSI_BIT_ID_TYPE scsi_busy;
-       ASC_SCSI_BIT_ID_TYPE target_id;
-       PortAddr iop_base;
-       ushort q_addr;
-       ushort sg_q_addr;
-       uchar cur_target_qng;
-       ASC_QDONE_INFO scsiq_buf;
-       ASC_QDONE_INFO *scsiq;
-       int false_overrun;
-       ASC_ISR_CALLBACK asc_isr_callback;
-
-       iop_base = asc_dvc->iop_base;
-       asc_isr_callback = asc_dvc->isr_callback;
-       n_q_used = 1;
-       scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
-       done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
-       q_addr = ASC_QNO_TO_QADDR(done_q_tail);
-       next_qp = AscReadLramByte(iop_base,
-                                 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
-       if (next_qp != ASC_QLINK_END) {
-               AscPutVarDoneQTail(iop_base, next_qp);
-               q_addr = ASC_QNO_TO_QADDR(next_qp);
-               sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
-                                                    asc_dvc->max_dma_count);
-               AscWriteLramByte(iop_base,
-                                (ushort)(q_addr +
-                                         (ushort)ASC_SCSIQ_B_STATUS),
-                                (uchar)(scsiq->
-                                        q_status & (uchar)~(QS_READY |
-                                                            QS_ABORTED)));
-               tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
-               target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
-               if ((scsiq->cntl & QC_SG_HEAD) != 0) {
-                       sg_q_addr = q_addr;
-                       sg_list_qp = next_qp;
-                       for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
-                               sg_list_qp = AscReadLramByte(iop_base,
-                                                            (ushort)(sg_q_addr
-                                                                     + (ushort)
-                                                                     ASC_SCSIQ_B_FWD));
-                               sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
-                               if (sg_list_qp == ASC_QLINK_END) {
-                                       AscSetLibErrorCode(asc_dvc,
-                                                          ASCQ_ERR_SG_Q_LINKS);
-                                       scsiq->d3.done_stat = QD_WITH_ERROR;
-                                       scsiq->d3.host_stat =
-                                           QHSTA_D_QDONE_SG_LIST_CORRUPTED;
-                                       goto FATAL_ERR_QDONE;
-                               }
-                               AscWriteLramByte(iop_base,
-                                                (ushort)(sg_q_addr + (ushort)
-                                                         ASC_SCSIQ_B_STATUS),
-                                                QS_FREE);
-                       }
-                       n_q_used = sg_queue_cnt + 1;
-                       AscPutVarDoneQTail(iop_base, sg_list_qp);
-               }
-               if (asc_dvc->queue_full_or_busy & target_id) {
-                       cur_target_qng = AscReadLramByte(iop_base,
-                                                        (ushort)((ushort)
-                                                                 ASC_QADR_BEG
-                                                                 + (ushort)
-                                                                 scsiq->d2.
-                                                                 target_ix));
-                       if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
-                               scsi_busy = AscReadLramByte(iop_base, (ushort)
-                                                           ASCV_SCSIBUSY_B);
-                               scsi_busy &= ~target_id;
-                               AscWriteLramByte(iop_base,
-                                                (ushort)ASCV_SCSIBUSY_B,
-                                                scsi_busy);
-                               asc_dvc->queue_full_or_busy &= ~target_id;
-                       }
-               }
-               if (asc_dvc->cur_total_qng >= n_q_used) {
-                       asc_dvc->cur_total_qng -= n_q_used;
-                       if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
-                               asc_dvc->cur_dvc_qng[tid_no]--;
-                       }
-               } else {
-                       AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
-                       scsiq->d3.done_stat = QD_WITH_ERROR;
-                       goto FATAL_ERR_QDONE;
-               }
-               if ((scsiq->d2.srb_ptr == 0UL) ||
-                   ((scsiq->q_status & QS_ABORTED) != 0)) {
-                       return (0x11);
-               } else if (scsiq->q_status == QS_DONE) {
-                       false_overrun = FALSE;
-                       if (scsiq->extra_bytes != 0) {
-                               scsiq->remain_bytes +=
-                                   (ADV_DCNT)scsiq->extra_bytes;
-                       }
-                       if (scsiq->d3.done_stat == QD_WITH_ERROR) {
-                               if (scsiq->d3.host_stat ==
-                                   QHSTA_M_DATA_OVER_RUN) {
-                                       if ((scsiq->
-                                            cntl & (QC_DATA_IN | QC_DATA_OUT))
-                                           == 0) {
-                                               scsiq->d3.done_stat =
-                                                   QD_NO_ERROR;
-                                               scsiq->d3.host_stat =
-                                                   QHSTA_NO_ERROR;
-                                       } else if (false_overrun) {
-                                               scsiq->d3.done_stat =
-                                                   QD_NO_ERROR;
-                                               scsiq->d3.host_stat =
-                                                   QHSTA_NO_ERROR;
-                                       }
-                               } else if (scsiq->d3.host_stat ==
-                                          QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
-                                       AscStopChip(iop_base);
-                                       AscSetChipControl(iop_base,
-                                                         (uchar)(CC_SCSI_RESET
-                                                                 | CC_HALT));
-                                       DvcDelayNanoSecond(asc_dvc, 60000);
-                                       AscSetChipControl(iop_base, CC_HALT);
-                                       AscSetChipStatus(iop_base,
-                                                        CIW_CLR_SCSI_RESET_INT);
-                                       AscSetChipStatus(iop_base, 0);
-                                       AscSetChipControl(iop_base, 0);
-                               }
-                       }
-                       if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
-                               (*asc_isr_callback) (asc_dvc, scsiq);
-                       } else {
-                               if ((AscReadLramByte(iop_base,
-                                                    (ushort)(q_addr + (ushort)
-                                                             ASC_SCSIQ_CDB_BEG))
-                                    == START_STOP)) {
-                                       asc_dvc->unit_not_ready &= ~target_id;
-                                       if (scsiq->d3.done_stat != QD_NO_ERROR) {
-                                               asc_dvc->start_motor &=
-                                                   ~target_id;
-                                       }
-                               }
-                       }
-                       return (1);
-               } else {
-                       AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
- FATAL_ERR_QDONE:
-                       if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
-                               (*asc_isr_callback) (asc_dvc, scsiq);
-                       }
-                       return (0x80);
-               }
-       }
-       return (0);
-}
-
-static int AscISR(ASC_DVC_VAR *asc_dvc)
-{
-       ASC_CS_TYPE chipstat;
-       PortAddr iop_base;
-       ushort saved_ram_addr;
-       uchar ctrl_reg;
-       uchar saved_ctrl_reg;
-       int int_pending;
-       int status;
-       uchar host_flag;
-
-       iop_base = asc_dvc->iop_base;
-       int_pending = FALSE;
-
-       if (AscIsIntPending(iop_base) == 0) {
-               return int_pending;
-       }
-
-       if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
-           || (asc_dvc->isr_callback == 0)
-           ) {
-               return (ERR);
-       }
-       if (asc_dvc->in_critical_cnt != 0) {
-               AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
-               return (ERR);
-       }
-       if (asc_dvc->is_in_int) {
-               AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
-               return (ERR);
-       }
-       asc_dvc->is_in_int = TRUE;
-       ctrl_reg = AscGetChipControl(iop_base);
-       saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
-                                      CC_SINGLE_STEP | CC_DIAG | CC_TEST));
-       chipstat = AscGetChipStatus(iop_base);
-       if (chipstat & CSW_SCSI_RESET_LATCH) {
-               if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
-                       int i = 10;
-                       int_pending = TRUE;
-                       asc_dvc->sdtr_done = 0;
-                       saved_ctrl_reg &= (uchar)(~CC_HALT);
-                       while ((AscGetChipStatus(iop_base) &
-                               CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
-                               DvcSleepMilliSecond(100);
-                       }
-                       AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
-                       AscSetChipControl(iop_base, CC_HALT);
-                       AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-                       AscSetChipStatus(iop_base, 0);
-                       chipstat = AscGetChipStatus(iop_base);
-               }
-       }
-       saved_ram_addr = AscGetChipLramAddr(iop_base);
-       host_flag = AscReadLramByte(iop_base,
-                                   ASCV_HOST_FLAG_B) &
-           (uchar)(~ASC_HOST_FLAG_IN_ISR);
-       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
-                        (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
-       if ((chipstat & CSW_INT_PENDING)
-           || (int_pending)
-           ) {
-               AscAckInterrupt(iop_base);
-               int_pending = TRUE;
-               if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
-                       if (AscIsrChipHalted(asc_dvc) == ERR) {
-                               goto ISR_REPORT_QDONE_FATAL_ERROR;
-                       } else {
-                               saved_ctrl_reg &= (uchar)(~CC_HALT);
-                       }
-               } else {
- ISR_REPORT_QDONE_FATAL_ERROR:
-                       if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
-                               while (((status =
-                                        AscIsrQDone(asc_dvc)) & 0x01) != 0) {
-                               }
-                       } else {
-                               do {
-                                       if ((status =
-                                            AscIsrQDone(asc_dvc)) == 1) {
-                                               break;
-                                       }
-                               } while (status == 0x11);
-                       }
-                       if ((status & 0x80) != 0)
-                               int_pending = ERR;
-               }
-       }
-       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
-       AscSetChipLramAddr(iop_base, saved_ram_addr);
-       AscSetChipControl(iop_base, saved_ctrl_reg);
-       asc_dvc->is_in_int = FALSE;
-       return (int_pending);
-}
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc38C0800_buf[] = {
+       0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
+       0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19,
+       0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00,
+       0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
+       0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
+       0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0,
+       0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc,
+       0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
+       0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
+       0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc,
+       0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54,
+       0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
+       0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
+       0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80,
+       0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00,
+       0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
+       0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
+       0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0,
+       0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01,
+       0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
+       0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
+       0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
+       0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11,
+       0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
+       0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
+       0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc,
+       0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00,
+       0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
+       0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
+       0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17,
+       0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44,
+       0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
+       0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
+       0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00,
+       0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00,
+       0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
+       0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
+       0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f,
+       0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12,
+       0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
+       0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
+       0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
+       0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10,
+       0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
+       0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+       0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00,
+       0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+       0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
+       0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+       0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe,
+       0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06,
+       0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
+       0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
+       0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe,
+       0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
+       0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
+       0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
+       0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02,
+       0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02,
+       0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
+       0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
+       0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10,
+       0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59,
+       0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
+       0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+       0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0,
+       0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe,
+       0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
+       0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
+       0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43,
+       0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54,
+       0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
+       0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
+       0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe,
+       0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02,
+       0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
+       0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
+       0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe,
+       0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10,
+       0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
+       0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
+       0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78,
+       0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9,
+       0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
+       0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
+       0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a,
+       0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d,
+       0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
+       0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
+       0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda,
+       0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28,
+       0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
+       0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
+       0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+       0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04,
+       0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
+       0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
+       0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62,
+       0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52,
+       0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
+       0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+       0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+       0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00,
+       0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
+       0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
+       0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf,
+       0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08,
+       0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
+       0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
+       0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe,
+       0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff,
+       0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
+       0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
+       0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05,
+       0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab,
+       0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
+       0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
+       0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39,
+       0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2,
+       0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
+       0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
+       0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18,
+       0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe,
+       0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
+       0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
+       0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01,
+       0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02,
+       0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
+       0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
+       0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12,
+       0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2,
+       0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
+       0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
+       0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05,
+       0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
+       0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
+       0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
+       0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01,
+       0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
+       0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
+       0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
+       0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d,
+       0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0,
+       0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
+       0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
+       0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14,
+       0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12,
+       0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
+       0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
+       0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe,
+       0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88,
+       0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
+       0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
+       0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe,
+       0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b,
+       0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
+       0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+       0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d,
+       0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08,
+       0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
+       0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
+       0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06,
+       0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9,
+       0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
+       0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
+       0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a,
+       0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09,
+       0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
+       0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
+       0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58,
+       0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe,
+       0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
+       0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
+       0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe,
+       0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76,
+       0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
+       0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
+       0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10,
+       0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a,
+       0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
+       0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
+       0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f,
+       0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18,
+       0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
+       0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
+       0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a,
+       0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09,
+       0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
+       0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
+       0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a,
+       0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d,
+       0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
+       0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
+       0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe,
+       0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe,
+       0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
+       0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
+       0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8,
+       0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40,
+       0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
+       0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
+       0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05,
+       0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe,
+       0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
+       0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
+       0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32,
+       0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe,
+       0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
+       0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
+       0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
+       0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe,
+       0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
+       0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
+       0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6,
+       0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe,
+       0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
+       0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
+       0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd,
+       0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb,
+       0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
+       0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
+       0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05,
+       0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27,
+       0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
+       0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
+       0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6,
+       0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00,
+       0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
+       0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
+       0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c,
+       0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe,
+       0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
+       0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
+       0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09,
+       0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b,
+       0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
+       0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
+       0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96,
+       0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f,
+       0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
+       0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
+       0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c,
+       0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
+       0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
+       0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
+       0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41,
+       0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70,
+       0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
+       0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
+       0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02,
+       0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45,
+       0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
+       0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
+       0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09,
+       0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe,
+       0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
+       0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
+       0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe,
+       0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41,
+       0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
+       0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
+       0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00,
+       0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
+       0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
+       0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
+       0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01,
+       0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01,
+       0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
+       0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
+       0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24,
+       0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03,
+       0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
+       0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
+       0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05,
+       0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+       0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
+       0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+       0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f,
+       0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01,
+       0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
+       0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+       0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe,
+       0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+       0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
+       0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+       0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe,
+       0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+       0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
+       0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
+       0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe,
+       0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22,
+       0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
+       0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+       0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b,
+       0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f,
+       0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
+       0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
+       0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe,
+       0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe,
+       0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
+       0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
+       0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe,
+       0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7,
+       0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
+       0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
+       0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17,
+       0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24,
+       0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
+       0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
+       0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe,
+       0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c,
+       0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
+       0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
+       0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01,
+       0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe,
+       0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
+       0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
+       0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe,
+       0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a,
+       0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
+       0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
+       0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe,
+       0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50,
+       0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
+       0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
+       0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a,
+       0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d,
+       0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
+       0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
+       0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a,
+       0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf,
+       0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
+       0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
+       0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06,
+       0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee,
+       0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
+       0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
+       0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01,
+       0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33,
+       0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
+       0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
+       0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1,
+       0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15,
+       0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
+       0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
+       0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01,
+       0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
+       0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
+       0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
+       0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
+       0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58,
+       0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
+       0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
+       0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c,
+       0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd,
+       0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
+       0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
+       0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15,
+       0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe,
+       0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
+       0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
+       0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83,
+       0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d,
+       0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
+       0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
+       0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2,
+       0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90,
+       0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
+       0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
+       0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e,
+       0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90,
+       0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
+       0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
+       0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58,
+       0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16,
+       0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
+       0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+       0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+       0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01,
+       0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
+       0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
+       0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27,
+       0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d,
+       0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
+       0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
+       0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8,
+       0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11,
+       0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
+       0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
+       0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01,
+       0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75,
+       0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
+       0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
+       0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04,
+       0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03,
+       0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
+       0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
+       0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
+       0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35,
+       0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
+       0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
+       0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c,
+       0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe,
+       0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
+       0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
+       0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23,
+       0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe,
+       0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
+       0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
+       0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7,
+       0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04,
+       0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
+       0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
+       0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2,
+       0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32,
+       0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
+       0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+       0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11,
+       0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16,
+       0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
+       0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
+       0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18,
+       0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73,
+       0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
+       0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
+       0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46,
+       0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04,
+       0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
+       0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
+       0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
+       0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00,
+       0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
+       0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
+       0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e,
+       0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08,
+       0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
+       0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
+       0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09,
+       0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19,
+       0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
+       0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
+       0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe,
+       0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0,
+       0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
+       0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
+};
+
+static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf);      /* 0x14E1 */
+static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
 
 /* Microcode buffer is kept after initialization for error recovery. */
-static uchar _asc_mcode_buf[] = {
-       0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
-       0x00, 0xFF, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0x00,
-       0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
-       0x00, 0x00, 0x00, 0x00,
-       0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
-       0x03, 0x23, 0x36, 0x40,
-       0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
-       0xC2, 0x00, 0x92, 0x80,
-       0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
-       0xB6, 0x00, 0x92, 0x80,
-       0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
-       0x92, 0x80, 0x80, 0x62,
-       0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
-       0xCD, 0x04, 0x4D, 0x00,
-       0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
-       0xE6, 0x84, 0xD2, 0xC1,
-       0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
-       0xC6, 0x81, 0xC2, 0x88,
-       0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
-       0x84, 0x97, 0x07, 0xA6,
-       0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
-       0xC2, 0x88, 0xCE, 0x00,
-       0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
-       0x80, 0x63, 0x07, 0xA6,
-       0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
-       0x34, 0x01, 0x00, 0x33,
-       0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
-       0x68, 0x98, 0x4D, 0x04,
-       0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
-       0xF8, 0x88, 0xFB, 0x23,
-       0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
-       0x00, 0x33, 0x0A, 0x00,
-       0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
-       0xC2, 0x88, 0xCD, 0x04,
-       0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
-       0x06, 0xAB, 0x82, 0x01,
-       0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
-       0x3C, 0x01, 0x00, 0x05,
-       0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
-       0x15, 0x23, 0xA1, 0x01,
-       0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
-       0x06, 0x61, 0x00, 0xA0,
-       0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
-       0xC2, 0x88, 0x06, 0x23,
-       0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
-       0x57, 0x60, 0x00, 0xA0,
-       0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
-       0x4B, 0x00, 0x06, 0x61,
-       0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
-       0x4F, 0x00, 0x84, 0x97,
-       0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
-       0x48, 0x04, 0x84, 0x80,
-       0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
-       0x81, 0x73, 0x06, 0x29,
-       0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
-       0x04, 0x98, 0xF0, 0x80,
-       0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
-       0x34, 0x02, 0x03, 0xA6,
-       0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
-       0x46, 0x82, 0xFE, 0x95,
-       0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
-       0x07, 0xA6, 0x5A, 0x02,
-       0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
-       0x48, 0x82, 0x60, 0x96,
-       0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
-       0x04, 0x01, 0x0C, 0xDC,
-       0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
-       0x6F, 0x00, 0xA5, 0x01,
-       0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
-       0x02, 0xA6, 0xAA, 0x02,
-       0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
-       0x01, 0xA6, 0xB4, 0x02,
-       0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
-       0x80, 0x63, 0x00, 0x43,
-       0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
-       0x04, 0x61, 0x84, 0x01,
-       0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
-       0x00, 0x00, 0xEA, 0x82,
-       0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
-       0x00, 0x33, 0x1F, 0x00,
-       0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
-       0xB6, 0x2D, 0x01, 0xA6,
-       0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
-       0x10, 0x03, 0x03, 0xA6,
-       0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
-       0x7C, 0x95, 0xEE, 0x82,
-       0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
-       0x04, 0x01, 0x2D, 0xC8,
-       0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
-       0x05, 0x05, 0x86, 0x98,
-       0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
-       0x3C, 0x04, 0x06, 0xA6,
-       0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
-       0x7C, 0x95, 0x32, 0x83,
-       0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
-       0xEB, 0x04, 0x00, 0x33,
-       0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
-       0xFF, 0xA2, 0x7A, 0x03,
-       0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
-       0x00, 0xA2, 0x9A, 0x03,
-       0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
-       0x01, 0xA6, 0x96, 0x03,
-       0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
-       0xA4, 0x03, 0x00, 0xA6,
-       0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
-       0x07, 0xA6, 0xB2, 0x03,
-       0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
-       0xA8, 0x98, 0x80, 0x42,
-       0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
-       0xC0, 0x83, 0x00, 0x33,
-       0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
-       0xA0, 0x01, 0x12, 0x23,
-       0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
-       0x80, 0x67, 0x05, 0x23,
-       0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
-       0x06, 0xA6, 0x0A, 0x04,
-       0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
-       0xF4, 0x83, 0x20, 0x84,
-       0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
-       0x83, 0x03, 0x80, 0x63,
-       0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
-       0x38, 0x04, 0x00, 0x33,
-       0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
-       0x1D, 0x01, 0x06, 0xCC,
-       0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
-       0xA2, 0x0D, 0x80, 0x63,
-       0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
-       0x80, 0x63, 0xA3, 0x01,
-       0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
-       0x76, 0x04, 0xE0, 0x00,
-       0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
-       0x00, 0x33, 0x1E, 0x00,
-       0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
-       0x08, 0x23, 0x22, 0xA3,
-       0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
-       0xC4, 0x04, 0x42, 0x23,
-       0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
-       0xF8, 0x88, 0x04, 0x98,
-       0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
-       0x81, 0x62, 0xE8, 0x81,
-       0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
-       0x00, 0x33, 0x00, 0x81,
-       0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
-       0xF8, 0x88, 0x04, 0x23,
-       0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
-       0xF4, 0x04, 0x00, 0x33,
-       0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
-       0x04, 0x23, 0xA0, 0x01,
-       0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
-       0x00, 0xA3, 0x22, 0x05,
-       0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
-       0x46, 0x97, 0xCD, 0x04,
-       0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
-       0x82, 0x01, 0x34, 0x85,
-       0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
-       0x1D, 0x01, 0x04, 0xD6,
-       0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
-       0x49, 0x00, 0x81, 0x01,
-       0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
-       0x49, 0x04, 0x80, 0x01,
-       0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
-       0x01, 0x23, 0xEA, 0x00,
-       0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
-       0x07, 0xA4, 0xF8, 0x05,
-       0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
-       0xC2, 0x88, 0x04, 0xA0,
-       0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
-       0x00, 0xA2, 0xA4, 0x05,
-       0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
-       0x62, 0x97, 0x04, 0x85,
-       0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
-       0xF4, 0x85, 0x03, 0xA0,
-       0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
-       0xCC, 0x86, 0x07, 0xA0,
-       0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
-       0x80, 0x67, 0x80, 0x63,
-       0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
-       0xF8, 0x88, 0x07, 0x23,
-       0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
-       0x00, 0x63, 0x4A, 0x00,
-       0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
-       0x07, 0x41, 0x83, 0x03,
-       0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
-       0x1D, 0x01, 0x01, 0xD6,
-       0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
-       0x07, 0xA6, 0x7C, 0x05,
-       0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
-       0x52, 0x00, 0x06, 0x61,
-       0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
-       0x00, 0x63, 0x1D, 0x01,
-       0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
-       0x07, 0x41, 0x00, 0x63,
-       0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
-       0xDF, 0x00, 0x06, 0xA6,
-       0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
-       0x00, 0x40, 0xC0, 0x20,
-       0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
-       0x06, 0xA6, 0x94, 0x06,
-       0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
-       0x40, 0x0E, 0x80, 0x63,
-       0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
-       0x80, 0x63, 0x00, 0x43,
-       0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
-       0x80, 0x67, 0x40, 0x0E,
-       0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
-       0x07, 0xA6, 0xD6, 0x06,
-       0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
-       0x0A, 0x2B, 0x07, 0xA6,
-       0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
-       0xF4, 0x06, 0xC0, 0x0E,
-       0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
-       0x81, 0x62, 0x04, 0x01,
-       0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
-       0x8C, 0x06, 0x00, 0x33,
-       0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
-       0x80, 0x63, 0x06, 0xA6,
-       0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
-       0x00, 0x00, 0x80, 0x67,
-       0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
-       0xBF, 0x23, 0x04, 0x61,
-       0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
-       0x00, 0x01, 0xF2, 0x00,
-       0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
-       0x80, 0x05, 0x81, 0x05,
-       0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
-       0x70, 0x00, 0x81, 0x01,
-       0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
-       0x70, 0x00, 0x80, 0x01,
-       0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
-       0xF1, 0x00, 0x70, 0x00,
-       0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
-       0x71, 0x04, 0x70, 0x00,
-       0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
-       0xA3, 0x01, 0xA2, 0x01,
-       0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
-       0xC4, 0x07, 0x00, 0x33,
-       0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
-       0x48, 0x00, 0xB0, 0x01,
-       0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
-       0x00, 0xA2, 0xE4, 0x07,
-       0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
-       0x05, 0x05, 0x00, 0x63,
-       0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
-       0x76, 0x08, 0x80, 0x02,
-       0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
-       0x00, 0x02, 0x00, 0xA0,
-       0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
-       0x00, 0x63, 0xF3, 0x04,
-       0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
-       0x00, 0xA2, 0x44, 0x08,
-       0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
-       0x24, 0x08, 0x04, 0x98,
-       0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
-       0x5A, 0x88, 0x02, 0x01,
-       0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
-       0x00, 0xA3, 0x64, 0x08,
-       0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
-       0x06, 0xA6, 0x76, 0x08,
-       0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
-       0x00, 0x63, 0x38, 0x2B,
-       0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
-       0x05, 0x05, 0xB2, 0x09,
-       0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
-       0x80, 0x32, 0x80, 0x36,
-       0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
-       0x40, 0x36, 0x40, 0x3A,
-       0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
-       0x5D, 0x00, 0xFE, 0xC3,
-       0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
-       0xFF, 0xFD, 0x80, 0x73,
-       0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
-       0xA1, 0x23, 0xA1, 0x01,
-       0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
-       0x80, 0x00, 0x03, 0xC2,
-       0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
-       0xA0, 0x01, 0xE6, 0x84,
+static unsigned char _adv_asc38C1600_buf[] = {
+       0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
+       0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13,
+       0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff,
+       0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
+       0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
+       0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4,
+       0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e,
+       0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
+       0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
+       0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc,
+       0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12,
+       0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
+       0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+       0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4,
+       0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01,
+       0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
+       0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
+       0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
+       0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10,
+       0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
+       0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
+       0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12,
+       0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c,
+       0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
+       0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
+       0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00,
+       0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10,
+       0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
+       0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
+       0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7,
+       0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00,
+       0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
+       0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
+       0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46,
+       0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6,
+       0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
+       0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
+       0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01,
+       0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01,
+       0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
+       0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
+       0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13,
+       0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10,
+       0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
+       0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+       0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00,
+       0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+       0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
+       0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+       0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe,
+       0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c,
+       0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
+       0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
+       0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05,
+       0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1,
+       0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
+       0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
+       0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60,
+       0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52,
+       0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
+       0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
+       0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7,
+       0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f,
+       0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
+       0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
+       0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d,
+       0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe,
+       0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
+       0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
+       0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec,
+       0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde,
+       0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
+       0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
+       0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+       0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03,
+       0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
+       0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
+       0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40,
+       0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0,
+       0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
+       0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
+       0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28,
+       0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01,
+       0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
+       0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
+       0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe,
+       0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0,
+       0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
+       0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
+       0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf,
+       0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a,
+       0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
+       0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
+       0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29,
+       0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00,
+       0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
+       0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
+       0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13,
+       0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e,
+       0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
+       0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
+       0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe,
+       0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43,
+       0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
+       0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
+       0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe,
+       0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f,
+       0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
+       0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
+       0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c,
+       0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0,
+       0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
+       0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
+       0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe,
+       0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f,
+       0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
+       0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
+       0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba,
+       0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2,
+       0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
+       0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
+       0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27,
+       0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f,
+       0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
+       0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
+       0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13,
+       0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06,
+       0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
+       0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
+       0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13,
+       0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe,
+       0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
+       0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
+       0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01,
+       0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15,
+       0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
+       0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
+       0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01,
+       0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95,
+       0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
+       0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
+       0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe,
+       0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21,
+       0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
+       0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
+       0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00,
+       0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe,
+       0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
+       0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
+       0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe,
+       0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76,
+       0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
+       0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
+       0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00,
+       0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe,
+       0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
+       0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
+       0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c,
+       0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08,
+       0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
+       0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
+       0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe,
+       0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21,
+       0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
+       0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
+       0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20,
+       0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
+       0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
+       0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
+       0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b,
+       0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12,
+       0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
+       0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
+       0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90,
+       0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6,
+       0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
+       0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
+       0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2,
+       0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34,
+       0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
+       0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
+       0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a,
+       0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a,
+       0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
+       0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
+       0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d,
+       0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76,
+       0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
+       0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
+       0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe,
+       0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b,
+       0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
+       0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
+       0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5,
+       0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe,
+       0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
+       0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
+       0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05,
+       0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06,
+       0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
+       0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
+       0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42,
+       0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57,
+       0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
+       0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
+       0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01,
+       0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c,
+       0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
+       0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
+       0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06,
+       0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7,
+       0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
+       0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
+       0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe,
+       0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a,
+       0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
+       0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
+       0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e,
+       0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26,
+       0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
+       0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
+       0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef,
+       0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe,
+       0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
+       0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
+       0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18,
+       0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe,
+       0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
+       0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
+       0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe,
+       0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe,
+       0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
+       0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
+       0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12,
+       0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e,
+       0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
+       0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
+       0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0,
+       0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41,
+       0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
+       0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
+       0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01,
+       0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81,
+       0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
+       0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
+       0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe,
+       0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00,
+       0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
+       0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
+       0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f,
+       0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e,
+       0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
+       0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
+       0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01,
+       0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d,
+       0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
+       0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
+       0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
+       0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19,
+       0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
+       0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
+       0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75,
+       0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d,
+       0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
+       0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
+       0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e,
+       0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0,
+       0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
+       0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
+       0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe,
+       0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe,
+       0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
+       0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
+       0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12,
+       0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe,
+       0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
+       0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
+       0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe,
+       0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec,
+       0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
+       0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
+       0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3,
+       0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10,
+       0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
+       0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
+       0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13,
+       0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc,
+       0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
+       0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
+       0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06,
+       0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83,
+       0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
+       0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
+       0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c,
+       0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe,
+       0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
+       0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
+       0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01,
+       0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01,
+       0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
+       0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
+       0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64,
+       0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe,
+       0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
+       0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
+       0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03,
+       0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07,
+       0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
+       0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
+       0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe,
+       0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13,
+       0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
+       0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
+       0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
+       0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
+       0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
+       0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
+       0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
+       0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01,
+       0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+       0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
+       0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85,
+       0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec,
+       0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
+       0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
+       0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee,
+       0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d,
+       0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
+       0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
+       0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42,
+       0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a,
+       0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
+       0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
+       0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34,
+       0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e,
+       0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
+       0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
+       0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+       0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa,
+       0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
+       0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+       0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56,
+       0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9,
+       0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
+       0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
+       0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03,
+       0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e,
+       0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
+       0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
+       0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13,
+       0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9,
+       0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
+       0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
+       0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d,
+       0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a,
+       0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
+       0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
+       0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45,
+       0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01,
+       0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
+       0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
+       0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66,
+       0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56,
+       0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
+       0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
+       0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe,
+       0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05,
+       0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
+       0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
+       0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b,
+       0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d,
+       0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
+       0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
+       0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17,
+       0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe,
+       0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
+       0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+       0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02,
+       0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30,
+       0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+       0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
+       0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58,
+       0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01,
+       0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
+       0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
+       0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a,
+       0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00,
+       0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
+       0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
+       0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16,
+       0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17,
+       0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
+       0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
+       0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d,
+       0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04,
+       0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
+       0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
+       0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16,
+       0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64,
+       0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
+       0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
+       0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe,
+       0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe,
+       0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
+       0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
+       0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe,
+       0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7,
+       0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
+       0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
+       0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9,
+       0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe,
+       0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
+       0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
+       0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01,
+       0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2,
+       0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
+       0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
+       0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18,
+       0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe,
+       0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
+       0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
+       0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe,
+       0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10,
+       0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
+       0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
+       0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe,
+       0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4,
+       0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
+       0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
+       0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01,
+       0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e,
+       0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
+       0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
+       0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f,
+       0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
+       0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
+       0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
+       0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f,
+       0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89,
+       0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
+       0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
+       0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c,
+       0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e,
+       0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
+       0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
+       0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09,
+       0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18,
+       0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
+       0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
+       0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe,
+       0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01,
+       0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
+       0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
+       0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c,
+       0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d,
+       0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
+       0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
+       0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01,
+       0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe,
+       0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
+       0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
+       0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9,
+       0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83,
+       0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
+       0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
+       0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b,
+       0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04,
+       0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
+       0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
+       0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6,
+       0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c,
+       0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
+       0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
+       0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83,
+       0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a,
+       0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
+       0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
+       0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13,
+       0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1,
+       0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
+       0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
+       0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48,
+       0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f,
+       0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
+       0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
+       0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d,
+       0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30,
+       0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
+       0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
+       0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31,
+       0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba,
+       0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
+       0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
+       0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89,
+       0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90,
+       0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
+       0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
+       0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe,
+       0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1,
+       0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
+       0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
+       0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa,
+       0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d,
+       0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
+       0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
+       0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e,
+       0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99,
+       0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
+       0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
+       0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80,
+       0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98,
+       0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
+       0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
+       0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b,
+       0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84,
+       0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
+       0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
+       0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06,
+       0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f,
+       0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+       0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+       0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+       0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+       0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+       0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+       0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b,
+       0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e,
+       0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
 };
 
-static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
-static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf);      /* 0x1673 */
+static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
 
-#define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
-static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
-       INQUIRY,
-       REQUEST_SENSE,
-       READ_CAPACITY,
-       READ_TOC,
-       MODE_SELECT,
-       MODE_SENSE,
-       MODE_SELECT_10,
-       MODE_SENSE_10,
-       0xFF,
-       0xFF,
-       0xFF,
-       0xFF,
-       0xFF,
-       0xFF,
-       0xFF,
-       0xFF
-};
+static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
+{
+       PortAddr iop_base;
+       int i;
+       ushort lram_addr;
+
+       iop_base = asc_dvc->iop_base;
+       AscPutRiscVarFreeQHead(iop_base, 1);
+       AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+       AscPutVarFreeQHead(iop_base, 1);
+       AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+       AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+                        (uchar)((int)asc_dvc->max_total_qng + 1));
+       AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+                        (uchar)((int)asc_dvc->max_total_qng + 2));
+       AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
+                        asc_dvc->max_total_qng);
+       AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+       AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+       AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+       AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+       AscPutQDoneInProgress(iop_base, 0);
+       lram_addr = ASC_QADR_BEG;
+       for (i = 0; i < 32; i++, lram_addr += 2) {
+               AscWriteLramWord(iop_base, lram_addr, 0);
+       }
+}
 
-static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
+static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
 {
-       PortAddr iop_base;
-       ulong last_int_level;
-       int sta;
-       int n_q_required;
-       int disable_syn_offset_one_fix;
        int i;
-       ASC_PADDR addr;
-       ASC_EXE_CALLBACK asc_exe_callback;
-       ushort sg_entry_cnt = 0;
-       ushort sg_entry_cnt_minus_one = 0;
-       uchar target_ix;
-       uchar tid_no;
-       uchar sdtr_data;
-       uchar extra_bytes;
-       uchar scsi_cmd;
-       uchar disable_cmd;
-       ASC_SG_HEAD *sg_head;
-       ASC_DCNT data_cnt;
+       ushort warn_code;
+       PortAddr iop_base;
+       ASC_PADDR phy_addr;
+       ASC_DCNT phy_size;
+       struct asc_board *board = asc_dvc_to_board(asc_dvc);
 
        iop_base = asc_dvc->iop_base;
-       sg_head = scsiq->sg_head;
-       asc_exe_callback = asc_dvc->exe_callback;
-       if (asc_dvc->err_code != 0)
-               return (ERR);
-       if (scsiq == (ASC_SCSI_Q *)0L) {
-               AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
-               return (ERR);
-       }
-       scsiq->q1.q_no = 0;
-       if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
-               scsiq->q1.extra_bytes = 0;
-       }
-       sta = 0;
-       target_ix = scsiq->q2.target_ix;
-       tid_no = ASC_TIX_TO_TID(target_ix);
-       n_q_required = 1;
-       if (scsiq->cdbptr[0] == REQUEST_SENSE) {
-               if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
-                       asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
-                       sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-                       AscMsgOutSDTR(asc_dvc,
-                                     asc_dvc->
-                                     sdtr_period_tbl[(sdtr_data >> 4) &
-                                                     (uchar)(asc_dvc->
-                                                             max_sdtr_index -
-                                                             1)],
-                                     (uchar)(sdtr_data & (uchar)
-                                             ASC_SYN_MAX_OFFSET));
-                       scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
-               }
-       }
-       last_int_level = DvcEnterCritical();
-       if (asc_dvc->in_critical_cnt != 0) {
-               DvcLeaveCritical(last_int_level);
-               AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
-               return (ERR);
-       }
-       asc_dvc->in_critical_cnt++;
-       if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
-               if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
-                       asc_dvc->in_critical_cnt--;
-                       DvcLeaveCritical(last_int_level);
-                       return (ERR);
-               }
-#if !CC_VERY_LONG_SG_LIST
-               if (sg_entry_cnt > ASC_MAX_SG_LIST) {
-                       asc_dvc->in_critical_cnt--;
-                       DvcLeaveCritical(last_int_level);
-                       return (ERR);
-               }
-#endif /* !CC_VERY_LONG_SG_LIST */
-               if (sg_entry_cnt == 1) {
-                       scsiq->q1.data_addr =
-                           (ADV_PADDR)sg_head->sg_list[0].addr;
-                       scsiq->q1.data_cnt =
-                           (ADV_DCNT)sg_head->sg_list[0].bytes;
-                       scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
-               }
-               sg_entry_cnt_minus_one = sg_entry_cnt - 1;
-       }
-       scsi_cmd = scsiq->cdbptr[0];
-       disable_syn_offset_one_fix = FALSE;
-       if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
-           !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
-               if (scsiq->q1.cntl & QC_SG_HEAD) {
-                       data_cnt = 0;
-                       for (i = 0; i < sg_entry_cnt; i++) {
-                               data_cnt +=
-                                   (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
-                                                         bytes);
-                       }
-               } else {
-                       data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
-               }
-               if (data_cnt != 0UL) {
-                       if (data_cnt < 512UL) {
-                               disable_syn_offset_one_fix = TRUE;
-                       } else {
-                               for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
-                                    i++) {
-                                       disable_cmd =
-                                           _syn_offset_one_disable_cmd[i];
-                                       if (disable_cmd == 0xFF) {
-                                               break;
-                                       }
-                                       if (scsi_cmd == disable_cmd) {
-                                               disable_syn_offset_one_fix =
-                                                   TRUE;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-       if (disable_syn_offset_one_fix) {
-               scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
-               scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
-                                      ASC_TAG_FLAG_DISABLE_DISCONNECT);
-       } else {
-               scsiq->q2.tag_code &= 0x27;
+       warn_code = 0;
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               AscPutMCodeInitSDTRAtID(iop_base, i,
+                                       asc_dvc->cfg->sdtr_period_offset[i]);
        }
-       if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
-               if (asc_dvc->bug_fix_cntl) {
-                       if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-                               if ((scsi_cmd == READ_6) ||
-                                   (scsi_cmd == READ_10)) {
-                                       addr =
-                                           (ADV_PADDR)le32_to_cpu(sg_head->
-                                                                  sg_list
-                                                                  [sg_entry_cnt_minus_one].
-                                                                  addr) +
-                                           (ADV_DCNT)le32_to_cpu(sg_head->
-                                                                 sg_list
-                                                                 [sg_entry_cnt_minus_one].
-                                                                 bytes);
-                                       extra_bytes =
-                                           (uchar)((ushort)addr & 0x0003);
-                                       if ((extra_bytes != 0)
-                                           &&
-                                           ((scsiq->q2.
-                                             tag_code &
-                                             ASC_TAG_FLAG_EXTRA_BYTES)
-                                            == 0)) {
-                                               scsiq->q2.tag_code |=
-                                                   ASC_TAG_FLAG_EXTRA_BYTES;
-                                               scsiq->q1.extra_bytes =
-                                                   extra_bytes;
-                                               data_cnt =
-                                                   le32_to_cpu(sg_head->
-                                                               sg_list
-                                                               [sg_entry_cnt_minus_one].
-                                                               bytes);
-                                               data_cnt -=
-                                                   (ASC_DCNT) extra_bytes;
-                                               sg_head->
-                                                   sg_list
-                                                   [sg_entry_cnt_minus_one].
-                                                   bytes =
-                                                   cpu_to_le32(data_cnt);
-                                       }
-                               }
-                       }
-               }
-               sg_head->entry_to_copy = sg_head->entry_cnt;
-#if CC_VERY_LONG_SG_LIST
-               /*
-                * Set the sg_entry_cnt to the maximum possible. The rest of
-                * the SG elements will be copied when the RISC completes the
-                * SG elements that fit and halts.
-                */
-               if (sg_entry_cnt > ASC_MAX_SG_LIST) {
-                       sg_entry_cnt = ASC_MAX_SG_LIST;
-               }
-#endif /* CC_VERY_LONG_SG_LIST */
-               n_q_required = AscSgListToQueue(sg_entry_cnt);
-               if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
-                    (uint) n_q_required)
-                   || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
-                       if ((sta =
-                            AscSendScsiQueue(asc_dvc, scsiq,
-                                             n_q_required)) == 1) {
-                               asc_dvc->in_critical_cnt--;
-                               if (asc_exe_callback != 0) {
-                                       (*asc_exe_callback) (asc_dvc, scsiq);
-                               }
-                               DvcLeaveCritical(last_int_level);
-                               return (sta);
-                       }
-               }
-       } else {
-               if (asc_dvc->bug_fix_cntl) {
-                       if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-                               if ((scsi_cmd == READ_6) ||
-                                   (scsi_cmd == READ_10)) {
-                                       addr =
-                                           le32_to_cpu(scsiq->q1.data_addr) +
-                                           le32_to_cpu(scsiq->q1.data_cnt);
-                                       extra_bytes =
-                                           (uchar)((ushort)addr & 0x0003);
-                                       if ((extra_bytes != 0)
-                                           &&
-                                           ((scsiq->q2.
-                                             tag_code &
-                                             ASC_TAG_FLAG_EXTRA_BYTES)
-                                            == 0)) {
-                                               data_cnt =
-                                                   le32_to_cpu(scsiq->q1.
-                                                               data_cnt);
-                                               if (((ushort)data_cnt & 0x01FF)
-                                                   == 0) {
-                                                       scsiq->q2.tag_code |=
-                                                           ASC_TAG_FLAG_EXTRA_BYTES;
-                                                       data_cnt -= (ASC_DCNT)
-                                                           extra_bytes;
-                                                       scsiq->q1.data_cnt =
-                                                           cpu_to_le32
-                                                           (data_cnt);
-                                                       scsiq->q1.extra_bytes =
-                                                           extra_bytes;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               n_q_required = 1;
-               if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
-                   ((scsiq->q1.cntl & QC_URGENT) != 0)) {
-                       if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
-                                                   n_q_required)) == 1) {
-                               asc_dvc->in_critical_cnt--;
-                               if (asc_exe_callback != 0) {
-                                       (*asc_exe_callback) (asc_dvc, scsiq);
-                               }
-                               DvcLeaveCritical(last_int_level);
-                               return (sta);
-                       }
-               }
+
+       AscInitQLinkVar(asc_dvc);
+       AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+                        asc_dvc->cfg->disc_enable);
+       AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+                        ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+
+       /* Ensure overrun buffer is aligned on an 8 byte boundary. */
+       BUG_ON((unsigned long)asc_dvc->overrun_buf & 7);
+       asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf,
+                                       ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+       phy_addr = cpu_to_le32(asc_dvc->overrun_dma);
+       AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
+                                (uchar *)&phy_addr, 1);
+       phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE);
+       AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
+                                (uchar *)&phy_size, 1);
+
+       asc_dvc->cfg->mcode_date =
+           AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
+       asc_dvc->cfg->mcode_version =
+           AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
+
+       AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+       if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+               asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+               return warn_code;
        }
-       asc_dvc->in_critical_cnt--;
-       DvcLeaveCritical(last_int_level);
-       return (sta);
+       if (AscStartChip(iop_base) != 1) {
+               asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+               return warn_code;
+       }
+
+       return warn_code;
 }
 
-static int
-AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
+static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
 {
+       ushort warn_code;
        PortAddr iop_base;
-       uchar free_q_head;
-       uchar next_qp;
-       uchar tid_no;
-       uchar target_ix;
-       int sta;
 
        iop_base = asc_dvc->iop_base;
-       target_ix = scsiq->q2.target_ix;
-       tid_no = ASC_TIX_TO_TID(target_ix);
-       sta = 0;
-       free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
-       if (n_q_required > 1) {
-               if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
-                                                        free_q_head, (uchar)
-                                                        (n_q_required)))
-                   != (uchar)ASC_QLINK_END) {
-                       asc_dvc->last_q_shortage = 0;
-                       scsiq->sg_head->queue_cnt = n_q_required - 1;
-                       scsiq->q1.q_no = free_q_head;
-                       if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
-                                                         free_q_head)) == 1) {
-                               AscPutVarFreeQHead(iop_base, next_qp);
-                               asc_dvc->cur_total_qng += (uchar)(n_q_required);
-                               asc_dvc->cur_dvc_qng[tid_no]++;
-                       }
-                       return (sta);
-               }
-       } else if (n_q_required == 1) {
-               if ((next_qp = AscAllocFreeQueue(iop_base,
-                                                free_q_head)) !=
-                   ASC_QLINK_END) {
-                       scsiq->q1.q_no = free_q_head;
-                       if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
-                                                   free_q_head)) == 1) {
-                               AscPutVarFreeQHead(iop_base, next_qp);
-                               asc_dvc->cur_total_qng++;
-                               asc_dvc->cur_dvc_qng[tid_no]++;
-                       }
-                       return (sta);
-               }
+       warn_code = 0;
+       if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+           !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+               AscResetChipAndScsiBus(asc_dvc);
+               mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
        }
-       return (sta);
+       asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+       if (asc_dvc->err_code != 0)
+               return UW_ERR;
+       if (!AscFindSignature(asc_dvc->iop_base)) {
+               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+               return warn_code;
+       }
+       AscDisableInterrupt(iop_base);
+       warn_code |= AscInitLram(asc_dvc);
+       if (asc_dvc->err_code != 0)
+               return UW_ERR;
+       ASC_DBG(1, "_asc_mcode_chksum 0x%lx\n", (ulong)_asc_mcode_chksum);
+       if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
+                            _asc_mcode_size) != _asc_mcode_chksum) {
+               asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+               return warn_code;
+       }
+       warn_code |= AscInitMicroCodeVar(asc_dvc);
+       asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+       AscEnableInterrupt(iop_base);
+       return warn_code;
 }
 
-static int AscSgListToQueue(int sg_list)
+/*
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ *
+ * The microcode is stored compressed in the following format:
+ *
+ *  254 word (508 byte) table indexed by byte code followed
+ *  by the following byte codes:
+ *
+ *    1-Byte Code:
+ *      00: Emit word 0 in table.
+ *      01: Emit word 1 in table.
+ *      .
+ *      FD: Emit word 253 in table.
+ *
+ *    Multi-Byte Code:
+ *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ *
+ * Returns 0 or an error if the checksum doesn't match
+ */
+static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
+                           int memsize, int chksum)
 {
-       int n_sg_list_qs;
+       int i, j, end, len = 0;
+       ADV_DCNT sum;
 
-       n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
-       if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
-               n_sg_list_qs++;
-       return (n_sg_list_qs + 1);
+       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+       for (i = 253 * 2; i < size; i++) {
+               if (buf[i] == 0xff) {
+                       unsigned short word = (buf[i + 3] << 8) | buf[i + 2];
+                       for (j = 0; j < buf[i + 1]; j++) {
+                               AdvWriteWordAutoIncLram(iop_base, word);
+                               len += 2;
+                       }
+                       i += 3;
+               } else if (buf[i] == 0xfe) {
+                       unsigned short word = (buf[i + 2] << 8) | buf[i + 1];
+                       AdvWriteWordAutoIncLram(iop_base, word);
+                       i += 2;
+                       len += 2;
+               } else {
+                       unsigned char off = buf[i] * 2;
+                       unsigned short word = (buf[off + 1] << 8) | buf[off];
+                       AdvWriteWordAutoIncLram(iop_base, word);
+                       len += 2;
+               }
+       }
+
+       end = len;
+
+       while (len < memsize) {
+               AdvWriteWordAutoIncLram(iop_base, 0);
+               len += 2;
+       }
+
+       /* Verify the microcode checksum. */
+       sum = 0;
+       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+       for (len = 0; len < end; len += 2) {
+               sum += AdvReadWordAutoIncLram(iop_base);
+       }
+
+       if (sum != chksum)
+               return ASC_IERR_MCODE_CHKSUM;
+
+       return 0;
 }
 
-static uint
-AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
+static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc)
 {
-       uint cur_used_qs;
-       uint cur_free_qs;
-       ASC_SCSI_BIT_ID_TYPE target_id;
-       uchar tid_no;
+       ADV_CARR_T *carrp;
+       ADV_SDCNT buf_size;
+       ADV_PADDR carr_paddr;
 
-       target_id = ASC_TIX_TO_TARGET_ID(target_ix);
-       tid_no = ASC_TIX_TO_TID(target_ix);
-       if ((asc_dvc->unit_not_ready & target_id) ||
-           (asc_dvc->queue_full_or_busy & target_id)) {
-               return (0);
-       }
-       if (n_qs == 1) {
-               cur_used_qs = (uint) asc_dvc->cur_total_qng +
-                   (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
+       carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+       asc_dvc->carr_freelist = NULL;
+       if (carrp == asc_dvc->carrier_buf) {
+               buf_size = ADV_CARRIER_BUFSIZE;
        } else {
-               cur_used_qs = (uint) asc_dvc->cur_total_qng +
-                   (uint) ASC_MIN_FREE_Q;
+               buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
        }
-       if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
-               cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
-               if (asc_dvc->cur_dvc_qng[tid_no] >=
-                   asc_dvc->max_dvc_qng[tid_no]) {
-                       return (0);
-               }
-               return (cur_free_qs);
+
+       do {
+               /* Get physical address of the carrier 'carrp'. */
+               carr_paddr = cpu_to_le32(virt_to_bus(carrp));
+
+               buf_size -= sizeof(ADV_CARR_T);
+
+               carrp->carr_pa = carr_paddr;
+               carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+
+               /*
+                * Insert the carrier at the beginning of the freelist.
+                */
+               carrp->next_vpa =
+                       cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+               asc_dvc->carr_freelist = carrp;
+
+               carrp++;
+       } while (buf_size > 0);
+}
+
+/*
+ * Send an idle command to the chip and wait for completion.
+ *
+ * Command completion is polled for once per microsecond.
+ *
+ * The function can be called from anywhere including an interrupt handler.
+ * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
+ * functions to prevent reentrancy.
+ *
+ * Return Values:
+ *   ADV_TRUE - command completed successfully
+ *   ADV_FALSE - command failed
+ *   ADV_ERROR - command timed out
+ */
+static int
+AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
+              ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
+{
+       int result;
+       ADV_DCNT i, j;
+       AdvPortAddr iop_base;
+
+       iop_base = asc_dvc->iop_base;
+
+       /*
+        * Clear the idle command status which is set by the microcode
+        * to a non-zero value to indicate when the command is completed.
+        * The non-zero result is one of the IDLE_CMD_STATUS_* values
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
+
+       /*
+        * Write the idle command value after the idle command parameter
+        * has been written to avoid a race condition. If the order is not
+        * followed, the microcode may process the idle command before the
+        * parameters have been written to LRAM.
+        */
+       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+                               cpu_to_le32(idle_cmd_parameter));
+       AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+
+       /*
+        * Tickle the RISC to tell it to process the idle command.
+        */
+       AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+       if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+               /*
+                * Clear the tickle value. In the ASC-3550 the RISC flag
+                * command 'clr_tickle_b' does not work unless the host
+                * value is cleared.
+                */
+               AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
        }
-       if (n_qs > 1) {
-               if ((n_qs > asc_dvc->last_q_shortage)
-                   && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
-                       asc_dvc->last_q_shortage = n_qs;
+
+       /* Wait for up to 100 millisecond for the idle command to timeout. */
+       for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
+               /* Poll once each microsecond for command completion. */
+               for (j = 0; j < SCSI_US_PER_MSEC; j++) {
+                       AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
+                                       result);
+                       if (result != 0)
+                               return result;
+                       udelay(1);
                }
        }
-       return (0);
+
+       BUG();          /* The idle command should never timeout. */
+       return ADV_ERROR;
 }
 
-static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
+/*
+ * Reset SCSI Bus and purge all outstanding requests.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) -   All requests are purged and SCSI Bus is reset.
+ *      ADV_FALSE(0) -  Microcode command failed.
+ *      ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
+ *                      may be hung which requires driver recovery.
+ */
+static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
 {
-       ushort q_addr;
-       uchar tid_no;
-       uchar sdtr_data;
-       uchar syn_period_ix;
-       uchar syn_offset;
-       PortAddr iop_base;
+       int status;
 
-       iop_base = asc_dvc->iop_base;
-       if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
-           ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
-               tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
-               sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-               syn_period_ix =
-                   (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
-               syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
-               AscMsgOutSDTR(asc_dvc,
-                             asc_dvc->sdtr_period_tbl[syn_period_ix],
-                             syn_offset);
-               scsiq->q1.cntl |= QC_MSG_OUT;
+       /*
+        * Send the SCSI Bus Reset idle start idle command which asserts
+        * the SCSI Bus Reset signal.
+        */
+       status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
+       if (status != ADV_TRUE) {
+               return status;
        }
-       q_addr = ASC_QNO_TO_QADDR(q_no);
-       if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
-               scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+
+       /*
+        * Delay for the specified SCSI Bus Reset hold time.
+        *
+        * The hold time delay is done on the host because the RISC has no
+        * microsecond accurate timer.
+        */
+       udelay(ASC_SCSI_RESET_HOLD_TIME_US);
+
+       /*
+        * Send the SCSI Bus Reset end idle command which de-asserts
+        * the SCSI Bus Reset signal and purges any pending requests.
+        */
+       status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
+       if (status != ADV_TRUE) {
+               return status;
        }
-       scsiq->q1.status = QS_FREE;
-       AscMemWordCopyPtrToLram(iop_base,
-                               q_addr + ASC_SCSIQ_CDB_BEG,
-                               (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
 
-       DvcPutScsiQ(iop_base,
-                   q_addr + ASC_SCSIQ_CPY_BEG,
-                   (uchar *)&scsiq->q1.cntl,
-                   ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
-       AscWriteLramWord(iop_base,
-                        (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
-                        (ushort)(((ushort)scsiq->q1.
-                                  q_no << 8) | (ushort)QS_READY));
-       return (1);
+       mdelay(asc_dvc->scsi_reset_wait * 1000);        /* XXX: msleep? */
+
+       return status;
 }
 
-static int
-AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
+/*
+ * Initialize the ASC-3550.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
+ */
+static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
 {
-       int sta;
+       AdvPortAddr iop_base;
+       ushort warn_code;
+       int begin_addr;
+       int end_addr;
+       ushort code_sum;
+       int word;
        int i;
-       ASC_SG_HEAD *sg_head;
-       ASC_SG_LIST_Q scsi_sg_q;
-       ASC_DCNT saved_data_addr;
-       ASC_DCNT saved_data_cnt;
-       PortAddr iop_base;
-       ushort sg_list_dwords;
-       ushort sg_index;
-       ushort sg_entry_cnt;
-       ushort q_addr;
-       uchar next_qp;
+       ushort scsi_cfg1;
+       uchar tid;
+       ushort bios_mem[ASC_MC_BIOSLEN / 2];    /* BIOS RISC Memory 0x40-0x8F. */
+       ushort wdtr_able = 0, sdtr_able, tagqng_able;
+       uchar max_cmd[ADV_MAX_TID + 1];
+
+       /* If there is already an error, don't continue. */
+       if (asc_dvc->err_code != 0)
+               return ADV_ERROR;
 
-       iop_base = asc_dvc->iop_base;
-       sg_head = scsiq->sg_head;
-       saved_data_addr = scsiq->q1.data_addr;
-       saved_data_cnt = scsiq->q1.data_cnt;
-       scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
-       scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
-#if CC_VERY_LONG_SG_LIST
        /*
-        * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
-        * then not all SG elements will fit in the allocated queues.
-        * The rest of the SG elements will be copied when the RISC
-        * completes the SG elements that fit and halts.
+        * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
         */
-       if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
-               /*
-                * Set sg_entry_cnt to be the number of SG elements that
-                * will fit in the allocated SG queues. It is minus 1, because
-                * the first SG element is handled above. ASC_MAX_SG_LIST is
-                * already inflated by 1 to account for this. For example it
-                * may be 50 which is 1 + 7 queues * 7 SG elements.
-                */
-               sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+       if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
+               asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+               return ADV_ERROR;
+       }
 
-               /*
-                * Keep track of remaining number of SG elements that will
-                * need to be handled from a_isr.c.
-                */
-               scsiq->remain_sg_entry_cnt =
-                   sg_head->entry_cnt - ASC_MAX_SG_LIST;
-       } else {
-#endif /* CC_VERY_LONG_SG_LIST */
-               /*
-                * Set sg_entry_cnt to be the number of SG elements that
-                * will fit in the allocated SG queues. It is minus 1, because
-                * the first SG element is handled above.
-                */
-               sg_entry_cnt = sg_head->entry_cnt - 1;
-#if CC_VERY_LONG_SG_LIST
+       warn_code = 0;
+       iop_base = asc_dvc->iop_base;
+
+       /*
+        * Save the RISC memory BIOS region before writing the microcode.
+        * The BIOS may already be loaded and using its RISC LRAM region
+        * so its region must be saved and restored.
+        *
+        * Note: This code makes the assumption, which is currently true,
+        * that a chip reset does not clear RISC LRAM.
+        */
+       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+               AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+                               bios_mem[i]);
        }
-#endif /* CC_VERY_LONG_SG_LIST */
-       if (sg_entry_cnt != 0) {
-               scsiq->q1.cntl |= QC_SG_HEAD;
-               q_addr = ASC_QNO_TO_QADDR(q_no);
-               sg_index = 1;
-               scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
-               scsi_sg_q.sg_head_qp = q_no;
-               scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
-               for (i = 0; i < sg_head->queue_cnt; i++) {
-                       scsi_sg_q.seq_no = i + 1;
-                       if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
-                               sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
-                               sg_entry_cnt -= ASC_SG_LIST_PER_Q;
-                               if (i == 0) {
-                                       scsi_sg_q.sg_list_cnt =
-                                           ASC_SG_LIST_PER_Q;
-                                       scsi_sg_q.sg_cur_list_cnt =
-                                           ASC_SG_LIST_PER_Q;
-                               } else {
-                                       scsi_sg_q.sg_list_cnt =
-                                           ASC_SG_LIST_PER_Q - 1;
-                                       scsi_sg_q.sg_cur_list_cnt =
-                                           ASC_SG_LIST_PER_Q - 1;
-                               }
-                       } else {
-#if CC_VERY_LONG_SG_LIST
-                               /*
-                                * This is the last SG queue in the list of
-                                * allocated SG queues. If there are more
-                                * SG elements than will fit in the allocated
-                                * queues, then set the QCSG_SG_XFER_MORE flag.
-                                */
-                               if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
-                                       scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
-                               } else {
-#endif /* CC_VERY_LONG_SG_LIST */
-                                       scsi_sg_q.cntl |= QCSG_SG_XFER_END;
-#if CC_VERY_LONG_SG_LIST
-                               }
-#endif /* CC_VERY_LONG_SG_LIST */
-                               sg_list_dwords = sg_entry_cnt << 1;
-                               if (i == 0) {
-                                       scsi_sg_q.sg_list_cnt = sg_entry_cnt;
-                                       scsi_sg_q.sg_cur_list_cnt =
-                                           sg_entry_cnt;
-                               } else {
-                                       scsi_sg_q.sg_list_cnt =
-                                           sg_entry_cnt - 1;
-                                       scsi_sg_q.sg_cur_list_cnt =
-                                           sg_entry_cnt - 1;
-                               }
-                               sg_entry_cnt = 0;
-                       }
-                       next_qp = AscReadLramByte(iop_base,
-                                                 (ushort)(q_addr +
-                                                          ASC_SCSIQ_B_FWD));
-                       scsi_sg_q.q_no = next_qp;
-                       q_addr = ASC_QNO_TO_QADDR(next_qp);
-                       AscMemWordCopyPtrToLram(iop_base,
-                                               q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
-                                               (uchar *)&scsi_sg_q,
-                                               sizeof(ASC_SG_LIST_Q) >> 1);
-                       AscMemDWordCopyPtrToLram(iop_base,
-                                                q_addr + ASC_SGQ_LIST_BEG,
-                                                (uchar *)&sg_head->
-                                                sg_list[sg_index],
-                                                sg_list_dwords);
-                       sg_index += ASC_SG_LIST_PER_Q;
-                       scsiq->next_sg_index = sg_index;
+
+       /*
+        * Save current per TID negotiated values.
+        */
+       if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
+               ushort bios_version, major, minor;
+
+               bios_version =
+                   bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
+               major = (bios_version >> 12) & 0xF;
+               minor = (bios_version >> 8) & 0xF;
+               if (major < 3 || (major == 3 && minor == 1)) {
+                       /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+                       AdvReadWordLram(iop_base, 0x120, wdtr_able);
+               } else {
+                       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
                }
-       } else {
-               scsiq->q1.cntl &= ~QC_SG_HEAD;
        }
-       sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
-       scsiq->q1.data_addr = saved_data_addr;
-       scsiq->q1.data_cnt = saved_data_cnt;
-       return (sta);
-}
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                               max_cmd[tid]);
+       }
 
-static int
-AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
-{
-       int sta = FALSE;
+       asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf,
+                                       _adv_asc3550_size, ADV_3550_MEMSIZE,
+                                       _adv_asc3550_chksum);
+       if (asc_dvc->err_code)
+               return ADV_ERROR;
 
-       if (AscHostReqRiscHalt(iop_base)) {
-               sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
-               AscStartChip(iop_base);
-               return (sta);
+       /*
+        * Restore the RISC memory BIOS region.
+        */
+       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+               AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+                                bios_mem[i]);
+       }
+
+       /*
+        * Calculate and write the microcode code checksum to the microcode
+        * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+        */
+       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+       AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+       code_sum = 0;
+       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+       for (word = begin_addr; word < end_addr; word += 2) {
+               code_sum += AdvReadWordAutoIncLram(iop_base);
+       }
+       AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+       /*
+        * Read and save microcode version and date.
+        */
+       AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+                       asc_dvc->cfg->mcode_date);
+       AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+                       asc_dvc->cfg->mcode_version);
+
+       /*
+        * Set the chip type to indicate the ASC3550.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+
+       /*
+        * If the PCI Configuration Command Register "Parity Error Response
+        * Control" Bit was clear (0), then set the microcode variable
+        * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+        * to ignore DMA parity errors.
+        */
+       if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+               word |= CONTROL_FLAG_IGNORE_PERR;
+               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
        }
-       return (sta);
-}
 
-static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
-{
-       ASC_SCSI_BIT_ID_TYPE org_id;
-       int i;
-       int sta = TRUE;
+       /*
+        * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+        * threshold of 128 bytes. This register is only accessible to the host.
+        */
+       AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+                            START_CTL_EMFU | READ_CMD_MRM);
 
-       AscSetBank(iop_base, 1);
-       org_id = AscReadChipDvcID(iop_base);
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               if (org_id == (0x01 << i))
-                       break;
+       /*
+        * Microcode operating variables for WDTR, SDTR, and command tag
+        * queuing will be set in slave_configure() based on what a
+        * device reports it is capable of in Inquiry byte 7.
+        *
+        * If SCSI Bus Resets have been disabled, then directly set
+        * SDTR and WDTR from the EEPROM configuration. This will allow
+        * the BIOS and warm boot to work without a SCSI bus hang on
+        * the Inquiry caused by host and target mismatched DTR values.
+        * Without the SCSI Bus Reset, before an Inquiry a device can't
+        * be assumed to be in Asynchronous, Narrow mode.
+        */
+       if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+               AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+                                asc_dvc->wdtr_able);
+               AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+                                asc_dvc->sdtr_able);
        }
-       org_id = (ASC_SCSI_BIT_ID_TYPE) i;
-       AscWriteChipDvcID(iop_base, id);
-       if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
-               AscSetBank(iop_base, 0);
-               AscSetChipSyn(iop_base, sdtr_data);
-               if (AscGetChipSyn(iop_base) != sdtr_data) {
-                       sta = FALSE;
+
+       /*
+        * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+        * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+        * bitmask. These values determine the maximum SDTR speed negotiated
+        * with a device.
+        *
+        * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+        * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+        * without determining here whether the device supports SDTR.
+        *
+        * 4-bit speed  SDTR speed name
+        * ===========  ===============
+        * 0000b (0x0)  SDTR disabled
+        * 0001b (0x1)  5 Mhz
+        * 0010b (0x2)  10 Mhz
+        * 0011b (0x3)  20 Mhz (Ultra)
+        * 0100b (0x4)  40 Mhz (LVD/Ultra2)
+        * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
+        * 0110b (0x6)  Undefined
+        * .
+        * 1111b (0xF)  Undefined
+        */
+       word = 0;
+       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+               if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
+                       /* Set Ultra speed for TID 'tid'. */
+                       word |= (0x3 << (4 * (tid % 4)));
+               } else {
+                       /* Set Fast speed for TID 'tid'. */
+                       word |= (0x2 << (4 * (tid % 4)));
+               }
+               if (tid == 3) { /* Check if done with sdtr_speed1. */
+                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+                       word = 0;
+               } else if (tid == 7) {  /* Check if done with sdtr_speed2. */
+                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+                       word = 0;
+               } else if (tid == 11) { /* Check if done with sdtr_speed3. */
+                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+                       word = 0;
+               } else if (tid == 15) { /* Check if done with sdtr_speed4. */
+                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+                       /* End of loop. */
                }
-       } else {
-               sta = FALSE;
        }
-       AscSetBank(iop_base, 1);
-       AscWriteChipDvcID(iop_base, org_id);
-       AscSetBank(iop_base, 0);
-       return (sta);
-}
 
-static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
-{
-       uchar i;
-       ushort s_addr;
-       PortAddr iop_base;
-       ushort warn_code;
+       /*
+        * Set microcode operating variable for the disconnect per TID bitmask.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+                        asc_dvc->cfg->disc_enable);
 
-       iop_base = asc_dvc->iop_base;
-       warn_code = 0;
-       AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
-                         (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
-                                   64) >> 1)
-           );
-       i = ASC_MIN_ACTIVE_QNO;
-       s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
-       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
-                        (uchar)(i + 1));
-       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
-                        (uchar)(asc_dvc->max_total_qng));
-       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
-                        (uchar)i);
-       i++;
-       s_addr += ASC_QBLK_SIZE;
-       for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
-               AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
-                                (uchar)(i + 1));
-               AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
-                                (uchar)(i - 1));
-               AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
-                                (uchar)i);
-       }
-       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
-                        (uchar)ASC_QLINK_END);
-       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
-                        (uchar)(asc_dvc->max_total_qng - 1));
-       AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
-                        (uchar)asc_dvc->max_total_qng);
-       i++;
-       s_addr += ASC_QBLK_SIZE;
-       for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
-            i++, s_addr += ASC_QBLK_SIZE) {
-               AscWriteLramByte(iop_base,
-                                (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
-               AscWriteLramByte(iop_base,
-                                (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
-               AscWriteLramByte(iop_base,
-                                (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
+       /*
+        * Set SCSI_CFG0 Microcode Default Value.
+        *
+        * The microcode will set the SCSI_CFG0 register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+                        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+                        asc_dvc->chip_scsi_id);
+
+       /*
+        * Determine SCSI_CFG1 Microcode Default Value.
+        *
+        * The microcode will set the SCSI_CFG1 register using this value
+        * after it is started below.
+        */
+
+       /* Read current SCSI_CFG1 Register value. */
+       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+       /*
+        * If all three connectors are in use, return an error.
+        */
+       if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+           (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
+               asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+               return ADV_ERROR;
        }
-       return (warn_code);
-}
 
-static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
-{
-       PortAddr iop_base;
-       int i;
-       ushort lram_addr;
+       /*
+        * If the internal narrow cable is reversed all of the SCSI_CTRL
+        * register signals will be set. Check for and return an error if
+        * this condition is found.
+        */
+       if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+               asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+               return ADV_ERROR;
+       }
 
-       iop_base = asc_dvc->iop_base;
-       AscPutRiscVarFreeQHead(iop_base, 1);
-       AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
-       AscPutVarFreeQHead(iop_base, 1);
-       AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
-       AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
-                        (uchar)((int)asc_dvc->max_total_qng + 1));
-       AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
-                        (uchar)((int)asc_dvc->max_total_qng + 2));
-       AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
-                        asc_dvc->max_total_qng);
-       AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
-       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-       AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
-       AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
-       AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
-       AscPutQDoneInProgress(iop_base, 0);
-       lram_addr = ASC_QADR_BEG;
-       for (i = 0; i < 32; i++, lram_addr += 2) {
-               AscWriteLramWord(iop_base, lram_addr, 0);
+       /*
+        * If this is a differential board and a single-ended device
+        * is attached to one of the connectors, return an error.
+        */
+       if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
+               asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+               return ADV_ERROR;
        }
-       return (0);
-}
 
-static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
-{
-       if (asc_dvc->err_code == 0) {
-               asc_dvc->err_code = err_code;
-               AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
-                                err_code);
+       /*
+        * If automatic termination control is enabled, then set the
+        * termination value based on a table listed in a_condor.h.
+        *
+        * If manual termination was specified with an EEPROM setting
+        * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
+        * is ready to be 'ored' into SCSI_CFG1.
+        */
+       if (asc_dvc->cfg->termination == 0) {
+               /*
+                * The software always controls termination by setting TERM_CTL_SEL.
+                * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+                */
+               asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+               switch (scsi_cfg1 & CABLE_DETECT) {
+                       /* TERM_CTL_H: on, TERM_CTL_L: on */
+               case 0x3:
+               case 0x7:
+               case 0xB:
+               case 0xD:
+               case 0xE:
+               case 0xF:
+                       asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+                       break;
+
+                       /* TERM_CTL_H: on, TERM_CTL_L: off */
+               case 0x1:
+               case 0x5:
+               case 0x9:
+               case 0xA:
+               case 0xC:
+                       asc_dvc->cfg->termination |= TERM_CTL_H;
+                       break;
+
+                       /* TERM_CTL_H: off, TERM_CTL_L: off */
+               case 0x2:
+               case 0x6:
+                       break;
+               }
        }
-       return (err_code);
-}
 
-static uchar
-AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
-{
-       EXT_MSG sdtr_buf;
-       uchar sdtr_period_index;
-       PortAddr iop_base;
+       /*
+        * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+        */
+       scsi_cfg1 &= ~TERM_CTL;
 
-       iop_base = asc_dvc->iop_base;
-       sdtr_buf.msg_type = MS_EXTEND;
-       sdtr_buf.msg_len = MS_SDTR_LEN;
-       sdtr_buf.msg_req = MS_SDTR_CODE;
-       sdtr_buf.xfer_period = sdtr_period;
-       sdtr_offset &= ASC_SYN_MAX_OFFSET;
-       sdtr_buf.req_ack_offset = sdtr_offset;
-       if ((sdtr_period_index =
-            AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
-           asc_dvc->max_sdtr_index) {
-               AscMemWordCopyPtrToLram(iop_base,
-                                       ASCV_MSGOUT_BEG,
-                                       (uchar *)&sdtr_buf,
-                                       sizeof(EXT_MSG) >> 1);
-               return ((sdtr_period_index << 4) | sdtr_offset);
-       } else {
+       /*
+        * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+        * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+        * referenced, because the hardware internally inverts
+        * the Termination High and Low bits if TERM_POL is set.
+        */
+       scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
 
-               sdtr_buf.req_ack_offset = 0;
-               AscMemWordCopyPtrToLram(iop_base,
-                                       ASCV_MSGOUT_BEG,
-                                       (uchar *)&sdtr_buf,
-                                       sizeof(EXT_MSG) >> 1);
-               return (0);
-       }
-}
+       /*
+        * Set SCSI_CFG1 Microcode Default Value
+        *
+        * Set filter value and possibly modified termination control
+        * bits in the Microcode SCSI_CFG1 Register Value.
+        *
+        * The microcode will set the SCSI_CFG1 register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+                        FLTR_DISABLE | scsi_cfg1);
 
-static uchar
-AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
-{
-       uchar byte;
-       uchar sdtr_period_ix;
+       /*
+        * Set MEM_CFG Microcode Default Value
+        *
+        * The microcode will set the MEM_CFG register using this value
+        * after it is started below.
+        *
+        * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+        * are defined.
+        *
+        * ASC-3550 has 8KB internal memory.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+                        BIOS_EN | RAM_SZ_8KB);
 
-       sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
-       if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
-           ) {
-               return (0xFF);
-       }
-       byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
-       return (byte);
-}
+       /*
+        * Set SEL_MASK Microcode Default Value
+        *
+        * The microcode will set the SEL_MASK register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
-static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
-{
-       AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
-       AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
-       return;
-}
+       AdvBuildCarrierFreelist(asc_dvc);
 
-static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
-{
-       uchar *period_table;
-       int max_index;
-       int min_index;
-       int i;
+       /*
+        * Set-up the Host->RISC Initiator Command Queue (ICQ).
+        */
 
-       period_table = asc_dvc->sdtr_period_tbl;
-       max_index = (int)asc_dvc->max_sdtr_index;
-       min_index = (int)asc_dvc->host_init_sdtr_index;
-       if ((syn_time <= period_table[max_index])) {
-               for (i = min_index; i < (max_index - 1); i++) {
-                       if (syn_time <= period_table[i]) {
-                               return ((uchar)i);
-                       }
-               }
-               return ((uchar)max_index);
-       } else {
-               return ((uchar)(max_index + 1));
+       if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+               return ADV_ERROR;
        }
-}
+       asc_dvc->carr_freelist = (ADV_CARR_T *)
+           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
-static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
-{
-       ushort q_addr;
-       uchar next_qp;
-       uchar q_status;
+       /*
+        * The first command issued will be placed in the stopper carrier.
+        */
+       asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-       q_addr = ASC_QNO_TO_QADDR(free_q_head);
-       q_status = (uchar)AscReadLramByte(iop_base,
-                                         (ushort)(q_addr +
-                                                  ASC_SCSIQ_B_STATUS));
-       next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
-       if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
-               return (next_qp);
+       /*
+        * Set RISC ICQ physical address start value.
+        */
+       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+       /*
+        * Set-up the RISC->Host Initiator Response Queue (IRQ).
+        */
+       if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+               return ADV_ERROR;
        }
-       return (ASC_QLINK_END);
-}
+       asc_dvc->carr_freelist = (ADV_CARR_T *)
+           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
-static uchar
-AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
-{
-       uchar i;
+       /*
+        * The first command completed by the RISC will be placed in
+        * the stopper.
+        *
+        * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+        * completed the RISC will set the ASC_RQ_STOPPER bit.
+        */
+       asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-       for (i = 0; i < n_free_q; i++) {
-               if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
-                   == ASC_QLINK_END) {
-                       return (ASC_QLINK_END);
-               }
-       }
-       return (free_q_head);
-}
+       /*
+        * Set RISC IRQ physical address start value.
+        */
+       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+       asc_dvc->carr_pending_cnt = 0;
 
-static int AscHostReqRiscHalt(PortAddr iop_base)
-{
-       int count = 0;
-       int sta = 0;
-       uchar saved_stop_code;
+       AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+                            (ADV_INTR_ENABLE_HOST_INTR |
+                             ADV_INTR_ENABLE_GLOBAL_INTR));
 
-       if (AscIsChipHalted(iop_base))
-               return (1);
-       saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
-       AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-                        ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
-       do {
-               if (AscIsChipHalted(iop_base)) {
-                       sta = 1;
-                       break;
-               }
-               DvcSleepMilliSecond(100);
-       } while (count++ < 20);
-       AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
-       return (sta);
-}
+       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+       AdvWriteWordRegister(iop_base, IOPW_PC, word);
 
-static int AscStopQueueExe(PortAddr iop_base)
-{
-       int count = 0;
+       /* finally, finally, gentlemen, start your engine */
+       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
 
-       if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
-               AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-                                ASC_STOP_REQ_RISC_STOP);
-               do {
-                       if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
-                           ASC_STOP_ACK_RISC_STOP) {
-                               return (1);
+       /*
+        * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+        * Resets should be performed. The RISC has to be running
+        * to issue a SCSI Bus Reset.
+        */
+       if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+               /*
+                * If the BIOS Signature is present in memory, restore the
+                * BIOS Handshake Configuration Table and do not perform
+                * a SCSI Bus Reset.
+                */
+               if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+                   0x55AA) {
+                       /*
+                        * Restore per TID negotiated values.
+                        */
+                       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+                                        tagqng_able);
+                       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+                               AdvWriteByteLram(iop_base,
+                                                ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                                                max_cmd[tid]);
                        }
-                       DvcSleepMilliSecond(100);
-               } while (count++ < 20);
+               } else {
+                       if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+                               warn_code = ASC_WARN_BUSRESET_ERROR;
+                       }
+               }
        }
-       return (0);
+
+       return warn_code;
 }
 
-static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
-{
-       udelay(micro_sec);
-}
+/*
+ * Initialize the ASC-38C0800.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
+ */
+static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+{
+       AdvPortAddr iop_base;
+       ushort warn_code;
+       int begin_addr;
+       int end_addr;
+       ushort code_sum;
+       int word;
+       int i;
+       ushort scsi_cfg1;
+       uchar byte;
+       uchar tid;
+       ushort bios_mem[ASC_MC_BIOSLEN / 2];    /* BIOS RISC Memory 0x40-0x8F. */
+       ushort wdtr_able, sdtr_able, tagqng_able;
+       uchar max_cmd[ADV_MAX_TID + 1];
+
+       /* If there is already an error, don't continue. */
+       if (asc_dvc->err_code != 0)
+               return ADV_ERROR;
 
-static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
-{
-       udelay((nano_sec + 999) / 1000);
-}
+       /*
+        * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+        */
+       if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
+               asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+               return ADV_ERROR;
+       }
 
-#ifdef CONFIG_ISA
-static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
-{
-       PortAddr eisa_iop;
-       ushort product_id_high, product_id_low;
-       ASC_DCNT product_id;
-
-       eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
-       product_id_low = inpw(eisa_iop);
-       product_id_high = inpw(eisa_iop + 2);
-       product_id = ((ASC_DCNT) product_id_high << 16) |
-           (ASC_DCNT) product_id_low;
-       return (product_id);
-}
+       warn_code = 0;
+       iop_base = asc_dvc->iop_base;
 
-static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
-{
-       ASC_DCNT eisa_product_id;
+       /*
+        * Save the RISC memory BIOS region before writing the microcode.
+        * The BIOS may already be loaded and using its RISC LRAM region
+        * so its region must be saved and restored.
+        *
+        * Note: This code makes the assumption, which is currently true,
+        * that a chip reset does not clear RISC LRAM.
+        */
+       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+               AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+                               bios_mem[i]);
+       }
 
-       if (iop_base == 0) {
-               iop_base = ASC_EISA_MIN_IOP_ADDR;
-       } else {
-               if (iop_base == ASC_EISA_MAX_IOP_ADDR)
-                       return (0);
-               if ((iop_base & 0x0050) == 0x0050) {
-                       iop_base += ASC_EISA_BIG_IOP_GAP;
-               } else {
-                       iop_base += ASC_EISA_SMALL_IOP_GAP;
-               }
+       /*
+        * Save current per TID negotiated values.
+        */
+       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                               max_cmd[tid]);
        }
-       while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
-               eisa_product_id = AscGetEisaProductID(iop_base);
-               if ((eisa_product_id == ASC_EISA_ID_740) ||
-                   (eisa_product_id == ASC_EISA_ID_750)) {
-                       if (AscFindSignature(iop_base)) {
-                               inpw(iop_base + 4);
-                               return (iop_base);
-                       }
+
+       /*
+        * RAM BIST (RAM Built-In Self Test)
+        *
+        * Address : I/O base + offset 0x38h register (byte).
+        * Function: Bit 7-6(RW) : RAM mode
+        *                          Normal Mode   : 0x00
+        *                          Pre-test Mode : 0x40
+        *                          RAM Test Mode : 0x80
+        *           Bit 5       : unused
+        *           Bit 4(RO)   : Done bit
+        *           Bit 3-0(RO) : Status
+        *                          Host Error    : 0x08
+        *                          Int_RAM Error : 0x04
+        *                          RISC Error    : 0x02
+        *                          SCSI Error    : 0x01
+        *                          No Error      : 0x00
+        *
+        * Note: RAM BIST code should be put right here, before loading the
+        * microcode and after saving the RISC memory BIOS region.
+        */
+
+       /*
+        * LRAM Pre-test
+        *
+        * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+        * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+        * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+        * to NORMAL_MODE, return an error too.
+        */
+       for (i = 0; i < 2; i++) {
+               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+               mdelay(10);     /* Wait for 10ms before reading back. */
+               byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+               if ((byte & RAM_TEST_DONE) == 0
+                   || (byte & 0x0F) != PRE_TEST_VALUE) {
+                       asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+                       return ADV_ERROR;
                }
-               if (iop_base == ASC_EISA_MAX_IOP_ADDR)
-                       return (0);
-               if ((iop_base & 0x0050) == 0x0050) {
-                       iop_base += ASC_EISA_BIG_IOP_GAP;
-               } else {
-                       iop_base += ASC_EISA_SMALL_IOP_GAP;
+
+               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+               mdelay(10);     /* Wait for 10ms before reading back. */
+               if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+                   != NORMAL_VALUE) {
+                       asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+                       return ADV_ERROR;
                }
        }
-       return (0);
-}
-#endif /* CONFIG_ISA */
 
-static int AscStartChip(PortAddr iop_base)
-{
-       AscSetChipControl(iop_base, 0);
-       if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
-               return (0);
+       /*
+        * LRAM Test - It takes about 1.5 ms to run through the test.
+        *
+        * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+        * If Done bit not set or Status not 0, save register byte, set the
+        * err_code, and return an error.
+        */
+       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+       mdelay(10);     /* Wait for 10ms before checking status. */
+
+       byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+       if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+               /* Get here if Done bit not set or Status not 0. */
+               asc_dvc->bist_err_code = byte;  /* for BIOS display message */
+               asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
+               return ADV_ERROR;
        }
-       return (1);
-}
 
-static int AscStopChip(PortAddr iop_base)
-{
-       uchar cc_val;
+       /* We need to reset back to normal mode after LRAM test passes. */
+       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
 
-       cc_val =
-           AscGetChipControl(iop_base) &
-           (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
-       AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
-       AscSetChipIH(iop_base, INS_HALT);
-       AscSetChipIH(iop_base, INS_RFLAG_WTM);
-       if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
-               return (0);
+       asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf,
+                                _adv_asc38C0800_size, ADV_38C0800_MEMSIZE,
+                                _adv_asc38C0800_chksum);
+       if (asc_dvc->err_code)
+               return ADV_ERROR;
+
+       /*
+        * Restore the RISC memory BIOS region.
+        */
+       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+               AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+                                bios_mem[i]);
        }
-       return (1);
-}
 
-static int AscIsChipHalted(PortAddr iop_base)
-{
-       if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
-               if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
-                       return (1);
-               }
+       /*
+        * Calculate and write the microcode code checksum to the microcode
+        * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+        */
+       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+       AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+       code_sum = 0;
+       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+       for (word = begin_addr; word < end_addr; word += 2) {
+               code_sum += AdvReadWordAutoIncLram(iop_base);
        }
-       return (0);
-}
+       AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
 
-static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
-{
-       AscSetBank(iop_base, 1);
-       AscWriteChipIH(iop_base, ins_code);
-       AscSetBank(iop_base, 0);
-       return;
-}
+       /*
+        * Read microcode version and date.
+        */
+       AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+                       asc_dvc->cfg->mcode_date);
+       AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+                       asc_dvc->cfg->mcode_version);
 
-static void AscAckInterrupt(PortAddr iop_base)
-{
-       uchar host_flag;
-       uchar risc_flag;
-       ushort loop;
+       /*
+        * Set the chip type to indicate the ASC38C0800.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
 
-       loop = 0;
-       do {
-               risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
-               if (loop++ > 0x7FFF) {
-                       break;
-               }
-       } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
-       host_flag =
-           AscReadLramByte(iop_base,
-                           ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
-       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
-                        (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
-       AscSetChipStatus(iop_base, CIW_INT_ACK);
-       loop = 0;
-       while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
-               AscSetChipStatus(iop_base, CIW_INT_ACK);
-               if (loop++ > 3) {
-                       break;
-               }
-       }
-       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
-       return;
-}
+       /*
+        * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+        * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+        * cable detection and then we are able to read C_DET[3:0].
+        *
+        * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+        * Microcode Default Value' section below.
+        */
+       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+       AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+                            scsi_cfg1 | DIS_TERM_DRV);
 
-static void AscDisableInterrupt(PortAddr iop_base)
-{
-       ushort cfg;
+       /*
+        * If the PCI Configuration Command Register "Parity Error Response
+        * Control" Bit was clear (0), then set the microcode variable
+        * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+        * to ignore DMA parity errors.
+        */
+       if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+               word |= CONTROL_FLAG_IGNORE_PERR;
+               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+       }
 
-       cfg = AscGetChipCfgLsw(iop_base);
-       AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
-       return;
-}
+       /*
+        * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+        * bits for the default FIFO threshold.
+        *
+        * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+        *
+        * For DMA Errata #4 set the BC_THRESH_ENB bit.
+        */
+       AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+                            BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
+                            READ_CMD_MRM);
 
-static void AscEnableInterrupt(PortAddr iop_base)
-{
-       ushort cfg;
+       /*
+        * Microcode operating variables for WDTR, SDTR, and command tag
+        * queuing will be set in slave_configure() based on what a
+        * device reports it is capable of in Inquiry byte 7.
+        *
+        * If SCSI Bus Resets have been disabled, then directly set
+        * SDTR and WDTR from the EEPROM configuration. This will allow
+        * the BIOS and warm boot to work without a SCSI bus hang on
+        * the Inquiry caused by host and target mismatched DTR values.
+        * Without the SCSI Bus Reset, before an Inquiry a device can't
+        * be assumed to be in Asynchronous, Narrow mode.
+        */
+       if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+               AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+                                asc_dvc->wdtr_able);
+               AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+                                asc_dvc->sdtr_able);
+       }
 
-       cfg = AscGetChipCfgLsw(iop_base);
-       AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
-       return;
-}
+       /*
+        * Set microcode operating variables for DISC and SDTR_SPEED1,
+        * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+        * configuration values.
+        *
+        * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+        * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+        * without determining here whether the device supports SDTR.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+                        asc_dvc->cfg->disc_enable);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
 
-static void AscSetBank(PortAddr iop_base, uchar bank)
-{
-       uchar val;
+       /*
+        * Set SCSI_CFG0 Microcode Default Value.
+        *
+        * The microcode will set the SCSI_CFG0 register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+                        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+                        asc_dvc->chip_scsi_id);
 
-       val = AscGetChipControl(iop_base) &
-           (~
-            (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
-             CC_CHIP_RESET));
-       if (bank == 1) {
-               val |= CC_BANK_ONE;
-       } else if (bank == 2) {
-               val |= CC_DIAG | CC_BANK_ONE;
-       } else {
-               val &= ~CC_BANK_ONE;
-       }
-       AscSetChipControl(iop_base, val);
-       return;
-}
+       /*
+        * Determine SCSI_CFG1 Microcode Default Value.
+        *
+        * The microcode will set the SCSI_CFG1 register using this value
+        * after it is started below.
+        */
 
-static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
-{
-       PortAddr iop_base;
-       int i = 10;
+       /* Read current SCSI_CFG1 Register value. */
+       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
 
-       iop_base = asc_dvc->iop_base;
-       while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
-              && (i-- > 0)) {
-               DvcSleepMilliSecond(100);
+       /*
+        * If the internal narrow cable is reversed all of the SCSI_CTRL
+        * register signals will be set. Check for and return an error if
+        * this condition is found.
+        */
+       if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+               asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+               return ADV_ERROR;
        }
-       AscStopChip(iop_base);
-       AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
-       DvcDelayNanoSecond(asc_dvc, 60000);
-       AscSetChipIH(iop_base, INS_RFLAG_WTM);
-       AscSetChipIH(iop_base, INS_HALT);
-       AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
-       AscSetChipControl(iop_base, CC_HALT);
-       DvcSleepMilliSecond(200);
-       AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-       AscSetChipStatus(iop_base, 0);
-       return (AscIsChipHalted(iop_base));
-}
 
-static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
-{
-       if (bus_type & ASC_IS_ISA)
-               return (ASC_MAX_ISA_DMA_COUNT);
-       else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
-               return (ASC_MAX_VL_DMA_COUNT);
-       return (ASC_MAX_PCI_DMA_COUNT);
-}
-
-#ifdef CONFIG_ISA
-static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
-{
-       ushort channel;
-
-       channel = AscGetChipCfgLsw(iop_base) & 0x0003;
-       if (channel == 0x03)
-               return (0);
-       else if (channel == 0x00)
-               return (7);
-       return (channel + 4);
-}
+       /*
+        * All kind of combinations of devices attached to one of four
+        * connectors are acceptable except HVD device attached. For example,
+        * LVD device can be attached to SE connector while SE device attached
+        * to LVD connector.  If LVD device attached to SE connector, it only
+        * runs up to Ultra speed.
+        *
+        * If an HVD device is attached to one of LVD connectors, return an
+        * error.  However, there is no way to detect HVD device attached to
+        * SE connectors.
+        */
+       if (scsi_cfg1 & HVD) {
+               asc_dvc->err_code = ASC_IERR_HVD_DEVICE;
+               return ADV_ERROR;
+       }
 
-static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
-{
-       ushort cfg_lsw;
-       uchar value;
+       /*
+        * If either SE or LVD automatic termination control is enabled, then
+        * set the termination value based on a table listed in a_condor.h.
+        *
+        * If manual termination was specified with an EEPROM setting then
+        * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready
+        * to be 'ored' into SCSI_CFG1.
+        */
+       if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+               /* SE automatic termination control is enabled. */
+               switch (scsi_cfg1 & C_DET_SE) {
+                       /* TERM_SE_HI: on, TERM_SE_LO: on */
+               case 0x1:
+               case 0x2:
+               case 0x3:
+                       asc_dvc->cfg->termination |= TERM_SE;
+                       break;
 
-       if ((dma_channel >= 5) && (dma_channel <= 7)) {
-               if (dma_channel == 7)
-                       value = 0x00;
-               else
-                       value = dma_channel - 4;
-               cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
-               cfg_lsw |= value;
-               AscSetChipCfgLsw(iop_base, cfg_lsw);
-               return (AscGetIsaDmaChannel(iop_base));
+                       /* TERM_SE_HI: on, TERM_SE_LO: off */
+               case 0x0:
+                       asc_dvc->cfg->termination |= TERM_SE_HI;
+                       break;
+               }
        }
-       return (0);
-}
 
-static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
-{
-       speed_value &= 0x07;
-       AscSetBank(iop_base, 1);
-       AscWriteChipDmaSpeed(iop_base, speed_value);
-       AscSetBank(iop_base, 0);
-       return (AscGetIsaDmaSpeed(iop_base));
-}
+       if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
+               /* LVD automatic termination control is enabled. */
+               switch (scsi_cfg1 & C_DET_LVD) {
+                       /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+               case 0x4:
+               case 0x8:
+               case 0xC:
+                       asc_dvc->cfg->termination |= TERM_LVD;
+                       break;
 
-static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
-{
-       uchar speed_value;
+                       /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+               case 0x0:
+                       break;
+               }
+       }
 
-       AscSetBank(iop_base, 1);
-       speed_value = AscReadChipDmaSpeed(iop_base);
-       speed_value &= 0x07;
-       AscSetBank(iop_base, 0);
-       return (speed_value);
-}
-#endif /* CONFIG_ISA */
+       /*
+        * Clear any set TERM_SE and TERM_LVD bits.
+        */
+       scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
 
-static ushort __init
-AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
-{
-       uchar lsb, msb;
+       /*
+        * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+        */
+       scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
 
-       lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
-       msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
-       return ((ushort)((msb << 8) | lsb));
-}
+       /*
+        * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE
+        * bits and set possibly modified termination control bits in the
+        * Microcode SCSI_CFG1 Register Value.
+        */
+       scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
 
-static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
-{
-       ushort warn_code;
-       PortAddr iop_base;
-       ushort PCIDeviceID;
-       ushort PCIVendorID;
-       uchar PCIRevisionID;
-       uchar prevCmdRegBits;
+       /*
+        * Set SCSI_CFG1 Microcode Default Value
+        *
+        * Set possibly modified termination control and reset DIS_TERM_DRV
+        * bits in the Microcode SCSI_CFG1 Register Value.
+        *
+        * The microcode will set the SCSI_CFG1 register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
 
-       warn_code = 0;
-       iop_base = asc_dvc->iop_base;
-       asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
-       if (asc_dvc->err_code != 0) {
-               return (UW_ERR);
-       }
-       if (asc_dvc->bus_type == ASC_IS_PCI) {
-               PCIVendorID = AscReadPCIConfigWord(asc_dvc,
-                                                  AscPCIConfigVendorIDRegister);
+       /*
+        * Set MEM_CFG Microcode Default Value
+        *
+        * The microcode will set the MEM_CFG register using this value
+        * after it is started below.
+        *
+        * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+        * are defined.
+        *
+        * ASC-38C0800 has 16KB internal memory.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+                        BIOS_EN | RAM_SZ_16KB);
 
-               PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
-                                                  AscPCIConfigDeviceIDRegister);
+       /*
+        * Set SEL_MASK Microcode Default Value
+        *
+        * The microcode will set the SEL_MASK register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
-               PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
-                                                    AscPCIConfigRevisionIDRegister);
+       AdvBuildCarrierFreelist(asc_dvc);
 
-               if (PCIVendorID != PCI_VENDOR_ID_ASP) {
-                       warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-               }
-               prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
-                                                     AscPCIConfigCommandRegister);
-
-               if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
-                   AscPCICmdRegBits_IOMemBusMaster) {
-                       DvcWritePCIConfigByte(asc_dvc,
-                                             AscPCIConfigCommandRegister,
-                                             (prevCmdRegBits |
-                                              AscPCICmdRegBits_IOMemBusMaster));
-
-                       if ((DvcReadPCIConfigByte(asc_dvc,
-                                                 AscPCIConfigCommandRegister)
-                            & AscPCICmdRegBits_IOMemBusMaster)
-                           != AscPCICmdRegBits_IOMemBusMaster) {
-                               warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-                       }
-               }
-               if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
-                   (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
-                       DvcWritePCIConfigByte(asc_dvc,
-                                             AscPCIConfigLatencyTimer, 0x00);
-                       if (DvcReadPCIConfigByte
-                           (asc_dvc, AscPCIConfigLatencyTimer)
-                           != 0x00) {
-                               warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-                       }
-               } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
-                       if (DvcReadPCIConfigByte(asc_dvc,
-                                                AscPCIConfigLatencyTimer) <
-                           0x20) {
-                               DvcWritePCIConfigByte(asc_dvc,
-                                                     AscPCIConfigLatencyTimer,
-                                                     0x20);
-
-                               if (DvcReadPCIConfigByte(asc_dvc,
-                                                        AscPCIConfigLatencyTimer)
-                                   < 0x20) {
-                                       warn_code |=
-                                           ASC_WARN_SET_PCI_CONFIG_SPACE;
-                               }
-                       }
-               }
-       }
+       /*
+        * Set-up the Host->RISC Initiator Command Queue (ICQ).
+        */
 
-       if (AscFindSignature(iop_base)) {
-               warn_code |= AscInitAscDvcVar(asc_dvc);
-               warn_code |= AscInitFromEEP(asc_dvc);
-               asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
-               if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
-                       asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
-               }
-       } else {
-               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+       if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+               return ADV_ERROR;
        }
-       return (warn_code);
-}
+       asc_dvc->carr_freelist = (ADV_CARR_T *)
+           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
-static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
-{
-       ushort warn_code = 0;
+       /*
+        * The first command issued will be placed in the stopper carrier.
+        */
+       asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-       asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
-       if (asc_dvc->err_code != 0)
-               return (UW_ERR);
-       if (AscFindSignature(asc_dvc->iop_base)) {
-               warn_code |= AscInitFromAscDvcVar(asc_dvc);
-               asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
-       } else {
-               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+       /*
+        * Set RISC ICQ physical address start value.
+        * carr_pa is LE, must be native before write
+        */
+       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+       /*
+        * Set-up the RISC->Host Initiator Response Queue (IRQ).
+        */
+       if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+               return ADV_ERROR;
        }
-       return (warn_code);
-}
+       asc_dvc->carr_freelist = (ADV_CARR_T *)
+           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
-static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
-{
-       PortAddr iop_base;
-       ushort cfg_msw;
-       ushort warn_code;
-       ushort pci_device_id = 0;
+       /*
+        * The first command completed by the RISC will be placed in
+        * the stopper.
+        *
+        * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+        * completed the RISC will set the ASC_RQ_STOPPER bit.
+        */
+       asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-       iop_base = asc_dvc->iop_base;
-#ifdef CONFIG_PCI
-       if (asc_dvc->cfg->dev)
-               pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
-#endif
-       warn_code = 0;
-       cfg_msw = AscGetChipCfgMsw(iop_base);
-       if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
-               cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-               warn_code |= ASC_WARN_CFG_MSW_RECOVER;
-               AscSetChipCfgMsw(iop_base, cfg_msw);
-       }
-       if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
-           asc_dvc->cfg->cmd_qng_enabled) {
-               asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
-               warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
-       }
-       if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
-               warn_code |= ASC_WARN_AUTO_CONFIG;
-       }
-       if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
-               if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
-                   != asc_dvc->irq_no) {
-                       asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
-               }
-       }
-       if (asc_dvc->bus_type & ASC_IS_PCI) {
-               cfg_msw &= 0xFFC0;
-               AscSetChipCfgMsw(iop_base, cfg_msw);
-               if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
-               } else {
-                       if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
-                           (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
-                               asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
-                               asc_dvc->bug_fix_cntl |=
-                                   ASC_BUG_FIX_ASYN_USE_SYN;
-                       }
-               }
-       } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
-               if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
-                   == ASC_CHIP_VER_ASYN_BUG) {
-                       asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
-               }
-       }
-       if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
-           asc_dvc->cfg->chip_scsi_id) {
-               asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
-       }
-#ifdef CONFIG_ISA
-       if (asc_dvc->bus_type & ASC_IS_ISA) {
-               AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
-               AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
-       }
-#endif /* CONFIG_ISA */
-       return (warn_code);
-}
+       /*
+        * Set RISC IRQ physical address start value.
+        *
+        * carr_pa is LE, must be native before write *
+        */
+       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+       asc_dvc->carr_pending_cnt = 0;
 
-static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
-{
-       ushort warn_code;
-       PortAddr iop_base;
+       AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+                            (ADV_INTR_ENABLE_HOST_INTR |
+                             ADV_INTR_ENABLE_GLOBAL_INTR));
 
-       iop_base = asc_dvc->iop_base;
-       warn_code = 0;
-       if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
-           !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
-               AscResetChipAndScsiBus(asc_dvc);
-               DvcSleepMilliSecond((ASC_DCNT)
-                                   ((ushort)asc_dvc->scsi_reset_wait * 1000));
-       }
-       asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
-       if (asc_dvc->err_code != 0)
-               return (UW_ERR);
-       if (!AscFindSignature(asc_dvc->iop_base)) {
-               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-               return (warn_code);
-       }
-       AscDisableInterrupt(iop_base);
-       warn_code |= AscInitLram(asc_dvc);
-       if (asc_dvc->err_code != 0)
-               return (UW_ERR);
-       ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
-                (ulong)_asc_mcode_chksum);
-       if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
-                            _asc_mcode_size) != _asc_mcode_chksum) {
-               asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-               return (warn_code);
-       }
-       warn_code |= AscInitMicroCodeVar(asc_dvc);
-       asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
-       AscEnableInterrupt(iop_base);
-       return (warn_code);
-}
+       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+       AdvWriteWordRegister(iop_base, IOPW_PC, word);
 
-static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
-{
-       int i;
-       PortAddr iop_base;
-       ushort warn_code;
-       uchar chip_version;
+       /* finally, finally, gentlemen, start your engine */
+       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
 
-       iop_base = asc_dvc->iop_base;
-       warn_code = 0;
-       asc_dvc->err_code = 0;
-       if ((asc_dvc->bus_type &
-            (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
-               asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
-       }
-       AscSetChipControl(iop_base, CC_HALT);
-       AscSetChipStatus(iop_base, 0);
-       asc_dvc->bug_fix_cntl = 0;
-       asc_dvc->pci_fix_asyn_xfer = 0;
-       asc_dvc->pci_fix_asyn_xfer_always = 0;
-       /* asc_dvc->init_state initalized in AscInitGetConfig(). */
-       asc_dvc->sdtr_done = 0;
-       asc_dvc->cur_total_qng = 0;
-       asc_dvc->is_in_int = 0;
-       asc_dvc->in_critical_cnt = 0;
-       asc_dvc->last_q_shortage = 0;
-       asc_dvc->use_tagged_qng = 0;
-       asc_dvc->no_scam = 0;
-       asc_dvc->unit_not_ready = 0;
-       asc_dvc->queue_full_or_busy = 0;
-       asc_dvc->redo_scam = 0;
-       asc_dvc->res2 = 0;
-       asc_dvc->host_init_sdtr_index = 0;
-       asc_dvc->cfg->can_tagged_qng = 0;
-       asc_dvc->cfg->cmd_qng_enabled = 0;
-       asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
-       asc_dvc->init_sdtr = 0;
-       asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
-       asc_dvc->scsi_reset_wait = 3;
-       asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
-       asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
-       asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
-       asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
-       asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
-       asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
-       asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
-           ASC_LIB_VERSION_MINOR;
-       chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
-       asc_dvc->cfg->chip_version = chip_version;
-       asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
-       asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
-       asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
-       asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
-       asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
-       asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
-       asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
-       asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
-       asc_dvc->max_sdtr_index = 7;
-       if ((asc_dvc->bus_type & ASC_IS_PCI) &&
-           (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
-               asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
-               asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
-               asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
-               asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
-               asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
-               asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
-               asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
-               asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
-               asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
-               asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
-               asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
-               asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
-               asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
-               asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
-               asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
-               asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
-               asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
-               asc_dvc->max_sdtr_index = 15;
-               if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
-                       AscSetExtraControl(iop_base,
-                                          (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
-               } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
-                       AscSetExtraControl(iop_base,
-                                          (SEC_ACTIVE_NEGATE |
-                                           SEC_ENABLE_FILTER));
+       /*
+        * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+        * Resets should be performed. The RISC has to be running
+        * to issue a SCSI Bus Reset.
+        */
+       if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+               /*
+                * If the BIOS Signature is present in memory, restore the
+                * BIOS Handshake Configuration Table and do not perform
+                * a SCSI Bus Reset.
+                */
+               if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+                   0x55AA) {
+                       /*
+                        * Restore per TID negotiated values.
+                        */
+                       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+                                        tagqng_able);
+                       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+                               AdvWriteByteLram(iop_base,
+                                                ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                                                max_cmd[tid]);
+                       }
+               } else {
+                       if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+                               warn_code = ASC_WARN_BUSRESET_ERROR;
+                       }
                }
        }
-       if (asc_dvc->bus_type == ASC_IS_PCI) {
-               AscSetExtraControl(iop_base,
-                                  (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
-       }
 
-       asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
-       if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
-               AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
-               asc_dvc->bus_type = ASC_IS_ISAPNP;
-       }
-#ifdef CONFIG_ISA
-       if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
-               asc_dvc->cfg->isa_dma_channel =
-                   (uchar)AscGetIsaDmaChannel(iop_base);
-       }
-#endif /* CONFIG_ISA */
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               asc_dvc->cur_dvc_qng[i] = 0;
-               asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
-               asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
-               asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
-               asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
-       }
-       return (warn_code);
+       return warn_code;
 }
 
-static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
+/*
+ * Initialize the ASC-38C1600.
+ *
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
+ */
+static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
 {
-       ASCEEP_CONFIG eep_config_buf;
-       ASCEEP_CONFIG *eep_config;
-       PortAddr iop_base;
-       ushort chksum;
+       AdvPortAddr iop_base;
        ushort warn_code;
-       ushort cfg_msw, cfg_lsw;
+       int begin_addr;
+       int end_addr;
+       ushort code_sum;
+       long word;
        int i;
-       int write_eep = 0;
-
-       iop_base = asc_dvc->iop_base;
-       warn_code = 0;
-       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
-       AscStopQueueExe(iop_base);
-       if ((AscStopChip(iop_base) == FALSE) ||
-           (AscGetChipScsiCtrl(iop_base) != 0)) {
-               asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
-               AscResetChipAndScsiBus(asc_dvc);
-               DvcSleepMilliSecond((ASC_DCNT)
-                                   ((ushort)asc_dvc->scsi_reset_wait * 1000));
-       }
-       if (AscIsChipHalted(iop_base) == FALSE) {
-               asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
-               return (warn_code);
+       ushort scsi_cfg1;
+       uchar byte;
+       uchar tid;
+       ushort bios_mem[ASC_MC_BIOSLEN / 2];    /* BIOS RISC Memory 0x40-0x8F. */
+       ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
+       uchar max_cmd[ASC_MAX_TID + 1];
+
+       /* If there is already an error, don't continue. */
+       if (asc_dvc->err_code != 0) {
+               return ADV_ERROR;
        }
-       AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-       if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-               asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
-               return (warn_code);
+
+       /*
+        * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
+        */
+       if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+               asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+               return ADV_ERROR;
        }
-       eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
-       cfg_msw = AscGetChipCfgMsw(iop_base);
-       cfg_lsw = AscGetChipCfgLsw(iop_base);
-       if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
-               cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-               warn_code |= ASC_WARN_CFG_MSW_RECOVER;
-               AscSetChipCfgMsw(iop_base, cfg_msw);
+
+       warn_code = 0;
+       iop_base = asc_dvc->iop_base;
+
+       /*
+        * Save the RISC memory BIOS region before writing the microcode.
+        * The BIOS may already be loaded and using its RISC LRAM region
+        * so its region must be saved and restored.
+        *
+        * Note: This code makes the assumption, which is currently true,
+        * that a chip reset does not clear RISC LRAM.
+        */
+       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+               AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+                               bios_mem[i]);
        }
-       chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
-       ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
-       if (chksum == 0) {
-               chksum = 0xaa55;
+
+       /*
+        * Save current per TID negotiated values.
+        */
+       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+       AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+       for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                               max_cmd[tid]);
        }
-       if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
-               warn_code |= ASC_WARN_AUTO_CONFIG;
-               if (asc_dvc->cfg->chip_version == 3) {
-                       if (eep_config->cfg_lsw != cfg_lsw) {
-                               warn_code |= ASC_WARN_EEPROM_RECOVER;
-                               eep_config->cfg_lsw =
-                                   AscGetChipCfgLsw(iop_base);
-                       }
-                       if (eep_config->cfg_msw != cfg_msw) {
-                               warn_code |= ASC_WARN_EEPROM_RECOVER;
-                               eep_config->cfg_msw =
-                                   AscGetChipCfgMsw(iop_base);
-                       }
+
+       /*
+        * RAM BIST (Built-In Self Test)
+        *
+        * Address : I/O base + offset 0x38h register (byte).
+        * Function: Bit 7-6(RW) : RAM mode
+        *                          Normal Mode   : 0x00
+        *                          Pre-test Mode : 0x40
+        *                          RAM Test Mode : 0x80
+        *           Bit 5       : unused
+        *           Bit 4(RO)   : Done bit
+        *           Bit 3-0(RO) : Status
+        *                          Host Error    : 0x08
+        *                          Int_RAM Error : 0x04
+        *                          RISC Error    : 0x02
+        *                          SCSI Error    : 0x01
+        *                          No Error      : 0x00
+        *
+        * Note: RAM BIST code should be put right here, before loading the
+        * microcode and after saving the RISC memory BIOS region.
+        */
+
+       /*
+        * LRAM Pre-test
+        *
+        * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+        * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+        * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+        * to NORMAL_MODE, return an error too.
+        */
+       for (i = 0; i < 2; i++) {
+               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+               mdelay(10);     /* Wait for 10ms before reading back. */
+               byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+               if ((byte & RAM_TEST_DONE) == 0
+                   || (byte & 0x0F) != PRE_TEST_VALUE) {
+                       asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+                       return ADV_ERROR;
                }
-       }
-       eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
-       eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
-       ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
-                eep_config->chksum);
-       if (chksum != eep_config->chksum) {
-               if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
-                   ASC_CHIP_VER_PCI_ULTRA_3050) {
-                       ASC_DBG(1,
-                               "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
-                       eep_config->init_sdtr = 0xFF;
-                       eep_config->disc_enable = 0xFF;
-                       eep_config->start_motor = 0xFF;
-                       eep_config->use_cmd_qng = 0;
-                       eep_config->max_total_qng = 0xF0;
-                       eep_config->max_tag_qng = 0x20;
-                       eep_config->cntl = 0xBFFF;
-                       ASC_EEP_SET_CHIP_ID(eep_config, 7);
-                       eep_config->no_scam = 0;
-                       eep_config->adapter_info[0] = 0;
-                       eep_config->adapter_info[1] = 0;
-                       eep_config->adapter_info[2] = 0;
-                       eep_config->adapter_info[3] = 0;
-                       eep_config->adapter_info[4] = 0;
-                       /* Indicate EEPROM-less board. */
-                       eep_config->adapter_info[5] = 0xBB;
-               } else {
-                       ASC_PRINT
-                           ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
-                       write_eep = 1;
-                       warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+               mdelay(10);     /* Wait for 10ms before reading back. */
+               if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+                   != NORMAL_VALUE) {
+                       asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+                       return ADV_ERROR;
                }
        }
-       asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
-       asc_dvc->cfg->disc_enable = eep_config->disc_enable;
-       asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
-       asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
-       asc_dvc->start_motor = eep_config->start_motor;
-       asc_dvc->dvc_cntl = eep_config->cntl;
-       asc_dvc->no_scam = eep_config->no_scam;
-       asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
-       asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
-       asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
-       asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
-       asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
-       asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
-       if (!AscTestExternalLram(asc_dvc)) {
-               if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
-                    ASC_IS_PCI_ULTRA)) {
-                       eep_config->max_total_qng =
-                           ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
-                       eep_config->max_tag_qng =
-                           ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
-               } else {
-                       eep_config->cfg_msw |= 0x0800;
-                       cfg_msw |= 0x0800;
-                       AscSetChipCfgMsw(iop_base, cfg_msw);
-                       eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
-                       eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
-               }
-       } else {
+
+       /*
+        * LRAM Test - It takes about 1.5 ms to run through the test.
+        *
+        * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+        * If Done bit not set or Status not 0, save register byte, set the
+        * err_code, and return an error.
+        */
+       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+       mdelay(10);     /* Wait for 10ms before checking status. */
+
+       byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+       if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+               /* Get here if Done bit not set or Status not 0. */
+               asc_dvc->bist_err_code = byte;  /* for BIOS display message */
+               asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
+               return ADV_ERROR;
        }
-       if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
-               eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
+
+       /* We need to reset back to normal mode after LRAM test passes. */
+       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+       asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf,
+                                _adv_asc38C1600_size, ADV_38C1600_MEMSIZE,
+                                _adv_asc38C1600_chksum);
+       if (asc_dvc->err_code)
+               return ADV_ERROR;
+
+       /*
+        * Restore the RISC memory BIOS region.
+        */
+       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+               AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+                                bios_mem[i]);
        }
-       if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
-               eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
+
+       /*
+        * Calculate and write the microcode code checksum to the microcode
+        * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+        */
+       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+       AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+       code_sum = 0;
+       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+       for (word = begin_addr; word < end_addr; word += 2) {
+               code_sum += AdvReadWordAutoIncLram(iop_base);
        }
-       if (eep_config->max_tag_qng > eep_config->max_total_qng) {
-               eep_config->max_tag_qng = eep_config->max_total_qng;
+       AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+       /*
+        * Read microcode version and date.
+        */
+       AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+                       asc_dvc->cfg->mcode_date);
+       AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+                       asc_dvc->cfg->mcode_version);
+
+       /*
+        * Set the chip type to indicate the ASC38C1600.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
+
+       /*
+        * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+        * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+        * cable detection and then we are able to read C_DET[3:0].
+        *
+        * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+        * Microcode Default Value' section below.
+        */
+       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+       AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+                            scsi_cfg1 | DIS_TERM_DRV);
+
+       /*
+        * If the PCI Configuration Command Register "Parity Error Response
+        * Control" Bit was clear (0), then set the microcode variable
+        * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+        * to ignore DMA parity errors.
+        */
+       if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+               word |= CONTROL_FLAG_IGNORE_PERR;
+               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+       }
+
+       /*
+        * If the BIOS control flag AIPP (Asynchronous Information
+        * Phase Protection) disable bit is not set, then set the firmware
+        * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
+        * AIPP checking and encoding.
+        */
+       if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
+               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+               word |= CONTROL_FLAG_ENABLE_AIPP;
+               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+       }
+
+       /*
+        * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
+        * and START_CTL_TH [3:2].
+        */
+       AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+                            FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+
+       /*
+        * Microcode operating variables for WDTR, SDTR, and command tag
+        * queuing will be set in slave_configure() based on what a
+        * device reports it is capable of in Inquiry byte 7.
+        *
+        * If SCSI Bus Resets have been disabled, then directly set
+        * SDTR and WDTR from the EEPROM configuration. This will allow
+        * the BIOS and warm boot to work without a SCSI bus hang on
+        * the Inquiry caused by host and target mismatched DTR values.
+        * Without the SCSI Bus Reset, before an Inquiry a device can't
+        * be assumed to be in Asynchronous, Narrow mode.
+        */
+       if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+               AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+                                asc_dvc->wdtr_able);
+               AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+                                asc_dvc->sdtr_able);
        }
-       if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
-               eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+
+       /*
+        * Set microcode operating variables for DISC and SDTR_SPEED1,
+        * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+        * configuration values.
+        *
+        * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+        * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+        * without determining here whether the device supports SDTR.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+                        asc_dvc->cfg->disc_enable);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+       /*
+        * Set SCSI_CFG0 Microcode Default Value.
+        *
+        * The microcode will set the SCSI_CFG0 register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+                        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+                        asc_dvc->chip_scsi_id);
+
+       /*
+        * Calculate SCSI_CFG1 Microcode Default Value.
+        *
+        * The microcode will set the SCSI_CFG1 register using this value
+        * after it is started below.
+        *
+        * Each ASC-38C1600 function has only two cable detect bits.
+        * The bus mode override bits are in IOPB_SOFT_OVER_WR.
+        */
+       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+       /*
+        * If the cable is reversed all of the SCSI_CTRL register signals
+        * will be set. Check for and return an error if this condition is
+        * found.
+        */
+       if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+               asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+               return ADV_ERROR;
        }
-       asc_dvc->max_total_qng = eep_config->max_total_qng;
-       if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
-           eep_config->use_cmd_qng) {
-               eep_config->disc_enable = eep_config->use_cmd_qng;
-               warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+
+       /*
+        * Each ASC-38C1600 function has two connectors. Only an HVD device
+        * can not be connected to either connector. An LVD device or SE device
+        * may be connected to either connecor. If an SE device is connected,
+        * then at most Ultra speed (20 Mhz) can be used on both connectors.
+        *
+        * If an HVD device is attached, return an error.
+        */
+       if (scsi_cfg1 & HVD) {
+               asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+               return ADV_ERROR;
        }
-       if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
-               asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
+
+       /*
+        * Each function in the ASC-38C1600 uses only the SE cable detect and
+        * termination because there are two connectors for each function. Each
+        * function may use either LVD or SE mode. Corresponding the SE automatic
+        * termination control EEPROM bits are used for each function. Each
+        * function has its own EEPROM. If SE automatic control is enabled for
+        * the function, then set the termination value based on a table listed
+        * in a_condor.h.
+        *
+        * If manual termination is specified in the EEPROM for the function,
+        * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
+        * ready to be 'ored' into SCSI_CFG1.
+        */
+       if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+               struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
+               /* SE automatic termination control is enabled. */
+               switch (scsi_cfg1 & C_DET_SE) {
+                       /* TERM_SE_HI: on, TERM_SE_LO: on */
+               case 0x1:
+               case 0x2:
+               case 0x3:
+                       asc_dvc->cfg->termination |= TERM_SE;
+                       break;
+
+               case 0x0:
+                       if (PCI_FUNC(pdev->devfn) == 0) {
+                               /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
+                       } else {
+                               /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
+                               asc_dvc->cfg->termination |= TERM_SE_HI;
+                       }
+                       break;
+               }
        }
-       ASC_EEP_SET_CHIP_ID(eep_config,
-                           ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
-       asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
-       if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
-           !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
-               asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+
+       /*
+        * Clear any set TERM_SE bits.
+        */
+       scsi_cfg1 &= ~TERM_SE;
+
+       /*
+        * Invert the TERM_SE bits and then set 'scsi_cfg1'.
+        */
+       scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
+
+       /*
+        * Clear Big Endian and Terminator Polarity bits and set possibly
+        * modified termination control bits in the Microcode SCSI_CFG1
+        * Register Value.
+        *
+        * Big Endian bit is not used even on big endian machines.
+        */
+       scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
+
+       /*
+        * Set SCSI_CFG1 Microcode Default Value
+        *
+        * Set possibly modified termination control bits in the Microcode
+        * SCSI_CFG1 Register Value.
+        *
+        * The microcode will set the SCSI_CFG1 register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+       /*
+        * Set MEM_CFG Microcode Default Value
+        *
+        * The microcode will set the MEM_CFG register using this value
+        * after it is started below.
+        *
+        * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+        * are defined.
+        *
+        * ASC-38C1600 has 32KB internal memory.
+        *
+        * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
+        * out a special 16K Adv Library and Microcode version. After the issue
+        * resolved, we should turn back to the 32K support. Both a_condor.h and
+        * mcode.sas files also need to be updated.
+        *
+        * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        *  BIOS_EN | RAM_SZ_32KB);
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+                        BIOS_EN | RAM_SZ_16KB);
+
+       /*
+        * Set SEL_MASK Microcode Default Value
+        *
+        * The microcode will set the SEL_MASK register using this value
+        * after it is started below.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+       AdvBuildCarrierFreelist(asc_dvc);
+
+       /*
+        * Set-up the Host->RISC Initiator Command Queue (ICQ).
+        */
+       if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+               return ADV_ERROR;
        }
+       asc_dvc->carr_freelist = (ADV_CARR_T *)
+           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
-               asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
-               asc_dvc->cfg->sdtr_period_offset[i] =
-                   (uchar)(ASC_DEF_SDTR_OFFSET |
-                           (asc_dvc->host_init_sdtr_index << 4));
+       /*
+        * The first command issued will be placed in the stopper carrier.
+        */
+       asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+       /*
+        * Set RISC ICQ physical address start value. Initialize the
+        * COMMA register to the same value otherwise the RISC will
+        * prematurely detect a command is available.
+        */
+       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+       AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+                             le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+
+       /*
+        * Set-up the RISC->Host Initiator Response Queue (IRQ).
+        */
+       if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+               return ADV_ERROR;
        }
-       eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
-       if (write_eep) {
-               if ((i =
-                    AscSetEEPConfig(iop_base, eep_config,
-                                    asc_dvc->bus_type)) != 0) {
-                       ASC_PRINT1
-                           ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
-                            i);
+       asc_dvc->carr_freelist = (ADV_CARR_T *)
+           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+       /*
+        * The first command completed by the RISC will be placed in
+        * the stopper.
+        *
+        * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+        * completed the RISC will set the ASC_RQ_STOPPER bit.
+        */
+       asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+       /*
+        * Set RISC IRQ physical address start value.
+        */
+       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+       asc_dvc->carr_pending_cnt = 0;
+
+       AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+                            (ADV_INTR_ENABLE_HOST_INTR |
+                             ADV_INTR_ENABLE_GLOBAL_INTR));
+       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+       AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+       /* finally, finally, gentlemen, start your engine */
+       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+       /*
+        * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+        * Resets should be performed. The RISC has to be running
+        * to issue a SCSI Bus Reset.
+        */
+       if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+               /*
+                * If the BIOS Signature is present in memory, restore the
+                * per TID microcode operating variables.
+                */
+               if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+                   0x55AA) {
+                       /*
+                        * Restore per TID negotiated values.
+                        */
+                       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+                       AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+                                        tagqng_able);
+                       for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+                               AdvWriteByteLram(iop_base,
+                                                ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                                                max_cmd[tid]);
+                       }
                } else {
-                       ASC_PRINT
-                           ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
+                       if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+                               warn_code = ASC_WARN_BUSRESET_ERROR;
+                       }
                }
        }
-       return (warn_code);
+
+       return warn_code;
 }
 
-static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
+/*
+ * Reset chip and SCSI Bus.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) -   Chip re-initialization and SCSI Bus Reset successful.
+ *      ADV_FALSE(0) -  Chip re-initialization and SCSI Bus Reset failure.
+ */
+static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
 {
-       int i;
-       ushort warn_code;
-       PortAddr iop_base;
-       ASC_PADDR phy_addr;
-       ASC_DCNT phy_size;
+       int status;
+       ushort wdtr_able, sdtr_able, tagqng_able;
+       ushort ppr_able = 0;
+       uchar tid, max_cmd[ADV_MAX_TID + 1];
+       AdvPortAddr iop_base;
+       ushort bios_sig;
 
        iop_base = asc_dvc->iop_base;
-       warn_code = 0;
-       for (i = 0; i <= ASC_MAX_TID; i++) {
-               AscPutMCodeInitSDTRAtID(iop_base, i,
-                                       asc_dvc->cfg->sdtr_period_offset[i]
-                   );
+
+       /*
+        * Save current per TID negotiated values.
+        */
+       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+       if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+               AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+       }
+       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                               max_cmd[tid]);
        }
 
-       AscInitQLinkVar(asc_dvc);
-       AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
-                        asc_dvc->cfg->disc_enable);
-       AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
-                        ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+       /*
+        * Force the AdvInitAsc3550/38C0800Driver() function to
+        * perform a SCSI Bus Reset by clearing the BIOS signature word.
+        * The initialization functions assumes a SCSI Bus Reset is not
+        * needed if the BIOS signature word is present.
+        */
+       AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+       AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
 
-       /* Align overrun buffer on an 8 byte boundary. */
-       phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
-       phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
-       AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
-                                (uchar *)&phy_addr, 1);
-       phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
-       AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
-                                (uchar *)&phy_size, 1);
+       /*
+        * Stop chip and reset it.
+        */
+       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+       AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+       mdelay(100);
+       AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+                            ADV_CTRL_REG_CMD_WR_IO_REG);
 
-       asc_dvc->cfg->mcode_date =
-           AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
-       asc_dvc->cfg->mcode_version =
-           AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
+       /*
+        * Reset Adv Library error code, if any, and try
+        * re-initializing the chip.
+        */
+       asc_dvc->err_code = 0;
+       if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+               status = AdvInitAsc38C1600Driver(asc_dvc);
+       } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+               status = AdvInitAsc38C0800Driver(asc_dvc);
+       } else {
+               status = AdvInitAsc3550Driver(asc_dvc);
+       }
 
-       AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-       if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-               asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
-               return (warn_code);
+       /* Translate initialization return value to status value. */
+       if (status == 0) {
+               status = ADV_TRUE;
+       } else {
+               status = ADV_FALSE;
        }
-       if (AscStartChip(iop_base) != 1) {
-               asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
-               return (warn_code);
+
+       /*
+        * Restore the BIOS signature word.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+
+       /*
+        * Restore per TID negotiated values.
+        */
+       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+       if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+               AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+       }
+       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+               AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                                max_cmd[tid]);
        }
 
-       return (warn_code);
+       return status;
 }
 
-static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
+/*
+ * adv_async_callback() - Adv Library asynchronous event callback function.
+ */
+static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
 {
-       PortAddr iop_base;
-       ushort q_addr;
-       ushort saved_word;
-       int sta;
+       switch (code) {
+       case ADV_ASYNC_SCSI_BUS_RESET_DET:
+               /*
+                * The firmware detected a SCSI Bus reset.
+                */
+               ASC_DBG(0, "ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+               break;
 
-       iop_base = asc_dvc->iop_base;
-       sta = 0;
-       q_addr = ASC_QNO_TO_QADDR(241);
-       saved_word = AscReadLramWord(iop_base, q_addr);
-       AscSetChipLramAddr(iop_base, q_addr);
-       AscSetChipLramData(iop_base, 0x55AA);
-       DvcSleepMilliSecond(10);
-       AscSetChipLramAddr(iop_base, q_addr);
-       if (AscGetChipLramData(iop_base) == 0x55AA) {
-               sta = 1;
-               AscWriteLramWord(iop_base, q_addr, saved_word);
+       case ADV_ASYNC_RDMA_FAILURE:
+               /*
+                * Handle RDMA failure by resetting the SCSI Bus and
+                * possibly the chip if it is unresponsive. Log the error
+                * with a unique code.
+                */
+               ASC_DBG(0, "ADV_ASYNC_RDMA_FAILURE\n");
+               AdvResetChipAndSB(adv_dvc_varp);
+               break;
+
+       case ADV_HOST_SCSI_BUS_RESET:
+               /*
+                * Host generated SCSI bus reset occurred.
+                */
+               ASC_DBG(0, "ADV_HOST_SCSI_BUS_RESET\n");
+               break;
+
+       default:
+               ASC_DBG(0, "unknown code 0x%x\n", code);
+               break;
        }
-       return (sta);
 }
 
-static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
+/*
+ * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ *
+ * Callback function for the Wide SCSI Adv Library.
+ */
+static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
 {
-       uchar read_back;
-       int retry;
+       struct asc_board *boardp;
+       adv_req_t *reqp;
+       adv_sgblk_t *sgblkp;
+       struct scsi_cmnd *scp;
+       struct Scsi_Host *shost;
+       ADV_DCNT resid_cnt;
 
-       retry = 0;
-       while (TRUE) {
-               AscSetChipEEPCmd(iop_base, cmd_reg);
-               DvcSleepMilliSecond(1);
-               read_back = AscGetChipEEPCmd(iop_base);
-               if (read_back == cmd_reg) {
-                       return (1);
-               }
-               if (retry++ > ASC_EEP_MAX_RETRY) {
-                       return (0);
-               }
+       ASC_DBG(1, "adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
+                (ulong)adv_dvc_varp, (ulong)scsiqp);
+       ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+
+       /*
+        * Get the adv_req_t structure for the command that has been
+        * completed. The adv_req_t structure actually contains the
+        * completed ADV_SCSI_REQ_Q structure.
+        */
+       reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
+       ASC_DBG(1, "reqp 0x%lx\n", (ulong)reqp);
+       if (reqp == NULL) {
+               ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+               return;
        }
-}
 
-static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
-{
-       ushort read_back;
-       int retry;
+       /*
+        * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+        * command that has been completed.
+        *
+        * Note: The adv_req_t request structure and adv_sgblk_t structure,
+        * if any, are dropped, because a board structure pointer can not be
+        * determined.
+        */
+       scp = reqp->cmndp;
+       ASC_DBG(1, "scp 0x%p\n", scp);
+       if (scp == NULL) {
+               ASC_PRINT
+                   ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+               return;
+       }
+       ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
 
-       retry = 0;
-       while (TRUE) {
-               AscSetChipEEPData(iop_base, data_reg);
-               DvcSleepMilliSecond(1);
-               read_back = AscGetChipEEPData(iop_base);
-               if (read_back == data_reg) {
-                       return (1);
-               }
-               if (retry++ > ASC_EEP_MAX_RETRY) {
-                       return (0);
+       shost = scp->device->host;
+       ASC_STATS(shost, callback);
+       ASC_DBG(1, "shost 0x%p\n", shost);
+
+       boardp = shost_priv(shost);
+       BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var);
+
+       /*
+        * 'done_status' contains the command's ending status.
+        */
+       switch (scsiqp->done_status) {
+       case QD_NO_ERROR:
+               ASC_DBG(2, "QD_NO_ERROR\n");
+               scp->result = 0;
+
+               /*
+                * Check for an underrun condition.
+                *
+                * If there was no error and an underrun condition, then
+                * then return the number of underrun bytes.
+                */
+               resid_cnt = le32_to_cpu(scsiqp->data_cnt);
+               if (scsi_bufflen(scp) != 0 && resid_cnt != 0 &&
+                   resid_cnt <= scsi_bufflen(scp)) {
+                       ASC_DBG(1, "underrun condition %lu bytes\n",
+                                (ulong)resid_cnt);
+                       scsi_set_resid(scp, resid_cnt);
                }
-       }
-}
-
-static void __init AscWaitEEPRead(void)
-{
-       DvcSleepMilliSecond(1);
-       return;
-}
+               break;
 
-static void __init AscWaitEEPWrite(void)
-{
-       DvcSleepMilliSecond(20);
-       return;
-}
+       case QD_WITH_ERROR:
+               ASC_DBG(2, "QD_WITH_ERROR\n");
+               switch (scsiqp->host_status) {
+               case QHSTA_NO_ERROR:
+                       if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+                               ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+                               ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+                                                 sizeof(scp->sense_buffer));
+                               /*
+                                * Note: The 'status_byte()' macro used by
+                                * target drivers defined in scsi.h shifts the
+                                * status byte returned by host drivers right
+                                * by 1 bit.  This is why target drivers also
+                                * use right shifted status byte definitions.
+                                * For instance target drivers use
+                                * CHECK_CONDITION, defined to 0x1, instead of
+                                * the SCSI defined check condition value of
+                                * 0x2. Host drivers are supposed to return
+                                * the status byte as it is defined by SCSI.
+                                */
+                               scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+                                   STATUS_BYTE(scsiqp->scsi_status);
+                       } else {
+                               scp->result = STATUS_BYTE(scsiqp->scsi_status);
+                       }
+                       break;
 
-static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
-{
-       ushort read_wval;
-       uchar cmd_reg;
+               default:
+                       /* Some other QHSTA error occurred. */
+                       ASC_DBG(1, "host_status 0x%x\n", scsiqp->host_status);
+                       scp->result = HOST_BYTE(DID_BAD_TARGET);
+                       break;
+               }
+               break;
 
-       AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
-       AscWaitEEPRead();
-       cmd_reg = addr | ASC_EEP_CMD_READ;
-       AscWriteEEPCmdReg(iop_base, cmd_reg);
-       AscWaitEEPRead();
-       read_wval = AscGetChipEEPData(iop_base);
-       AscWaitEEPRead();
-       return (read_wval);
-}
+       case QD_ABORTED_BY_HOST:
+               ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
+               scp->result =
+                   HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+               break;
 
-static ushort __init
-AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
-{
-       ushort read_wval;
+       default:
+               ASC_DBG(1, "done_status 0x%x\n", scsiqp->done_status);
+               scp->result =
+                   HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+               break;
+       }
 
-       read_wval = AscReadEEPWord(iop_base, addr);
-       if (read_wval != word_val) {
-               AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
-               AscWaitEEPRead();
-               AscWriteEEPDataReg(iop_base, word_val);
-               AscWaitEEPRead();
-               AscWriteEEPCmdReg(iop_base,
-                                 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
-               AscWaitEEPWrite();
-               AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
-               AscWaitEEPRead();
-               return (AscReadEEPWord(iop_base, addr));
+       /*
+        * If the 'init_tidmask' bit isn't already set for the target and the
+        * current request finished normally, then set the bit for the target
+        * to indicate that a device is present.
+        */
+       if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+           scsiqp->done_status == QD_NO_ERROR &&
+           scsiqp->host_status == QHSTA_NO_ERROR) {
+               boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
        }
-       return (read_wval);
-}
 
-static ushort __init
-AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
-{
-       ushort wval;
-       ushort sum;
-       ushort *wbuf;
-       int cfg_beg;
-       int cfg_end;
-       int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
-       int s_addr;
+       asc_scsi_done(scp);
 
-       wbuf = (ushort *)cfg_buf;
-       sum = 0;
-       /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
-       for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-               *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
-               sum += *wbuf;
-       }
-       if (bus_type & ASC_IS_VL) {
-               cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-               cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-       } else {
-               cfg_beg = ASC_EEP_DVC_CFG_BEG;
-               cfg_end = ASC_EEP_MAX_DVC_ADDR;
-       }
-       for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
-               wval = AscReadEEPWord(iop_base, (uchar)s_addr);
-               if (s_addr <= uchar_end_in_config) {
-                       /*
-                        * Swap all char fields - must unswap bytes already swapped
-                        * by AscReadEEPWord().
-                        */
-                       *wbuf = le16_to_cpu(wval);
-               } else {
-                       /* Don't swap word field at the end - cntl field. */
-                       *wbuf = wval;
-               }
-               sum += wval;    /* Checksum treats all EEPROM data as words. */
+       /*
+        * Free all 'adv_sgblk_t' structures allocated for the request.
+        */
+       while ((sgblkp = reqp->sgblkp) != NULL) {
+               /* Remove 'sgblkp' from the request list. */
+               reqp->sgblkp = sgblkp->next_sgblkp;
+
+               /* Add 'sgblkp' to the board free list. */
+               sgblkp->next_sgblkp = boardp->adv_sgblkp;
+               boardp->adv_sgblkp = sgblkp;
        }
+
        /*
-        * Read the checksum word which will be compared against 'sum'
-        * by the caller. Word field already swapped.
+        * Free the adv_req_t structure used with the command by adding
+        * it back to the board free list.
         */
-       *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
-       return (sum);
+       reqp->next_reqp = boardp->adv_reqp;
+       boardp->adv_reqp = reqp;
+
+       ASC_DBG(1, "done\n");
 }
 
-static int __init
-AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+/*
+ * Adv Library Interrupt Service Routine
+ *
+ *  This function is called by a driver's interrupt service routine.
+ *  The function disables and re-enables interrupts.
+ *
+ *  When a microcode idle command is completed, the ADV_DVC_VAR
+ *  'idle_cmd_done' field is set to ADV_TRUE.
+ *
+ *  Note: AdvISR() can be called when interrupts are disabled or even
+ *  when there is no hardware interrupt condition present. It will
+ *  always check for completed idle commands and microcode requests.
+ *  This is an important feature that shouldn't be changed because it
+ *  allows commands to be completed from polling mode loops.
+ *
+ * Return:
+ *   ADV_TRUE(1) - interrupt was pending
+ *   ADV_FALSE(0) - no interrupt was pending
+ */
+static int AdvISR(ADV_DVC_VAR *asc_dvc)
 {
-       int n_error;
-       ushort *wbuf;
-       ushort word;
-       ushort sum;
-       int s_addr;
-       int cfg_beg;
-       int cfg_end;
-       int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+       AdvPortAddr iop_base;
+       uchar int_stat;
+       ushort target_bit;
+       ADV_CARR_T *free_carrp;
+       ADV_VADDR irq_next_vpa;
+       ADV_SCSI_REQ_Q *scsiq;
 
-       wbuf = (ushort *)cfg_buf;
-       n_error = 0;
-       sum = 0;
-       /* Write two config words; AscWriteEEPWord() will swap bytes. */
-       for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-               sum += *wbuf;
-               if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
-                       n_error++;
-               }
-       }
-       if (bus_type & ASC_IS_VL) {
-               cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-               cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-       } else {
-               cfg_beg = ASC_EEP_DVC_CFG_BEG;
-               cfg_end = ASC_EEP_MAX_DVC_ADDR;
-       }
-       for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
-               if (s_addr <= uchar_end_in_config) {
-                       /*
-                        * This is a char field. Swap char fields before they are
-                        * swapped again by AscWriteEEPWord().
-                        */
-                       word = cpu_to_le16(*wbuf);
-                       if (word !=
-                           AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
-                               n_error++;
-                       }
-               } else {
-                       /* Don't swap word field at the end - cntl field. */
-                       if (*wbuf !=
-                           AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
-                               n_error++;
-                       }
-               }
-               sum += *wbuf;   /* Checksum calculated from word values. */
-       }
-       /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
-       *wbuf = sum;
-       if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
-               n_error++;
+       iop_base = asc_dvc->iop_base;
+
+       /* Reading the register clears the interrupt. */
+       int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+
+       if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+                        ADV_INTR_STATUS_INTRC)) == 0) {
+               return ADV_FALSE;
        }
 
-       /* Read EEPROM back again. */
-       wbuf = (ushort *)cfg_buf;
        /*
-        * Read two config words; Byte-swapping done by AscReadEEPWord().
+        * Notify the driver of an asynchronous microcode condition by
+        * calling the adv_async_callback function. The function
+        * is passed the microcode ASC_MC_INTRB_CODE byte value.
         */
-       for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-               if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
-                       n_error++;
-               }
-       }
-       if (bus_type & ASC_IS_VL) {
-               cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-               cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-       } else {
-               cfg_beg = ASC_EEP_DVC_CFG_BEG;
-               cfg_end = ASC_EEP_MAX_DVC_ADDR;
-       }
-       for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
-               if (s_addr <= uchar_end_in_config) {
-                       /*
-                        * Swap all char fields. Must unswap bytes already swapped
-                        * by AscReadEEPWord().
-                        */
-                       word =
-                           le16_to_cpu(AscReadEEPWord
-                                       (iop_base, (uchar)s_addr));
-               } else {
-                       /* Don't swap word field at the end - cntl field. */
-                       word = AscReadEEPWord(iop_base, (uchar)s_addr);
+       if (int_stat & ADV_INTR_STATUS_INTRB) {
+               uchar intrb_code;
+
+               AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
+
+               if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+                   asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+                       if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+                           asc_dvc->carr_pending_cnt != 0) {
+                               AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+                                                    ADV_TICKLE_A);
+                               if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+                                       AdvWriteByteRegister(iop_base,
+                                                            IOPB_TICKLE,
+                                                            ADV_TICKLE_NOP);
+                               }
+                       }
                }
-               if (*wbuf != word) {
-                       n_error++;
+
+               adv_async_callback(asc_dvc, intrb_code);
+       }
+
+       /*
+        * Check if the IRQ stopper carrier contains a completed request.
+        */
+       while (((irq_next_vpa =
+                le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
+               /*
+                * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+                * The RISC will have set 'areq_vpa' to a virtual address.
+                *
+                * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
+                * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
+                * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
+                * in AdvExeScsiQueue().
+                */
+               scsiq = (ADV_SCSI_REQ_Q *)
+                   ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+
+               /*
+                * Request finished with good status and the queue was not
+                * DMAed to host memory by the firmware. Set all status fields
+                * to indicate good status.
+                */
+               if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
+                       scsiq->done_status = QD_NO_ERROR;
+                       scsiq->host_status = scsiq->scsi_status = 0;
+                       scsiq->data_cnt = 0L;
                }
+
+               /*
+                * Advance the stopper pointer to the next carrier
+                * ignoring the lower four bits. Free the previous
+                * stopper carrier.
+                */
+               free_carrp = asc_dvc->irq_sp;
+               asc_dvc->irq_sp = (ADV_CARR_T *)
+                   ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
+
+               free_carrp->next_vpa =
+                   cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+               asc_dvc->carr_freelist = free_carrp;
+               asc_dvc->carr_pending_cnt--;
+
+               target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+
+               /*
+                * Clear request microcode control flag.
+                */
+               scsiq->cntl = 0;
+
+               /*
+                * Notify the driver of the completed request by passing
+                * the ADV_SCSI_REQ_Q pointer to its callback function.
+                */
+               scsiq->a_flag |= ADV_SCSIQ_DONE;
+               adv_isr_callback(asc_dvc, scsiq);
+               /*
+                * Note: After the driver callback function is called, 'scsiq'
+                * can no longer be referenced.
+                *
+                * Fall through and continue processing other completed
+                * requests...
+                */
        }
-       /* Read checksum; Byte swapping not needed. */
-       if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
-               n_error++;
+       return ADV_TRUE;
+}
+
+static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
+{
+       if (asc_dvc->err_code == 0) {
+               asc_dvc->err_code = err_code;
+               AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+                                err_code);
        }
-       return (n_error);
+       return err_code;
 }
 
-static int __init
-AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+static void AscAckInterrupt(PortAddr iop_base)
 {
-       int retry;
-       int n_error;
+       uchar host_flag;
+       uchar risc_flag;
+       ushort loop;
 
-       retry = 0;
-       while (TRUE) {
-               if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
-                                                  bus_type)) == 0) {
+       loop = 0;
+       do {
+               risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+               if (loop++ > 0x7FFF) {
                        break;
                }
-               if (++retry > ASC_EEP_MAX_RETRY) {
+       } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+       host_flag =
+           AscReadLramByte(iop_base,
+                           ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
+       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+                        (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
+       AscSetChipStatus(iop_base, CIW_INT_ACK);
+       loop = 0;
+       while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+               AscSetChipStatus(iop_base, CIW_INT_ACK);
+               if (loop++ > 3) {
                        break;
                }
        }
-       return (n_error);
+       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
 }
 
-static void
-AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
+static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
 {
-       uchar dvc_type;
-       ASC_SCSI_BIT_ID_TYPE tid_bits;
-
-       dvc_type = ASC_INQ_DVC_TYPE(inq);
-       tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
-
-       if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
-               if (!(asc_dvc->init_sdtr & tid_bits)) {
-                       if ((dvc_type == TYPE_ROM) &&
-                           (AscCompareString((uchar *)inq->vendor_id,
-                                             (uchar *)"HP ", 3) == 0)) {
-                               asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
-                       }
-                       asc_dvc->pci_fix_asyn_xfer |= tid_bits;
-                       if ((dvc_type == TYPE_PROCESSOR) ||
-                           (dvc_type == TYPE_SCANNER) ||
-                           (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
-                               asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-                       }
+       const uchar *period_table;
+       int max_index;
+       int min_index;
+       int i;
 
-                       if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
-                               AscSetRunChipSynRegAtID(asc_dvc->iop_base,
-                                                       tid_no,
-                                                       ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+       period_table = asc_dvc->sdtr_period_tbl;
+       max_index = (int)asc_dvc->max_sdtr_index;
+       min_index = (int)asc_dvc->min_sdtr_index;
+       if ((syn_time <= period_table[max_index])) {
+               for (i = min_index; i < (max_index - 1); i++) {
+                       if (syn_time <= period_table[i]) {
+                               return (uchar)i;
                        }
                }
+               return (uchar)max_index;
+       } else {
+               return (uchar)(max_index + 1);
        }
-       return;
 }
 
-static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
+static uchar
+AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
 {
-       if ((inq->add_len >= 32) &&
-           (AscCompareString((uchar *)inq->vendor_id,
-                             (uchar *)"QUANTUM XP34301", 15) == 0) &&
-           (AscCompareString((uchar *)inq->product_rev_level,
-                             (uchar *)"1071", 4) == 0)) {
+       EXT_MSG sdtr_buf;
+       uchar sdtr_period_index;
+       PortAddr iop_base;
+
+       iop_base = asc_dvc->iop_base;
+       sdtr_buf.msg_type = EXTENDED_MESSAGE;
+       sdtr_buf.msg_len = MS_SDTR_LEN;
+       sdtr_buf.msg_req = EXTENDED_SDTR;
+       sdtr_buf.xfer_period = sdtr_period;
+       sdtr_offset &= ASC_SYN_MAX_OFFSET;
+       sdtr_buf.req_ack_offset = sdtr_offset;
+       sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+       if (sdtr_period_index <= asc_dvc->max_sdtr_index) {
+               AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
+                                       (uchar *)&sdtr_buf,
+                                       sizeof(EXT_MSG) >> 1);
+               return ((sdtr_period_index << 4) | sdtr_offset);
+       } else {
+               sdtr_buf.req_ack_offset = 0;
+               AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
+                                       (uchar *)&sdtr_buf,
+                                       sizeof(EXT_MSG) >> 1);
                return 0;
        }
-       return 1;
 }
 
-static void
-AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
+static uchar
+AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
 {
-       ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
-       ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
+       uchar byte;
+       uchar sdtr_period_ix;
 
-       orig_init_sdtr = asc_dvc->init_sdtr;
-       orig_use_tagged_qng = asc_dvc->use_tagged_qng;
+       sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+       if (sdtr_period_ix > asc_dvc->max_sdtr_index)
+               return 0xFF;
+       byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+       return byte;
+}
 
-       asc_dvc->init_sdtr &= ~tid_bit;
-       asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
-       asc_dvc->use_tagged_qng &= ~tid_bit;
+static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
+{
+       ASC_SCSI_BIT_ID_TYPE org_id;
+       int i;
+       int sta = TRUE;
 
-       if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
-               if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
-                       asc_dvc->init_sdtr |= tid_bit;
-               }
-               if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
-                   ASC_INQ_CMD_QUEUE(inq)) {
-                       if (AscTagQueuingSafe(inq)) {
-                               asc_dvc->use_tagged_qng |= tid_bit;
-                               asc_dvc->cfg->can_tagged_qng |= tid_bit;
-                       }
+       AscSetBank(iop_base, 1);
+       org_id = AscReadChipDvcID(iop_base);
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               if (org_id == (0x01 << i))
+                       break;
+       }
+       org_id = (ASC_SCSI_BIT_ID_TYPE) i;
+       AscWriteChipDvcID(iop_base, id);
+       if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
+               AscSetBank(iop_base, 0);
+               AscSetChipSyn(iop_base, sdtr_data);
+               if (AscGetChipSyn(iop_base) != sdtr_data) {
+                       sta = FALSE;
                }
+       } else {
+               sta = FALSE;
        }
-       if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
-               AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
-                                asc_dvc->cfg->disc_enable);
-               AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
-                                asc_dvc->use_tagged_qng);
-               AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
-                                asc_dvc->cfg->can_tagged_qng);
+       AscSetBank(iop_base, 1);
+       AscWriteChipDvcID(iop_base, org_id);
+       AscSetBank(iop_base, 0);
+       return (sta);
+}
 
-               asc_dvc->max_dvc_qng[tid_no] =
-                   asc_dvc->cfg->max_tag_qng[tid_no];
-               AscWriteLramByte(asc_dvc->iop_base,
-                                (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
-                                asc_dvc->max_dvc_qng[tid_no]);
-       }
-       if (orig_init_sdtr != asc_dvc->init_sdtr) {
-               AscAsyncFix(asc_dvc, tid_no, inq);
-       }
-       return;
+static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
+{
+       AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+       AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
 }
 
-static int AscCompareString(uchar *str1, uchar *str2, int len)
+static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
 {
-       int i;
-       int diff;
+       EXT_MSG ext_msg;
+       EXT_MSG out_msg;
+       ushort halt_q_addr;
+       int sdtr_accept;
+       ushort int_halt_code;
+       ASC_SCSI_BIT_ID_TYPE scsi_busy;
+       ASC_SCSI_BIT_ID_TYPE target_id;
+       PortAddr iop_base;
+       uchar tag_code;
+       uchar q_status;
+       uchar halt_qp;
+       uchar sdtr_data;
+       uchar target_ix;
+       uchar q_cntl, tid_no;
+       uchar cur_dvc_qng;
+       uchar asyn_sdtr;
+       uchar scsi_status;
+       struct asc_board *boardp;
+
+       BUG_ON(!asc_dvc->drv_ptr);
+       boardp = asc_dvc->drv_ptr;
+
+       iop_base = asc_dvc->iop_base;
+       int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
 
-       for (i = 0; i < len; i++) {
-               diff = (int)(str1[i] - str2[i]);
-               if (diff != 0)
-                       return (diff);
+       halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
+       halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
+       target_ix = AscReadLramByte(iop_base,
+                                   (ushort)(halt_q_addr +
+                                            (ushort)ASC_SCSIQ_B_TARGET_IX));
+       q_cntl = AscReadLramByte(iop_base,
+                           (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
+       tid_no = ASC_TIX_TO_TID(target_ix);
+       target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
+       if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+               asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
+       } else {
+               asyn_sdtr = 0;
        }
-       return (0);
-}
+       if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
+               if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+                       AscSetChipSDTR(iop_base, 0, tid_no);
+                       boardp->sdtr_data[tid_no] = 0;
+               }
+               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+               return (0);
+       } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
+               if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+                       AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+                       boardp->sdtr_data[tid_no] = asyn_sdtr;
+               }
+               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+               return (0);
+       } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
+               AscMemWordCopyPtrFromLram(iop_base,
+                                         ASCV_MSGIN_BEG,
+                                         (uchar *)&ext_msg,
+                                         sizeof(EXT_MSG) >> 1);
+
+               if (ext_msg.msg_type == EXTENDED_MESSAGE &&
+                   ext_msg.msg_req == EXTENDED_SDTR &&
+                   ext_msg.msg_len == MS_SDTR_LEN) {
+                       sdtr_accept = TRUE;
+                       if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
 
-static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
-{
-       uchar byte_data;
-       ushort word_data;
+                               sdtr_accept = FALSE;
+                               ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
+                       }
+                       if ((ext_msg.xfer_period <
+                            asc_dvc->sdtr_period_tbl[asc_dvc->min_sdtr_index])
+                           || (ext_msg.xfer_period >
+                               asc_dvc->sdtr_period_tbl[asc_dvc->
+                                                        max_sdtr_index])) {
+                               sdtr_accept = FALSE;
+                               ext_msg.xfer_period =
+                                   asc_dvc->sdtr_period_tbl[asc_dvc->
+                                                            min_sdtr_index];
+                       }
+                       if (sdtr_accept) {
+                               sdtr_data =
+                                   AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+                                                  ext_msg.req_ack_offset);
+                               if ((sdtr_data == 0xFF)) {
 
-       if (isodd_word(addr)) {
-               AscSetChipLramAddr(iop_base, addr - 1);
-               word_data = AscGetChipLramData(iop_base);
-               byte_data = (uchar)((word_data >> 8) & 0xFF);
-       } else {
-               AscSetChipLramAddr(iop_base, addr);
-               word_data = AscGetChipLramData(iop_base);
-               byte_data = (uchar)(word_data & 0xFF);
-       }
-       return (byte_data);
-}
+                                       q_cntl |= QC_MSG_OUT;
+                                       asc_dvc->init_sdtr &= ~target_id;
+                                       asc_dvc->sdtr_done &= ~target_id;
+                                       AscSetChipSDTR(iop_base, asyn_sdtr,
+                                                      tid_no);
+                                       boardp->sdtr_data[tid_no] = asyn_sdtr;
+                               }
+                       }
+                       if (ext_msg.req_ack_offset == 0) {
 
-static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
-{
-       ushort word_data;
+                               q_cntl &= ~QC_MSG_OUT;
+                               asc_dvc->init_sdtr &= ~target_id;
+                               asc_dvc->sdtr_done &= ~target_id;
+                               AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+                       } else {
+                               if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
+                                       q_cntl &= ~QC_MSG_OUT;
+                                       asc_dvc->sdtr_done |= target_id;
+                                       asc_dvc->init_sdtr |= target_id;
+                                       asc_dvc->pci_fix_asyn_xfer &=
+                                           ~target_id;
+                                       sdtr_data =
+                                           AscCalSDTRData(asc_dvc,
+                                                          ext_msg.xfer_period,
+                                                          ext_msg.
+                                                          req_ack_offset);
+                                       AscSetChipSDTR(iop_base, sdtr_data,
+                                                      tid_no);
+                                       boardp->sdtr_data[tid_no] = sdtr_data;
+                               } else {
+                                       q_cntl |= QC_MSG_OUT;
+                                       AscMsgOutSDTR(asc_dvc,
+                                                     ext_msg.xfer_period,
+                                                     ext_msg.req_ack_offset);
+                                       asc_dvc->pci_fix_asyn_xfer &=
+                                           ~target_id;
+                                       sdtr_data =
+                                           AscCalSDTRData(asc_dvc,
+                                                          ext_msg.xfer_period,
+                                                          ext_msg.
+                                                          req_ack_offset);
+                                       AscSetChipSDTR(iop_base, sdtr_data,
+                                                      tid_no);
+                                       boardp->sdtr_data[tid_no] = sdtr_data;
+                                       asc_dvc->sdtr_done |= target_id;
+                                       asc_dvc->init_sdtr |= target_id;
+                               }
+                       }
 
-       AscSetChipLramAddr(iop_base, addr);
-       word_data = AscGetChipLramData(iop_base);
-       return (word_data);
-}
+                       AscWriteLramByte(iop_base,
+                                        (ushort)(halt_q_addr +
+                                                 (ushort)ASC_SCSIQ_B_CNTL),
+                                        q_cntl);
+                       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+                       return (0);
+               } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
+                          ext_msg.msg_req == EXTENDED_WDTR &&
+                          ext_msg.msg_len == MS_WDTR_LEN) {
 
-#if CC_VERY_LONG_SG_LIST
-static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
-{
-       ushort val_low, val_high;
-       ASC_DCNT dword_data;
+                       ext_msg.wdtr_width = 0;
+                       AscMemWordCopyPtrToLram(iop_base,
+                                               ASCV_MSGOUT_BEG,
+                                               (uchar *)&ext_msg,
+                                               sizeof(EXT_MSG) >> 1);
+                       q_cntl |= QC_MSG_OUT;
+                       AscWriteLramByte(iop_base,
+                                        (ushort)(halt_q_addr +
+                                                 (ushort)ASC_SCSIQ_B_CNTL),
+                                        q_cntl);
+                       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+                       return (0);
+               } else {
 
-       AscSetChipLramAddr(iop_base, addr);
-       val_low = AscGetChipLramData(iop_base);
-       val_high = AscGetChipLramData(iop_base);
-       dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
-       return (dword_data);
-}
-#endif /* CC_VERY_LONG_SG_LIST */
+                       ext_msg.msg_type = MESSAGE_REJECT;
+                       AscMemWordCopyPtrToLram(iop_base,
+                                               ASCV_MSGOUT_BEG,
+                                               (uchar *)&ext_msg,
+                                               sizeof(EXT_MSG) >> 1);
+                       q_cntl |= QC_MSG_OUT;
+                       AscWriteLramByte(iop_base,
+                                        (ushort)(halt_q_addr +
+                                                 (ushort)ASC_SCSIQ_B_CNTL),
+                                        q_cntl);
+                       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+                       return (0);
+               }
+       } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
 
-static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
-{
-       AscSetChipLramAddr(iop_base, addr);
-       AscSetChipLramData(iop_base, word_val);
-       return;
-}
+               q_cntl |= QC_REQ_SENSE;
 
-static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
-{
-       ushort word_data;
+               if ((asc_dvc->init_sdtr & target_id) != 0) {
 
-       if (isodd_word(addr)) {
-               addr--;
-               word_data = AscReadLramWord(iop_base, addr);
-               word_data &= 0x00FF;
-               word_data |= (((ushort)byte_val << 8) & 0xFF00);
-       } else {
-               word_data = AscReadLramWord(iop_base, addr);
-               word_data &= 0xFF00;
-               word_data |= ((ushort)byte_val & 0x00FF);
-       }
-       AscWriteLramWord(iop_base, addr, word_data);
-       return;
-}
+                       asc_dvc->sdtr_done &= ~target_id;
 
-/*
- * Copy 2 bytes to LRAM.
- *
- * The source data is assumed to be in little-endian order in memory
- * and is maintained in little-endian order when written to LRAM.
- */
-static void
-AscMemWordCopyPtrToLram(PortAddr iop_base,
-                       ushort s_addr, uchar *s_buffer, int words)
-{
-       int i;
+                       sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+                       q_cntl |= QC_MSG_OUT;
+                       AscMsgOutSDTR(asc_dvc,
+                                     asc_dvc->
+                                     sdtr_period_tbl[(sdtr_data >> 4) &
+                                                     (uchar)(asc_dvc->
+                                                             max_sdtr_index -
+                                                             1)],
+                                     (uchar)(sdtr_data & (uchar)
+                                             ASC_SYN_MAX_OFFSET));
+               }
 
-       AscSetChipLramAddr(iop_base, s_addr);
-       for (i = 0; i < 2 * words; i += 2) {
-               /*
-                * On a little-endian system the second argument below
-                * produces a little-endian ushort which is written to
-                * LRAM in little-endian order. On a big-endian system
-                * the second argument produces a big-endian ushort which
-                * is "transparently" byte-swapped by outpw() and written
-                * in little-endian order to LRAM.
-                */
-               outpw(iop_base + IOP_RAM_DATA,
-                     ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
-       }
-       return;
-}
+               AscWriteLramByte(iop_base,
+                                (ushort)(halt_q_addr +
+                                         (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
 
-/*
- * Copy 4 bytes to LRAM.
- *
- * The source data is assumed to be in little-endian order in memory
- * and is maintained in little-endian order when writen to LRAM.
- */
-static void
-AscMemDWordCopyPtrToLram(PortAddr iop_base,
-                        ushort s_addr, uchar *s_buffer, int dwords)
-{
-       int i;
+               tag_code = AscReadLramByte(iop_base,
+                                          (ushort)(halt_q_addr + (ushort)
+                                                   ASC_SCSIQ_B_TAG_CODE));
+               tag_code &= 0xDC;
+               if ((asc_dvc->pci_fix_asyn_xfer & target_id)
+                   && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
+                   ) {
 
-       AscSetChipLramAddr(iop_base, s_addr);
-       for (i = 0; i < 4 * dwords; i += 4) {
-               outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);   /* LSW */
-               outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]);       /* MSW */
-       }
-       return;
-}
+                       tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
+                                    | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
 
-/*
- * Copy 2 bytes from LRAM.
- *
- * The source data is assumed to be in little-endian order in LRAM
- * and is maintained in little-endian order when written to memory.
- */
-static void
-AscMemWordCopyPtrFromLram(PortAddr iop_base,
-                         ushort s_addr, uchar *d_buffer, int words)
-{
-       int i;
-       ushort word;
+               }
+               AscWriteLramByte(iop_base,
+                                (ushort)(halt_q_addr +
+                                         (ushort)ASC_SCSIQ_B_TAG_CODE),
+                                tag_code);
 
-       AscSetChipLramAddr(iop_base, s_addr);
-       for (i = 0; i < 2 * words; i += 2) {
-               word = inpw(iop_base + IOP_RAM_DATA);
-               d_buffer[i] = word & 0xff;
-               d_buffer[i + 1] = (word >> 8) & 0xff;
-       }
-       return;
-}
+               q_status = AscReadLramByte(iop_base,
+                                          (ushort)(halt_q_addr + (ushort)
+                                                   ASC_SCSIQ_B_STATUS));
+               q_status |= (QS_READY | QS_BUSY);
+               AscWriteLramByte(iop_base,
+                                (ushort)(halt_q_addr +
+                                         (ushort)ASC_SCSIQ_B_STATUS),
+                                q_status);
 
-static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
-{
-       ASC_DCNT sum;
-       int i;
+               scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
+               scsi_busy &= ~target_id;
+               AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
 
-       sum = 0L;
-       for (i = 0; i < words; i++, s_addr += 2) {
-               sum += AscReadLramWord(iop_base, s_addr);
-       }
-       return (sum);
-}
+               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+               return (0);
+       } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
 
-static void
-AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
-{
-       int i;
+               AscMemWordCopyPtrFromLram(iop_base,
+                                         ASCV_MSGOUT_BEG,
+                                         (uchar *)&out_msg,
+                                         sizeof(EXT_MSG) >> 1);
 
-       AscSetChipLramAddr(iop_base, s_addr);
-       for (i = 0; i < words; i++) {
-               AscSetChipLramData(iop_base, set_wval);
-       }
-       return;
-}
+               if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
+                   (out_msg.msg_len == MS_SDTR_LEN) &&
+                   (out_msg.msg_req == EXTENDED_SDTR)) {
 
-/*
- * --- Adv Library Functions
- */
+                       asc_dvc->init_sdtr &= ~target_id;
+                       asc_dvc->sdtr_done &= ~target_id;
+                       AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+                       boardp->sdtr_data[tid_no] = asyn_sdtr;
+               }
+               q_cntl &= ~QC_MSG_OUT;
+               AscWriteLramByte(iop_base,
+                                (ushort)(halt_q_addr +
+                                         (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
+               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+               return (0);
+       } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
 
-/* a_mcode.h */
+               scsi_status = AscReadLramByte(iop_base,
+                                             (ushort)((ushort)halt_q_addr +
+                                                      (ushort)
+                                                      ASC_SCSIQ_SCSI_STATUS));
+               cur_dvc_qng =
+                   AscReadLramByte(iop_base,
+                                   (ushort)((ushort)ASC_QADR_BEG +
+                                            (ushort)target_ix));
+               if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
 
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc3550_buf[] = {
-       0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
-       0x01, 0x00, 0x48, 0xe4,
-       0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
-       0x28, 0x0e, 0x9e, 0xe7,
-       0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
-       0x55, 0xf0, 0x01, 0xf6,
-       0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
-       0x00, 0xec, 0x85, 0xf0,
-       0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
-       0x86, 0xf0, 0xb4, 0x00,
-       0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
-       0xaa, 0x18, 0x02, 0x80,
-       0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
-       0x00, 0x57, 0x01, 0xea,
-       0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
-       0x03, 0xe6, 0xb6, 0x00,
-       0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
-       0x02, 0x4a, 0xb9, 0x54,
-       0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
-       0x3e, 0x00, 0x80, 0x00,
-       0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
-       0x74, 0x01, 0x76, 0x01,
-       0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
-       0x4c, 0x1c, 0xbb, 0x55,
-       0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
-       0x03, 0xf7, 0x06, 0xf7,
-       0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
-       0x30, 0x13, 0x64, 0x15,
-       0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
-       0x04, 0xea, 0x5d, 0xf0,
-       0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
-       0xcc, 0x00, 0x20, 0x01,
-       0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
-       0x40, 0x13, 0x30, 0x1c,
-       0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
-       0x59, 0xf0, 0xa7, 0xf0,
-       0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
-       0xa4, 0x00, 0xb5, 0x00,
-       0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
-       0x14, 0x0e, 0x02, 0x10,
-       0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
-       0x10, 0x15, 0x14, 0x15,
-       0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
-       0x91, 0x44, 0x0a, 0x45,
-       0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
-       0x83, 0x59, 0x05, 0xe6,
-       0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
-       0x02, 0xfa, 0x03, 0xfa,
-       0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
-       0x9e, 0x00, 0xa8, 0x00,
-       0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
-       0x7a, 0x01, 0xc0, 0x01,
-       0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
-       0x69, 0x08, 0xba, 0x08,
-       0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
-       0xf1, 0x10, 0x06, 0x12,
-       0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
-       0x8a, 0x15, 0xc6, 0x17,
-       0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
-       0x0e, 0x47, 0x48, 0x47,
-       0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
-       0x14, 0x56, 0x77, 0x57,
-       0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
-       0xf0, 0x29, 0x02, 0xfe,
-       0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
-       0xfe, 0x80, 0x01, 0xff,
-       0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
-       0x00, 0xfe, 0x57, 0x24,
-       0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
-       0x00, 0x00, 0xff, 0x08,
-       0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
-       0xff, 0xff, 0xff, 0x0f,
-       0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
-       0xfe, 0x04, 0xf7, 0xcf,
-       0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
-       0x0b, 0x3c, 0x2a, 0xfe,
-       0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
-       0xfe, 0xf0, 0x01, 0xfe,
-       0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
-       0x02, 0xfe, 0xd4, 0x0c,
-       0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
-       0x1c, 0x05, 0xfe, 0xa6,
-       0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
-       0xf0, 0xfe, 0x86, 0x02,
-       0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
-       0xfe, 0x46, 0xf0, 0xfe,
-       0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
-       0x44, 0x02, 0xfe, 0x44,
-       0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
-       0xa0, 0x17, 0x06, 0x18,
-       0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
-       0x1e, 0x1c, 0xfe, 0xe9,
-       0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
-       0x0a, 0x6b, 0x01, 0x9e,
-       0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
-       0x01, 0x82, 0xfe, 0xbd,
-       0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
-       0x58, 0x1c, 0x17, 0x06,
-       0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
-       0xfe, 0x94, 0x02, 0xfe,
-       0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
-       0x01, 0xfe, 0x54, 0x0f,
-       0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
-       0x69, 0x10, 0x17, 0x06,
-       0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
-       0xf6, 0xc7, 0x01, 0xfe,
-       0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
-       0x02, 0x29, 0x0a, 0x40,
-       0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
-       0x58, 0x0a, 0x99, 0x01,
-       0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
-       0x2a, 0x46, 0xfe, 0x02,
-       0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
-       0x01, 0xfe, 0x07, 0x4b,
-       0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
-       0xfe, 0x56, 0x03, 0xfe,
-       0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
-       0xfe, 0x9f, 0xf0, 0xfe,
-       0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
-       0x1c, 0xeb, 0x09, 0x04,
-       0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
-       0x01, 0x0e, 0xac, 0x75,
-       0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
-       0xfe, 0x82, 0xf0, 0xfe,
-       0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
-       0x32, 0x1f, 0xfe, 0xb4,
-       0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
-       0x0a, 0xf0, 0xfe, 0x7a,
-       0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
-       0x01, 0x33, 0x8f, 0xfe,
-       0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
-       0xf7, 0xfe, 0x48, 0x1c,
-       0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
-       0x0a, 0xca, 0x01, 0x0e,
-       0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
-       0x2c, 0x01, 0x33, 0x8f,
-       0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
-       0xfe, 0x3c, 0x04, 0x1f,
-       0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
-       0x12, 0x2b, 0xff, 0x02,
-       0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
-       0x22, 0x30, 0x2e, 0xd5,
-       0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
-       0xfe, 0x4c, 0x54, 0x64,
-       0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
-       0xfe, 0x2a, 0x13, 0x2f,
-       0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
-       0xd3, 0xfa, 0xef, 0x86,
-       0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
-       0x1d, 0xfe, 0x1c, 0x12,
-       0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
-       0x70, 0x0c, 0x02, 0x22,
-       0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
-       0x01, 0x33, 0x02, 0x29,
-       0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
-       0x80, 0xfe, 0x31, 0xe4,
-       0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
-       0xfe, 0x70, 0x12, 0x49,
-       0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
-       0x80, 0x05, 0xfe, 0x31,
-       0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
-       0x28, 0xfe, 0x42, 0x12,
-       0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
-       0x11, 0xfe, 0xe3, 0x00,
-       0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
-       0x64, 0x05, 0x83, 0x24,
-       0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
-       0x09, 0x48, 0x01, 0x08,
-       0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
-       0x86, 0x24, 0x06, 0x12,
-       0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
-       0x01, 0xa7, 0x14, 0x92,
-       0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
-       0x02, 0x22, 0x05, 0xfe,
-       0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
-       0x47, 0x01, 0xa7, 0x26,
-       0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
-       0x01, 0xfe, 0xaa, 0x14,
-       0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
-       0x05, 0x50, 0xb4, 0x0c,
-       0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
-       0x13, 0x01, 0xfe, 0x14,
-       0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
-       0xff, 0x02, 0x00, 0x57,
-       0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
-       0x72, 0x06, 0x49, 0x04,
-       0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
-       0x06, 0x11, 0x9a, 0x01,
-       0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
-       0x01, 0xa7, 0xec, 0x72,
-       0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
-       0xfe, 0x0a, 0xf0, 0xfe,
-       0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
-       0x8d, 0x81, 0x02, 0x22,
-       0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
-       0x01, 0x08, 0x15, 0x00,
-       0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
-       0x00, 0x02, 0xfe, 0x32,
-       0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
-       0xfe, 0x1b, 0x00, 0x01,
-       0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
-       0x08, 0x15, 0x06, 0x01,
-       0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
-       0x9a, 0x81, 0x4b, 0x1d,
-       0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
-       0x45, 0xfe, 0x32, 0x12,
-       0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
-       0xfe, 0x32, 0x07, 0x8d,
-       0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
-       0x06, 0x15, 0x19, 0x02,
-       0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
-       0x90, 0x77, 0xfe, 0xca,
-       0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
-       0x10, 0xfe, 0x0e, 0x12,
-       0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
-       0x83, 0xe7, 0xc4, 0xa1,
-       0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
-       0x40, 0x12, 0x58, 0x01,
-       0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
-       0x51, 0x83, 0xfb, 0xfe,
-       0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
-       0xfe, 0x40, 0x50, 0xfe,
-       0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
-       0xfe, 0x2a, 0x12, 0xfe,
-       0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
-       0x85, 0x01, 0xa8, 0xfe,
-       0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
-       0x18, 0x57, 0xfb, 0xfe,
-       0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
-       0x0c, 0x39, 0x18, 0x3a,
-       0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
-       0x11, 0x65, 0xfe, 0x48,
-       0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
-       0xdd, 0xb8, 0xfe, 0x80,
-       0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
-       0xfe, 0x7a, 0x08, 0x8d,
-       0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
-       0x10, 0x61, 0x04, 0x06,
-       0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
-       0x12, 0xfe, 0x2e, 0x1c,
-       0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
-       0x52, 0x12, 0xfe, 0x2c,
-       0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
-       0x08, 0xfe, 0x8a, 0x10,
-       0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
-       0x24, 0x0a, 0xab, 0xfe,
-       0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
-       0x1c, 0x12, 0xb5, 0xfe,
-       0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
-       0x1c, 0x06, 0x16, 0x9d,
-       0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
-       0x14, 0x92, 0x01, 0x33,
-       0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
-       0xfe, 0x74, 0x18, 0x1c,
-       0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
-       0x01, 0xe6, 0x1e, 0x27,
-       0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
-       0x09, 0x04, 0x6a, 0xfe,
-       0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
-       0xfe, 0x83, 0x80, 0xfe,
-       0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
-       0x27, 0xfe, 0x40, 0x59,
-       0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
-       0x7c, 0xbe, 0x54, 0xbf,
-       0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
-       0x79, 0x56, 0x68, 0x57,
-       0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
-       0xa2, 0x23, 0x0c, 0x7b,
-       0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
-       0x16, 0xd7, 0x79, 0x39,
-       0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
-       0xfe, 0x10, 0x58, 0xfe,
-       0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
-       0x19, 0x16, 0xd7, 0x09,
-       0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
-       0xfe, 0x10, 0x90, 0xfe,
-       0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
-       0x11, 0x9b, 0x09, 0x04,
-       0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
-       0xfe, 0x0c, 0x58, 0xfe,
-       0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
-       0x0b, 0xfe, 0x1a, 0x12,
-       0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
-       0x14, 0x7a, 0x01, 0x33,
-       0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
-       0xfe, 0xed, 0x19, 0xbf,
-       0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
-       0x34, 0xfe, 0x74, 0x10,
-       0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
-       0x84, 0x05, 0xcb, 0x1c,
-       0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
-       0xf0, 0xfe, 0xc4, 0x0a,
-       0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
-       0xce, 0xf0, 0xfe, 0xca,
-       0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
-       0x22, 0x00, 0x02, 0x5a,
-       0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
-       0xfe, 0xd0, 0xf0, 0xfe,
-       0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
-       0x4c, 0xfe, 0x10, 0x10,
-       0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
-       0x2a, 0x13, 0xfe, 0x4e,
-       0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
-       0x16, 0x32, 0x2a, 0x73,
-       0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
-       0x32, 0x8c, 0xfe, 0x48,
-       0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
-       0xdb, 0x10, 0x11, 0xfe,
-       0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
-       0x22, 0x30, 0x2e, 0xd8,
-       0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
-       0x45, 0x0f, 0xfe, 0x42,
-       0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
-       0x09, 0x04, 0x0b, 0xfe,
-       0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
-       0x00, 0x21, 0xfe, 0xa6,
-       0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
-       0xfe, 0xe2, 0x10, 0x01,
-       0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
-       0x01, 0x6f, 0x02, 0x29,
-       0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
-       0x01, 0x86, 0x3e, 0x0b,
-       0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
-       0x3e, 0x0b, 0x0f, 0xfe,
-       0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
-       0xe8, 0x59, 0x11, 0x2d,
-       0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
-       0x04, 0x0b, 0x84, 0x3e,
-       0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
-       0x09, 0x04, 0x1b, 0xfe,
-       0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
-       0x1c, 0x1c, 0xfe, 0x9d,
-       0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
-       0xfe, 0x15, 0x00, 0xfe,
-       0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
-       0x0f, 0xfe, 0x47, 0x00,
-       0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
-       0xab, 0x70, 0x05, 0x6b,
-       0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
-       0x1c, 0x42, 0x59, 0x01,
-       0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
-       0x00, 0x37, 0x97, 0x01,
-       0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
-       0x1d, 0xfe, 0xce, 0x45,
-       0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
-       0x57, 0x05, 0x51, 0xfe,
-       0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
-       0x46, 0x09, 0x04, 0x1d,
-       0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
-       0x99, 0x01, 0x0e, 0xfe,
-       0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
-       0xfe, 0xee, 0x14, 0xee,
-       0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
-       0x13, 0x02, 0x29, 0x1e,
-       0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
-       0xce, 0x1e, 0x2d, 0x47,
-       0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
-       0x12, 0x4d, 0x01, 0xfe,
-       0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
-       0xf0, 0x0d, 0xfe, 0x02,
-       0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
-       0xf6, 0xfe, 0x34, 0x01,
-       0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
-       0xaf, 0xfe, 0x02, 0xea,
-       0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
-       0x05, 0xfe, 0x38, 0x01,
-       0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
-       0x0c, 0xfe, 0x62, 0x01,
-       0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
-       0x03, 0x23, 0x03, 0x1e,
-       0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
-       0x71, 0x13, 0xfe, 0x24,
-       0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
-       0xdc, 0xfe, 0x73, 0x57,
-       0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
-       0x80, 0x5d, 0x03, 0xfe,
-       0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
-       0x75, 0x03, 0x09, 0x04,
-       0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
-       0xfe, 0x1e, 0x80, 0xe1,
-       0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
-       0x90, 0xa3, 0xfe, 0x3c,
-       0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
-       0x16, 0x2f, 0x07, 0x2d,
-       0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
-       0xe8, 0x11, 0xfe, 0xe9,
-       0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
-       0x1e, 0x1c, 0xfe, 0x14,
-       0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
-       0x09, 0x04, 0x4f, 0xfe,
-       0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
-       0x40, 0x12, 0x20, 0x63,
-       0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
-       0x1c, 0x05, 0xfe, 0xac,
-       0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
-       0xfe, 0xb0, 0x00, 0xfe,
-       0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
-       0x24, 0x69, 0x12, 0xc9,
-       0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
-       0x90, 0x4d, 0xfe, 0x91,
-       0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
-       0xfe, 0x90, 0x4d, 0xfe,
-       0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
-       0x46, 0x1e, 0x20, 0xed,
-       0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
-       0x70, 0xfe, 0x14, 0x1c,
-       0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
-       0xfe, 0x07, 0xe6, 0x1d,
-       0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
-       0xfa, 0xef, 0xfe, 0x42,
-       0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
-       0xfe, 0x36, 0x12, 0xf0,
-       0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
-       0x3d, 0x75, 0x07, 0x10,
-       0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
-       0x10, 0x07, 0x7e, 0x45,
-       0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
-       0xfe, 0x01, 0xec, 0x97,
-       0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
-       0x27, 0x01, 0xda, 0xfe,
-       0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
-       0xfe, 0x48, 0x12, 0x07,
-       0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
-       0xfe, 0x3e, 0x11, 0x07,
-       0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
-       0x11, 0x07, 0x19, 0xfe,
-       0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
-       0x01, 0x08, 0x8c, 0x43,
-       0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
-       0x7e, 0x02, 0x29, 0x2b,
-       0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
-       0xfc, 0x10, 0x09, 0x04,
-       0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
-       0xc6, 0x10, 0x1e, 0x58,
-       0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
-       0x54, 0x18, 0x55, 0x23,
-       0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
-       0xa5, 0xc0, 0x38, 0xc1,
-       0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
-       0x05, 0xfa, 0x4e, 0xfe,
-       0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
-       0x0c, 0x56, 0x18, 0x57,
-       0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
-       0x00, 0x56, 0xfe, 0xa1,
-       0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
-       0x58, 0xfe, 0x1f, 0x40,
-       0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
-       0x31, 0x57, 0xfe, 0x44,
-       0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
-       0x8a, 0x50, 0x05, 0x39,
-       0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
-       0x12, 0xcd, 0x02, 0x5b,
-       0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
-       0x2f, 0x07, 0x9b, 0x21,
-       0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
-       0x39, 0x68, 0x3a, 0xfe,
-       0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
-       0x51, 0xfe, 0x8e, 0x51,
-       0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
-       0x01, 0x08, 0x25, 0x32,
-       0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
-       0x3b, 0x02, 0x44, 0x01,
-       0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
-       0x01, 0x08, 0x1f, 0xa2,
-       0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
-       0x00, 0x28, 0x84, 0x49,
-       0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
-       0x78, 0x3d, 0xfe, 0xda,
-       0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
-       0x05, 0xc6, 0x28, 0x84,
-       0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
-       0x14, 0xfe, 0x03, 0x17,
-       0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
-       0xfe, 0xaa, 0x14, 0x02,
-       0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
-       0x21, 0x44, 0x01, 0xfe,
-       0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
-       0xfe, 0x4a, 0xf4, 0x0b,
-       0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
-       0x85, 0x02, 0x5b, 0x05,
-       0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
-       0xd8, 0x14, 0x02, 0x5c,
-       0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
-       0x01, 0x08, 0x23, 0x72,
-       0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
-       0x12, 0x5e, 0x2b, 0x01,
-       0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
-       0x1c, 0xfe, 0xff, 0x7f,
-       0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
-       0x57, 0x48, 0x8b, 0x1c,
-       0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
-       0x00, 0x57, 0x48, 0x8b,
-       0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
-       0x03, 0x0a, 0x50, 0x01,
-       0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
-       0x54, 0xfe, 0x00, 0xf4,
-       0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
-       0x03, 0x7c, 0x63, 0x27,
-       0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
-       0xfe, 0x82, 0x4a, 0xfe,
-       0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
-       0x42, 0x48, 0x5f, 0x60,
-       0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
-       0x1f, 0xfe, 0xa2, 0x14,
-       0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
-       0xcc, 0x12, 0x49, 0x04,
-       0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
-       0xe8, 0x13, 0x3b, 0x13,
-       0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
-       0xa1, 0xff, 0x02, 0x83,
-       0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
-       0x13, 0x06, 0xfe, 0x56,
-       0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
-       0x64, 0x00, 0x17, 0x93,
-       0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
-       0xc8, 0x00, 0x8e, 0xe4,
-       0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
-       0x01, 0xba, 0xfe, 0x4e,
-       0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
-       0xfe, 0x60, 0x14, 0xfe,
-       0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
-       0xfe, 0x22, 0x13, 0x1c,
-       0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
-       0xfe, 0x9c, 0x14, 0xb7,
-       0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
-       0xfe, 0x9c, 0x14, 0xb7,
-       0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
-       0xfe, 0xb4, 0x56, 0xfe,
-       0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
-       0xe5, 0x15, 0x0b, 0x01,
-       0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
-       0x49, 0x01, 0x08, 0x03,
-       0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
-       0x15, 0x06, 0x01, 0x08,
-       0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
-       0x4a, 0x01, 0x08, 0x03,
-       0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
-       0xfe, 0x49, 0xf4, 0x00,
-       0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
-       0x08, 0x2f, 0x07, 0xfe,
-       0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
-       0x01, 0x43, 0x1e, 0xcd,
-       0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
-       0xed, 0x88, 0x07, 0x10,
-       0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
-       0x80, 0x01, 0x0e, 0x88,
-       0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
-       0x88, 0x03, 0x0a, 0x42,
-       0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
-       0xfe, 0x80, 0x80, 0xf2,
-       0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
-       0x01, 0x82, 0x03, 0x17,
-       0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
-       0xfe, 0x24, 0x1c, 0xfe,
-       0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
-       0x91, 0x1d, 0x66, 0xfe,
-       0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
-       0xda, 0x10, 0x17, 0x10,
-       0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
-       0x05, 0xfe, 0x66, 0x01,
-       0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
-       0xfe, 0x3c, 0x50, 0x66,
-       0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
-       0x40, 0x16, 0xfe, 0xb6,
-       0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
-       0x10, 0x71, 0xfe, 0x83,
-       0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
-       0xfe, 0x62, 0x16, 0xfe,
-       0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
-       0xfe, 0x98, 0xe7, 0x00,
-       0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
-       0xfe, 0x30, 0xbc, 0xfe,
-       0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
-       0xc5, 0x90, 0xfe, 0x9a,
-       0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
-       0x42, 0x10, 0xfe, 0x02,
-       0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
-       0xfe, 0x1d, 0xf7, 0x4f,
-       0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
-       0x47, 0xfe, 0x83, 0x58,
-       0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
-       0xfe, 0xdd, 0x00, 0x63,
-       0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
-       0x06, 0x37, 0x95, 0xa9,
-       0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
-       0x18, 0x1c, 0x1a, 0x5d,
-       0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
-       0xe1, 0x10, 0x78, 0x2c,
-       0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
-       0x13, 0x3c, 0x8a, 0x0a,
-       0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
-       0xe3, 0xfe, 0x00, 0xcc,
-       0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
-       0x0e, 0xf2, 0x01, 0x6f,
-       0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
-       0xf6, 0xfe, 0xd6, 0xf0,
-       0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
-       0x15, 0x00, 0x59, 0x76,
-       0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
-       0x11, 0x2d, 0x01, 0x6f,
-       0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
-       0xc8, 0xfe, 0x48, 0x55,
-       0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
-       0x99, 0x01, 0x0e, 0xf0,
-       0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
-       0x75, 0x03, 0x0a, 0x42,
-       0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
-       0x0e, 0x73, 0x75, 0x03,
-       0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
-       0xfe, 0x3a, 0x45, 0x5b,
-       0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
-       0xfe, 0x02, 0xe6, 0x1b,
-       0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
-       0xfe, 0x94, 0x00, 0xfe,
-       0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
-       0xe6, 0x2c, 0xfe, 0x4e,
-       0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
-       0x03, 0x07, 0x7a, 0xfe,
-       0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
-       0x07, 0x1b, 0xfe, 0x5a,
-       0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
-       0x24, 0x2c, 0xdc, 0x07,
-       0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
-       0x9f, 0xad, 0x03, 0x14,
-       0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
-       0x03, 0x25, 0xfe, 0xca,
-       0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
-       0x00, 0x00,
-};
+                       scsi_busy = AscReadLramByte(iop_base,
+                                                   (ushort)ASCV_SCSIBUSY_B);
+                       scsi_busy |= target_id;
+                       AscWriteLramByte(iop_base,
+                                        (ushort)ASCV_SCSIBUSY_B, scsi_busy);
+                       asc_dvc->queue_full_or_busy |= target_id;
 
-static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf);    /* 0x13AD */
-static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL;    /* Expanded little-endian checksum. */
+                       if (scsi_status == SAM_STAT_TASK_SET_FULL) {
+                               if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
+                                       cur_dvc_qng -= 1;
+                                       asc_dvc->max_dvc_qng[tid_no] =
+                                           cur_dvc_qng;
 
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc38C0800_buf[] = {
-       0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
-       0x01, 0x00, 0x48, 0xe4,
-       0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
-       0x1c, 0x0f, 0x00, 0xf6,
-       0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
-       0x09, 0xe7, 0x55, 0xf0,
-       0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
-       0x18, 0xf4, 0x08, 0x00,
-       0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
-       0x86, 0xf0, 0xb1, 0xf0,
-       0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
-       0x3c, 0x00, 0xbb, 0x00,
-       0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
-       0xba, 0x13, 0x18, 0x40,
-       0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
-       0x6e, 0x01, 0x74, 0x01,
-       0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
-       0xc0, 0x00, 0x01, 0x01,
-       0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
-       0x08, 0x12, 0x02, 0x4a,
-       0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
-       0x5d, 0xf0, 0x02, 0xfa,
-       0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
-       0x68, 0x01, 0x6a, 0x01,
-       0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
-       0x06, 0x13, 0x4c, 0x1c,
-       0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
-       0x0f, 0x00, 0x47, 0x00,
-       0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
-       0x4e, 0x1c, 0x10, 0x44,
-       0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
-       0x05, 0x00, 0x34, 0x00,
-       0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
-       0x42, 0x0c, 0x12, 0x0f,
-       0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
-       0x00, 0x4e, 0x42, 0x54,
-       0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
-       0x59, 0xf0, 0xb8, 0xf0,
-       0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
-       0x19, 0x00, 0x33, 0x00,
-       0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
-       0xe7, 0x00, 0xe2, 0x03,
-       0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
-       0x12, 0x13, 0x24, 0x14,
-       0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
-       0x36, 0x1c, 0x08, 0x44,
-       0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
-       0x3a, 0x55, 0x83, 0x55,
-       0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
-       0x0c, 0xf0, 0x04, 0xf8,
-       0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
-       0xa8, 0x00, 0xaa, 0x00,
-       0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
-       0xc4, 0x01, 0xc6, 0x01,
-       0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
-       0x68, 0x08, 0x69, 0x08,
-       0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
-       0xed, 0x10, 0xf1, 0x10,
-       0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
-       0x1e, 0x13, 0x46, 0x14,
-       0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
-       0xca, 0x18, 0xe6, 0x19,
-       0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
-       0xf0, 0x2b, 0x02, 0xfe,
-       0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
-       0xfe, 0x84, 0x01, 0xff,
-       0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
-       0x00, 0xfe, 0x57, 0x24,
-       0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
-       0x00, 0x00, 0xff, 0x08,
-       0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
-       0xff, 0xff, 0xff, 0x11,
-       0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
-       0xfe, 0x04, 0xf7, 0xd6,
-       0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
-       0x0a, 0x42, 0x2c, 0xfe,
-       0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
-       0xfe, 0xf4, 0x01, 0xfe,
-       0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
-       0x02, 0xfe, 0xc8, 0x0d,
-       0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
-       0x1c, 0x03, 0xfe, 0xa6,
-       0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
-       0xf0, 0xfe, 0x8a, 0x02,
-       0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
-       0xfe, 0x46, 0xf0, 0xfe,
-       0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
-       0x48, 0x02, 0xfe, 0x44,
-       0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
-       0xaa, 0x18, 0x06, 0x14,
-       0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
-       0x1e, 0x1c, 0xfe, 0xe9,
-       0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
-       0x09, 0x70, 0x01, 0xa8,
-       0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
-       0x01, 0x87, 0xfe, 0xbd,
-       0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
-       0x58, 0x1c, 0x18, 0x06,
-       0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
-       0xfe, 0x98, 0x02, 0xfe,
-       0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
-       0x01, 0xfe, 0x48, 0x10,
-       0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
-       0x69, 0x10, 0x18, 0x06,
-       0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
-       0xf6, 0xce, 0x01, 0xfe,
-       0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
-       0x82, 0x16, 0x02, 0x2b,
-       0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
-       0xfe, 0x41, 0x58, 0x09,
-       0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
-       0x82, 0x16, 0x02, 0x2b,
-       0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
-       0xfe, 0x77, 0x57, 0xfe,
-       0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
-       0xfe, 0x40, 0x1c, 0x1c,
-       0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
-       0x03, 0xfe, 0x11, 0xf0,
-       0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
-       0xfe, 0x11, 0x00, 0x02,
-       0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
-       0x21, 0x22, 0xa3, 0xb7,
-       0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
-       0x12, 0xd1, 0x1c, 0xd9,
-       0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
-       0xfe, 0xe4, 0x00, 0x27,
-       0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
-       0x06, 0xf0, 0xfe, 0xc8,
-       0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
-       0x70, 0x28, 0x17, 0xfe,
-       0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
-       0xf9, 0x2c, 0x99, 0x19,
-       0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
-       0x74, 0x01, 0xaf, 0x8c,
-       0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
-       0x8d, 0x51, 0x64, 0x79,
-       0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
-       0xfe, 0x6a, 0x02, 0x02,
-       0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
-       0xfe, 0x3c, 0x04, 0x3b,
-       0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
-       0x00, 0x10, 0x01, 0x0b,
-       0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
-       0xfe, 0x4c, 0x44, 0xfe,
-       0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
-       0xda, 0x4f, 0x79, 0x2a,
-       0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
-       0xfe, 0x2a, 0x13, 0x32,
-       0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
-       0x54, 0x6b, 0xda, 0xfe,
-       0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
-       0x08, 0x13, 0x32, 0x07,
-       0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
-       0x08, 0x05, 0x06, 0x4d,
-       0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
-       0x2d, 0x12, 0xfe, 0xe6,
-       0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
-       0x02, 0x2b, 0xfe, 0x42,
-       0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
-       0xfe, 0x87, 0x80, 0xfe,
-       0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
-       0x07, 0x19, 0xfe, 0x7c,
-       0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
-       0x17, 0xfe, 0x90, 0x05,
-       0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
-       0xa0, 0x00, 0x28, 0xfe,
-       0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
-       0x34, 0xfe, 0x89, 0x48,
-       0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
-       0x12, 0xfe, 0xe3, 0x00,
-       0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
-       0x70, 0x05, 0x88, 0x25,
-       0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
-       0x09, 0x48, 0xff, 0x02,
-       0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
-       0x08, 0x53, 0x05, 0xcb,
-       0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
-       0x05, 0x1b, 0xfe, 0x22,
-       0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
-       0x0d, 0x00, 0x01, 0x36,
-       0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
-       0x03, 0x5c, 0x28, 0xfe,
-       0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
-       0x05, 0x1f, 0xfe, 0x02,
-       0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
-       0x01, 0x4b, 0x12, 0xfe,
-       0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
-       0x12, 0x03, 0x45, 0x28,
-       0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
-       0x43, 0x48, 0xc4, 0xcc,
-       0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
-       0x6e, 0x41, 0x01, 0xb2,
-       0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
-       0xfe, 0xcc, 0x15, 0x1d,
-       0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
-       0x45, 0xc1, 0x0c, 0x45,
-       0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
-       0xe2, 0x00, 0x27, 0xdb,
-       0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
-       0xfe, 0x06, 0xf0, 0xfe,
-       0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
-       0x16, 0x19, 0x01, 0x0b,
-       0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
-       0xfe, 0x99, 0xa4, 0x01,
-       0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
-       0x12, 0x08, 0x05, 0x1a,
-       0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
-       0x0b, 0x16, 0x00, 0x01,
-       0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
-       0xe2, 0x6c, 0x58, 0xbe,
-       0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
-       0xfe, 0x09, 0x6f, 0xba,
-       0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
-       0xfe, 0x54, 0x07, 0x1c,
-       0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
-       0x07, 0x02, 0x24, 0x01,
-       0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
-       0x2c, 0x90, 0xfe, 0xae,
-       0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
-       0x37, 0x22, 0x20, 0x07,
-       0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
-       0xfe, 0x06, 0x10, 0xfe,
-       0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
-       0x37, 0x01, 0xb3, 0xb8,
-       0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
-       0x50, 0xfe, 0x44, 0x51,
-       0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
-       0x14, 0x5f, 0xfe, 0x0c,
-       0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
-       0x14, 0x3e, 0xfe, 0x4a,
-       0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
-       0x90, 0x0c, 0x60, 0x14,
-       0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
-       0xfe, 0x44, 0x90, 0xfe,
-       0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
-       0x0c, 0x5e, 0x14, 0x5f,
-       0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
-       0x14, 0x3c, 0x21, 0x0c,
-       0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
-       0x27, 0xdd, 0xfe, 0x9e,
-       0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
-       0x9a, 0x08, 0xc6, 0xfe,
-       0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
-       0x95, 0x86, 0x02, 0x24,
-       0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
-       0x06, 0xfe, 0x10, 0x12,
-       0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
-       0x1c, 0x02, 0xfe, 0x18,
-       0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
-       0x2c, 0x1c, 0xfe, 0xaa,
-       0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
-       0xde, 0x09, 0xfe, 0xb7,
-       0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
-       0xfe, 0xf1, 0x18, 0xfe,
-       0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
-       0x14, 0x59, 0xfe, 0x95,
-       0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
-       0xfe, 0xf0, 0x08, 0xb5,
-       0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
-       0x0b, 0xb6, 0xfe, 0xbf,
-       0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
-       0x12, 0xc2, 0xfe, 0xd2,
-       0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
-       0x06, 0x17, 0x85, 0xc5,
-       0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
-       0x9d, 0x01, 0x36, 0x10,
-       0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
-       0x98, 0x80, 0xfe, 0x19,
-       0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
-       0xfe, 0x44, 0x54, 0xbe,
-       0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
-       0x02, 0x4a, 0x08, 0x05,
-       0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
-       0x9c, 0x3c, 0xfe, 0x6c,
-       0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
-       0x3b, 0x40, 0x03, 0x49,
-       0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
-       0x8f, 0xfe, 0xe3, 0x54,
-       0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
-       0xda, 0x09, 0xfe, 0x8b,
-       0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
-       0x0a, 0x3a, 0x49, 0x3b,
-       0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
-       0xad, 0xfe, 0x01, 0x59,
-       0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
-       0x49, 0x8f, 0xfe, 0xe3,
-       0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
-       0x4a, 0x3a, 0x49, 0x3b,
-       0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
-       0x02, 0x4a, 0x08, 0x05,
-       0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
-       0xb7, 0xfe, 0x03, 0xa1,
-       0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
-       0xfe, 0x86, 0x91, 0x6a,
-       0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
-       0x61, 0x0c, 0x7f, 0x14,
-       0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
-       0x9b, 0x2e, 0x9c, 0x3c,
-       0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
-       0xfa, 0x3c, 0x01, 0xef,
-       0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
-       0xe4, 0x08, 0x05, 0x1f,
-       0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
-       0x03, 0x5e, 0x29, 0x5f,
-       0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
-       0xf4, 0x09, 0x08, 0x05,
-       0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
-       0x81, 0x50, 0xfe, 0x10,
-       0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
-       0x08, 0x09, 0x12, 0xa6,
-       0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
-       0x08, 0x09, 0xfe, 0x0c,
-       0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
-       0x08, 0x05, 0x0a, 0xfe,
-       0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
-       0xf0, 0xe2, 0x15, 0x7e,
-       0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
-       0x57, 0x3d, 0xfe, 0xed,
-       0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
-       0x00, 0xff, 0x35, 0xfe,
-       0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
-       0x1e, 0x19, 0x8a, 0x03,
-       0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
-       0xfe, 0xd1, 0xf0, 0xfe,
-       0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
-       0x10, 0xfe, 0xce, 0xf0,
-       0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
-       0x10, 0xfe, 0x22, 0x00,
-       0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
-       0x02, 0x65, 0xfe, 0xd0,
-       0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
-       0x0b, 0x10, 0x58, 0xfe,
-       0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
-       0x12, 0x00, 0x2c, 0x0f,
-       0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
-       0x0c, 0xbc, 0x17, 0x34,
-       0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
-       0x0c, 0x1c, 0x34, 0x94,
-       0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
-       0x4b, 0xfe, 0xdb, 0x10,
-       0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
-       0x89, 0xf0, 0x24, 0x33,
-       0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
-       0x33, 0x31, 0xdf, 0xbc,
-       0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
-       0x17, 0xfe, 0x2c, 0x0d,
-       0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
-       0x12, 0x55, 0xfe, 0x28,
-       0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
-       0x44, 0xfe, 0x28, 0x00,
-       0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
-       0x0f, 0x64, 0x12, 0x2f,
-       0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
-       0x0a, 0xfe, 0xb4, 0x10,
-       0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
-       0xfe, 0x34, 0x46, 0xac,
-       0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
-       0x37, 0x01, 0xf5, 0x01,
-       0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
-       0xfe, 0x2e, 0x03, 0x08,
-       0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
-       0x1a, 0xfe, 0x58, 0x12,
-       0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
-       0xfe, 0x50, 0x0d, 0xfe,
-       0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
-       0xfe, 0xa9, 0x10, 0x10,
-       0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
-       0xfe, 0x13, 0x00, 0xfe,
-       0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
-       0x24, 0x00, 0x8c, 0xb5,
-       0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
-       0xfe, 0x9d, 0x41, 0xfe,
-       0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
-       0xb4, 0x15, 0xfe, 0x31,
-       0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
-       0xec, 0xd0, 0xfc, 0x44,
-       0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
-       0x4b, 0x91, 0xfe, 0x75,
-       0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
-       0x0e, 0xfe, 0x44, 0x48,
-       0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
-       0xfe, 0x41, 0x58, 0x09,
-       0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
-       0x2e, 0x03, 0x09, 0x5d,
-       0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
-       0xce, 0x47, 0xfe, 0xad,
-       0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
-       0x59, 0x13, 0x9f, 0x13,
-       0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
-       0xe0, 0x0e, 0x0f, 0x06,
-       0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
-       0x3a, 0x01, 0x56, 0xfe,
-       0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
-       0x20, 0x4f, 0xfe, 0x05,
-       0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
-       0x48, 0xf4, 0x0d, 0xfe,
-       0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
-       0x15, 0x1a, 0x39, 0xa0,
-       0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
-       0x0c, 0xfe, 0x60, 0x01,
-       0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
-       0x06, 0x13, 0x2f, 0x12,
-       0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
-       0x22, 0x9f, 0xb7, 0x13,
-       0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
-       0xa0, 0xb4, 0xfe, 0xd9,
-       0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
-       0xc3, 0xfe, 0x03, 0xdc,
-       0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
-       0xfe, 0x00, 0xcc, 0x04,
-       0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
-       0xfe, 0x1c, 0x80, 0x07,
-       0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
-       0xfe, 0x0c, 0x90, 0xfe,
-       0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
-       0x0a, 0xfe, 0x3c, 0x50,
-       0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
-       0x16, 0x08, 0x05, 0x1b,
-       0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
-       0xfe, 0x2c, 0x13, 0x01,
-       0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
-       0x0c, 0xfe, 0x64, 0x01,
-       0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
-       0x80, 0x8d, 0xfe, 0x01,
-       0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
-       0x22, 0x20, 0xfb, 0x79,
-       0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
-       0x03, 0xfe, 0xae, 0x00,
+                                       AscWriteLramByte(iop_base,
+                                                        (ushort)((ushort)
+                                                                 ASCV_MAX_DVC_QNG_BEG
+                                                                 + (ushort)
+                                                                 tid_no),
+                                                        cur_dvc_qng);
+
+                                       /*
+                                        * Set the device queue depth to the
+                                        * number of active requests when the
+                                        * QUEUE FULL condition was encountered.
+                                        */
+                                       boardp->queue_full |= target_id;
+                                       boardp->queue_full_cnt[tid_no] =
+                                           cur_dvc_qng;
+                               }
+                       }
+               }
+               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+               return (0);
+       }
+#if CC_VERY_LONG_SG_LIST
+       else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
+               uchar q_no;
+               ushort q_addr;
+               uchar sg_wk_q_no;
+               uchar first_sg_wk_q_no;
+               ASC_SCSI_Q *scsiq;      /* Ptr to driver request. */
+               ASC_SG_HEAD *sg_head;   /* Ptr to driver SG request. */
+               ASC_SG_LIST_Q scsi_sg_q;        /* Structure written to queue. */
+               ushort sg_list_dwords;
+               ushort sg_entry_cnt;
+               uchar next_qp;
+               int i;
 
-       0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
-       0xb2, 0x00, 0xfe, 0x09,
-       0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
-       0x45, 0x0f, 0x46, 0x52,
-       0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
-       0x0f, 0x44, 0x11, 0x0f,
-       0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
-       0x25, 0x11, 0x13, 0x20,
-       0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
-       0x56, 0xfe, 0xd6, 0xf0,
-       0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
-       0x18, 0x1c, 0x04, 0x42,
-       0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
-       0xf5, 0x13, 0x04, 0x01,
-       0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
-       0x13, 0x32, 0x07, 0x2f,
-       0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
-       0x41, 0x48, 0xfe, 0x45,
-       0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
-       0x07, 0x11, 0xac, 0x09,
-       0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
-       0x82, 0x4e, 0xfe, 0x14,
-       0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
-       0xfe, 0x01, 0xec, 0xa2,
-       0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
-       0x2a, 0x01, 0xe3, 0xfe,
-       0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
-       0xfe, 0x48, 0x12, 0x07,
-       0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
-       0xfe, 0x32, 0x12, 0x07,
-       0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
-       0x1f, 0xfe, 0x12, 0x12,
-       0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
-       0x94, 0x4b, 0x04, 0x2d,
-       0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
-       0x32, 0x07, 0xa6, 0xfe,
-       0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
-       0x5a, 0xfe, 0x72, 0x12,
-       0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
-       0xfe, 0x26, 0x13, 0x03,
-       0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
-       0x0c, 0x7f, 0x0c, 0x80,
-       0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
-       0x3c, 0xfe, 0x04, 0x55,
-       0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
-       0x91, 0x10, 0x03, 0x3f,
-       0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
-       0x88, 0x9b, 0x2e, 0x9c,
-       0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
-       0x56, 0x0c, 0x5e, 0x14,
-       0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
-       0x03, 0x60, 0x29, 0x61,
-       0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
-       0x50, 0xfe, 0xc6, 0x50,
-       0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
-       0x29, 0x3e, 0xfe, 0x40,
-       0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
-       0x2d, 0x01, 0x0b, 0x1d,
-       0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
-       0x72, 0x01, 0xaf, 0x1e,
-       0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
-       0x0a, 0x55, 0x35, 0xfe,
-       0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
-       0x02, 0x72, 0xfe, 0x19,
-       0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
-       0x1d, 0xe8, 0x33, 0x31,
-       0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
-       0x0b, 0x1c, 0x34, 0x1d,
-       0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
-       0x33, 0x31, 0xfe, 0xe8,
-       0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
-       0x05, 0x1f, 0x35, 0xa9,
-       0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
-       0x14, 0x01, 0xaf, 0x8c,
-       0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
-       0x03, 0x45, 0x28, 0x35,
-       0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
-       0x03, 0x5c, 0xc1, 0x0c,
-       0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
-       0x89, 0x01, 0x0b, 0x1c,
-       0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
-       0xfe, 0x42, 0x58, 0xf1,
-       0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
-       0xf4, 0x06, 0xea, 0x32,
-       0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
-       0x01, 0x0b, 0x26, 0x89,
-       0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
-       0x26, 0xfe, 0xd4, 0x13,
-       0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
-       0x13, 0x1c, 0xfe, 0xd0,
-       0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
-       0x0f, 0x71, 0xff, 0x02,
-       0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
-       0x00, 0x5c, 0x04, 0x0f,
-       0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
-       0xfe, 0x00, 0x5c, 0x04,
-       0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
-       0x02, 0x00, 0x57, 0x52,
-       0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
-       0x87, 0x04, 0xfe, 0x03,
-       0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
-       0xfe, 0x00, 0x7d, 0xfe,
-       0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
-       0x14, 0x5f, 0x57, 0x3f,
-       0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
-       0x5a, 0x8d, 0x04, 0x01,
-       0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
-       0xfe, 0x96, 0x15, 0x33,
-       0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
-       0x0a, 0xfe, 0xc1, 0x59,
-       0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
-       0x21, 0x69, 0x1a, 0xee,
-       0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
-       0x30, 0xfe, 0x78, 0x10,
-       0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
-       0x98, 0xfe, 0x30, 0x00,
-       0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
-       0x98, 0xfe, 0x64, 0x00,
-       0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
-       0x10, 0x69, 0x06, 0xfe,
-       0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
-       0x18, 0x59, 0x0f, 0x06,
-       0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
-       0x43, 0xf4, 0x9f, 0xfe,
-       0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
-       0x9e, 0xfe, 0xf3, 0x10,
-       0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
-       0x17, 0xfe, 0x4d, 0xe4,
-       0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
-       0x17, 0xfe, 0x4d, 0xe4,
-       0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
-       0xf4, 0x00, 0xe9, 0x91,
-       0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
-       0x04, 0x16, 0x06, 0x01,
-       0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
-       0x0b, 0x26, 0xf3, 0x76,
-       0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
-       0x16, 0x19, 0x01, 0x0b,
-       0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
-       0x0b, 0x26, 0xb1, 0x76,
-       0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
-       0xfe, 0x48, 0x13, 0xb8,
-       0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
-       0xec, 0xfe, 0x27, 0x01,
-       0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
-       0x07, 0xfe, 0xe3, 0x00,
-       0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
-       0x22, 0xd4, 0x07, 0x06,
-       0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
-       0x07, 0x11, 0xae, 0x09,
-       0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
-       0x0e, 0x8e, 0xfe, 0x80,
-       0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
-       0x09, 0x48, 0x01, 0x0e,
-       0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
-       0x80, 0xfe, 0x80, 0x4c,
-       0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
-       0x09, 0x5d, 0x01, 0x87,
-       0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
-       0x19, 0xde, 0xfe, 0x24,
-       0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
-       0x17, 0xad, 0x9a, 0x1b,
-       0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
-       0x16, 0xfe, 0xda, 0x10,
-       0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
-       0x18, 0x58, 0x03, 0xfe,
-       0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
-       0xf4, 0x06, 0xfe, 0x3c,
-       0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
-       0x97, 0xfe, 0x38, 0x17,
-       0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
-       0x10, 0x18, 0x11, 0x75,
-       0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
-       0x2e, 0x97, 0xfe, 0x5a,
-       0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
-       0xfe, 0x98, 0xe7, 0x00,
-       0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
-       0xfe, 0x30, 0xbc, 0xfe,
-       0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
-       0xcb, 0x97, 0xfe, 0x92,
-       0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
-       0x42, 0x10, 0xfe, 0x02,
-       0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
-       0x03, 0xa1, 0xfe, 0x1d,
-       0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
-       0x9a, 0x5b, 0x41, 0xfe,
-       0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
-       0x11, 0x12, 0xfe, 0xdd,
-       0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
-       0x17, 0x15, 0x06, 0x39,
-       0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
-       0xfe, 0x7e, 0x18, 0x1e,
-       0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
-       0x12, 0xfe, 0xe1, 0x10,
-       0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
-       0x13, 0x42, 0x92, 0x09,
-       0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
-       0xf0, 0xfe, 0x00, 0xcc,
-       0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
-       0x0e, 0xfe, 0x80, 0x4c,
-       0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
-       0x24, 0x12, 0xfe, 0x14,
-       0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
-       0xe7, 0x0a, 0x10, 0xfe,
-       0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
-       0x08, 0x54, 0x1b, 0x37,
-       0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
-       0x90, 0x3a, 0xce, 0x3b,
-       0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
-       0x13, 0xa3, 0x04, 0x09,
-       0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
-       0x44, 0x17, 0xfe, 0xe8,
-       0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
-       0x5d, 0x01, 0xa8, 0x09,
-       0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
-       0x1c, 0x19, 0x03, 0xfe,
-       0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
-       0x6b, 0xfe, 0x2e, 0x19,
-       0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
-       0xfe, 0x0b, 0x00, 0x6b,
-       0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
-       0x08, 0x10, 0x03, 0xfe,
-       0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
-       0x04, 0x68, 0x54, 0xe7,
-       0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
-       0x1a, 0xf4, 0xfe, 0x00,
-       0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
-       0x04, 0x07, 0x7e, 0xfe,
-       0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
-       0x07, 0x1a, 0xfe, 0x5a,
-       0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
-       0x25, 0x6d, 0xe5, 0x07,
-       0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
-       0xa9, 0xb8, 0x04, 0x15,
-       0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
-       0x40, 0x5c, 0x04, 0x1c,
-       0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
-       0xf7, 0xfe, 0x82, 0xf0,
-       0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
-};
+               q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
+               if (q_no == ASC_QLINK_END)
+                       return 0;
 
-static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf);      /* 0x14E1 */
-static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
+               q_addr = ASC_QNO_TO_QADDR(q_no);
 
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc38C1600_buf[] = {
-       0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
-       0x18, 0xe4, 0x01, 0x00,
-       0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
-       0x07, 0x17, 0xc0, 0x5f,
-       0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
-       0x85, 0xf0, 0x86, 0xf0,
-       0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
-       0x98, 0x57, 0x01, 0xe6,
-       0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
-       0x38, 0x54, 0x32, 0xf0,
-       0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
-       0x00, 0xe6, 0xb1, 0xf0,
-       0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
-       0x06, 0x13, 0x0c, 0x1c,
-       0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
-       0xb9, 0x54, 0x00, 0x80,
-       0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
-       0x03, 0xe6, 0x01, 0xea,
-       0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
-       0x04, 0x13, 0xbb, 0x55,
-       0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
-       0xbb, 0x00, 0xc0, 0x00,
-       0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
-       0x4c, 0x1c, 0x4e, 0x1c,
-       0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
-       0x24, 0x01, 0x3c, 0x01,
-       0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
-       0x78, 0x01, 0x7c, 0x01,
-       0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
-       0x6e, 0x1e, 0x02, 0x48,
-       0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
-       0x03, 0xfc, 0x06, 0x00,
-       0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
-       0x30, 0x1c, 0x38, 0x1c,
-       0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
-       0x5d, 0xf0, 0xa7, 0xf0,
-       0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
-       0x33, 0x00, 0x34, 0x00,
-       0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
-       0x79, 0x01, 0x3c, 0x09,
-       0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
-       0x40, 0x16, 0x50, 0x16,
-       0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
-       0x05, 0xf0, 0x09, 0xf0,
-       0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
-       0x9c, 0x00, 0xa4, 0x00,
-       0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
-       0xe9, 0x09, 0x5c, 0x0c,
-       0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
-       0x42, 0x1d, 0x08, 0x44,
-       0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
-       0x83, 0x55, 0x83, 0x59,
-       0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
-       0x4b, 0xf4, 0x04, 0xf8,
-       0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
-       0xa8, 0x00, 0xaa, 0x00,
-       0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
-       0x7a, 0x01, 0x82, 0x01,
-       0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
-       0x68, 0x08, 0x10, 0x0d,
-       0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
-       0xf3, 0x10, 0x06, 0x12,
-       0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
-       0xf0, 0x35, 0x05, 0xfe,
-       0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
-       0xfe, 0x88, 0x01, 0xff,
-       0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
-       0x00, 0xfe, 0x57, 0x24,
-       0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
-       0x00, 0x00, 0xff, 0x08,
-       0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
-       0xff, 0xff, 0xff, 0x13,
-       0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
-       0xfe, 0x04, 0xf7, 0xe8,
-       0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
-       0x0d, 0x51, 0x37, 0xfe,
-       0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
-       0xfe, 0xf8, 0x01, 0xfe,
-       0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
-       0x05, 0xfe, 0x08, 0x0f,
-       0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
-       0x28, 0x1c, 0x03, 0xfe,
-       0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
-       0x48, 0xf0, 0xfe, 0x90,
-       0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
-       0x02, 0xfe, 0x46, 0xf0,
-       0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
-       0xfe, 0x4e, 0x02, 0xfe,
-       0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
-       0x0d, 0xa2, 0x1c, 0x07,
-       0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
-       0x1c, 0xf5, 0xfe, 0x1e,
-       0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
-       0xde, 0x0a, 0x81, 0x01,
-       0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
-       0x81, 0x01, 0x5c, 0xfe,
-       0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
-       0xfe, 0x58, 0x1c, 0x1c,
-       0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
-       0x2b, 0xfe, 0x9e, 0x02,
-       0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
-       0x00, 0x47, 0xb8, 0x01,
-       0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
-       0x1a, 0x31, 0xfe, 0x69,
-       0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
-       0x1e, 0x1e, 0x20, 0x2c,
-       0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
-       0x44, 0x15, 0x56, 0x51,
-       0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
-       0x01, 0x18, 0x09, 0x00,
-       0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
-       0x18, 0xfe, 0xc8, 0x54,
-       0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
-       0xfe, 0x02, 0xe8, 0x30,
-       0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
-       0xfe, 0xe4, 0x01, 0xfe,
-       0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
-       0x26, 0xf0, 0xfe, 0x66,
-       0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
-       0xef, 0x10, 0xfe, 0x9f,
-       0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
-       0x70, 0x37, 0xfe, 0x48,
-       0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
-       0x21, 0xb9, 0xc7, 0x20,
-       0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
-       0xe1, 0x2a, 0xeb, 0xfe,
-       0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
-       0x15, 0xfe, 0xe4, 0x00,
-       0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
-       0xfe, 0x06, 0xf0, 0xfe,
-       0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
-       0x03, 0x81, 0x1e, 0x1b,
-       0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
-       0xea, 0xfe, 0x46, 0x1c,
-       0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
-       0xfe, 0x48, 0x1c, 0x75,
-       0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
-       0xe1, 0x01, 0x18, 0x77,
-       0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
-       0x8f, 0xfe, 0x70, 0x02,
-       0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
-       0x16, 0xfe, 0x4a, 0x04,
-       0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
-       0x02, 0x00, 0x10, 0x01,
-       0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
-       0xee, 0xfe, 0x4c, 0x44,
-       0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
-       0x7b, 0xec, 0x60, 0x8d,
-       0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
-       0x0c, 0x06, 0x28, 0xfe,
-       0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
-       0x13, 0x34, 0xfe, 0x4c,
-       0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
-       0x13, 0x01, 0x0c, 0x06,
-       0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
-       0x28, 0xf9, 0x1f, 0x7f,
-       0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
-       0xfe, 0xa4, 0x0e, 0x05,
-       0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
-       0x9c, 0x93, 0x3a, 0x0b,
-       0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
-       0x7d, 0x1d, 0xfe, 0x46,
-       0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
-       0xfe, 0x87, 0x83, 0xfe,
-       0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
-       0x13, 0x0f, 0xfe, 0x20,
-       0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
-       0x12, 0x01, 0x38, 0x06,
-       0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
-       0x05, 0xd0, 0x54, 0x01,
-       0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
-       0x50, 0x12, 0x5e, 0xff,
-       0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
-       0x00, 0x10, 0x2f, 0xfe,
-       0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
-       0x38, 0xfe, 0x4a, 0xf0,
-       0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
-       0x21, 0x00, 0xf1, 0x2e,
-       0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
-       0x10, 0x2f, 0xfe, 0xd0,
-       0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
-       0x1c, 0x00, 0x4d, 0x01,
-       0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
-       0x28, 0xfe, 0x24, 0x12,
-       0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
-       0x0d, 0x00, 0x01, 0x42,
-       0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
-       0x03, 0xb6, 0x1e, 0xfe,
-       0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
-       0xfe, 0x72, 0x06, 0x0a,
-       0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
-       0x19, 0x16, 0xfe, 0x68,
-       0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
-       0x03, 0x9a, 0x1e, 0xfe,
-       0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
-       0x48, 0xfe, 0x92, 0x06,
-       0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
-       0x58, 0xff, 0x02, 0x00,
-       0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
-       0xfe, 0xea, 0x06, 0x01,
-       0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
-       0xfe, 0xe0, 0x06, 0x15,
-       0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
-       0x01, 0x84, 0xfe, 0xae,
-       0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
-       0x1e, 0xfe, 0x1a, 0x12,
-       0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
-       0x43, 0x48, 0x62, 0x80,
-       0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
-       0x36, 0xfe, 0x02, 0xf6,
-       0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
-       0xd0, 0x0d, 0x17, 0xfe,
-       0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
-       0x9e, 0x15, 0x82, 0x01,
-       0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
-       0x57, 0x10, 0xe6, 0x05,
-       0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
-       0xfe, 0x9c, 0x32, 0x5f,
-       0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
-       0xfe, 0x0a, 0xf0, 0xfe,
-       0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
-       0xaf, 0xa0, 0x05, 0x29,
-       0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
-       0x00, 0x01, 0x08, 0x14,
-       0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
-       0x14, 0x00, 0x05, 0xfe,
-       0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
-       0x12, 0xfe, 0x30, 0x13,
-       0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
-       0x01, 0x08, 0x14, 0x00,
-       0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
-       0x78, 0x4f, 0x0f, 0xfe,
-       0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
-       0x28, 0x48, 0xfe, 0x6c,
-       0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
-       0x12, 0x53, 0x63, 0x4e,
-       0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
-       0x6c, 0x08, 0xaf, 0xa0,
-       0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
-       0x05, 0xed, 0xfe, 0x9c,
-       0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
-       0x1e, 0xfe, 0x99, 0x58,
-       0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
-       0x22, 0x6b, 0x01, 0x0c,
-       0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
-       0x1e, 0x47, 0x2c, 0x7a,
-       0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
-       0x01, 0x0c, 0x61, 0x65,
-       0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
-       0x16, 0xfe, 0x08, 0x50,
-       0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
-       0x01, 0xfe, 0xce, 0x1e,
-       0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
-       0x01, 0xfe, 0xfe, 0x1e,
-       0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
-       0x10, 0x01, 0x0c, 0x06,
-       0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
-       0x10, 0x6a, 0x22, 0x6b,
-       0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
-       0xfe, 0x9f, 0x83, 0x33,
-       0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
-       0x3a, 0x0b, 0xfe, 0xc6,
-       0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
-       0x01, 0xfe, 0xce, 0x1e,
-       0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
-       0x04, 0xfe, 0xc0, 0x93,
-       0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
-       0x10, 0x4b, 0x22, 0x4c,
-       0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
-       0x4e, 0x11, 0x2f, 0xfe,
-       0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
-       0x3c, 0x37, 0x88, 0xf5,
-       0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
-       0xd3, 0xfe, 0x42, 0x0a,
-       0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
-       0x05, 0x29, 0x01, 0x41,
-       0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
-       0xfe, 0x14, 0x12, 0x01,
-       0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
-       0x2e, 0x1c, 0x05, 0xfe,
-       0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
-       0xfe, 0x2c, 0x1c, 0xfe,
-       0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
-       0x92, 0x10, 0xc4, 0xf6,
-       0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
-       0xe7, 0x10, 0xfe, 0x2b,
-       0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
-       0xac, 0xfe, 0xd2, 0xf0,
-       0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
-       0x1b, 0xbf, 0xd4, 0x5b,
-       0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
-       0x5e, 0x32, 0x1f, 0x7f,
-       0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
-       0x05, 0x70, 0xfe, 0x74,
-       0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
-       0x0f, 0x4d, 0x01, 0xfe,
-       0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
-       0x0d, 0x2b, 0xfe, 0xe2,
-       0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
-       0xfe, 0x88, 0x13, 0x21,
-       0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
-       0x83, 0x83, 0xfe, 0xc9,
-       0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
-       0x91, 0x04, 0xfe, 0x84,
-       0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
-       0xfe, 0xcb, 0x57, 0x0b,
-       0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
-       0x6a, 0x3b, 0x6b, 0x10,
-       0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
-       0x20, 0x6e, 0xdb, 0x64,
-       0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
-       0xfe, 0x04, 0xfa, 0x64,
-       0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
-       0x10, 0x98, 0x91, 0x6c,
-       0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
-       0x4b, 0x7e, 0x4c, 0x01,
-       0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
-       0x58, 0xfe, 0x91, 0x58,
-       0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
-       0x1b, 0x40, 0x01, 0x0c,
-       0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
-       0xfe, 0x10, 0x90, 0x04,
-       0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
-       0x79, 0x0b, 0x0e, 0xfe,
-       0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
-       0x01, 0x0c, 0x06, 0x0d,
-       0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
-       0x0c, 0x58, 0xfe, 0x8d,
-       0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
-       0x83, 0x33, 0x0b, 0x0e,
-       0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
-       0x19, 0xfe, 0x19, 0x41,
-       0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
-       0x19, 0xfe, 0x44, 0x00,
-       0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
-       0x4c, 0xfe, 0x0c, 0x51,
-       0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
-       0x76, 0x10, 0xac, 0xfe,
-       0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
-       0xe3, 0x23, 0x07, 0xfe,
-       0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
-       0xcc, 0x0c, 0x1f, 0x92,
-       0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
-       0x0c, 0xfe, 0x3e, 0x10,
-       0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
-       0xfe, 0xcb, 0xf0, 0xfe,
-       0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
-       0xf4, 0x0c, 0x19, 0x94,
-       0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
-       0xfe, 0xcc, 0xf0, 0xef,
-       0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
-       0x4e, 0x11, 0x2f, 0xfe,
-       0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
-       0x3c, 0x37, 0x88, 0xf5,
-       0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
-       0x2f, 0xfe, 0x3e, 0x0d,
-       0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
-       0xd2, 0x9f, 0xd3, 0x9f,
-       0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
-       0xc5, 0x75, 0xd7, 0x99,
-       0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
-       0x9c, 0x2f, 0xfe, 0x8c,
-       0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
-       0x42, 0x00, 0x05, 0x70,
-       0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
-       0x0d, 0xfe, 0x44, 0x13,
-       0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
-       0xfe, 0xda, 0x0e, 0x0a,
-       0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
-       0x10, 0x01, 0xfe, 0xf4,
-       0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
-       0x15, 0x56, 0x01, 0x85,
-       0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
-       0xcc, 0x10, 0x01, 0xa7,
-       0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
-       0xfe, 0x99, 0x83, 0xfe,
-       0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
-       0x43, 0x00, 0xfe, 0xa2,
-       0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
-       0x00, 0x1d, 0x40, 0x15,
-       0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
-       0xfe, 0x3a, 0x03, 0x01,
-       0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
-       0x76, 0x06, 0x12, 0xfe,
-       0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
-       0xfe, 0x9d, 0xf0, 0xfe,
-       0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
-       0x0c, 0x61, 0x12, 0x44,
-       0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
-       0xfe, 0x2e, 0x10, 0x19,
-       0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
-       0xfe, 0x41, 0x00, 0xa2,
-       0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
-       0xea, 0x4f, 0xfe, 0x04,
-       0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
-       0x35, 0xfe, 0x12, 0x1c,
-       0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
-       0xfe, 0xd4, 0x11, 0x05,
-       0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
-       0xce, 0x45, 0x31, 0x51,
-       0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
-       0x67, 0xfe, 0x98, 0x56,
-       0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
-       0x0c, 0x06, 0x28, 0xfe,
-       0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
-       0xfe, 0xfa, 0x14, 0xfe,
-       0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
-       0xfe, 0xe0, 0x14, 0xfe,
-       0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
-       0xfe, 0xad, 0x13, 0x05,
-       0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
-       0xe7, 0xfe, 0x08, 0x1c,
-       0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
-       0x48, 0x55, 0xa5, 0x3b,
-       0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
-       0xf0, 0x1a, 0x03, 0xfe,
-       0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
-       0xec, 0xe7, 0x53, 0x00,
-       0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
-       0x01, 0xfe, 0x62, 0x1b,
-       0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
-       0xea, 0xe7, 0x53, 0x92,
-       0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
-       0xfe, 0x38, 0x01, 0x23,
-       0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
-       0x01, 0x01, 0xfe, 0x1e,
-       0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
-       0x26, 0x02, 0x21, 0x96,
-       0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
-       0xc3, 0xfe, 0xe1, 0x10,
-       0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
-       0xfe, 0x03, 0xdc, 0xfe,
-       0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
-       0x00, 0xcc, 0x02, 0xfe,
-       0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
-       0x0f, 0xfe, 0x1c, 0x80,
-       0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
-       0x0f, 0xfe, 0x1e, 0x80,
-       0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
-       0x1d, 0x80, 0x04, 0xfe,
-       0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
-       0x1e, 0xac, 0xfe, 0x14,
-       0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
-       0x1f, 0xfe, 0x30, 0xf4,
-       0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
-       0x56, 0xfb, 0x01, 0xfe,
-       0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
-       0xfe, 0x00, 0x1d, 0x15,
-       0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
-       0x22, 0x1b, 0xfe, 0x1e,
-       0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
-       0x96, 0x90, 0x04, 0xfe,
-       0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
-       0x01, 0x01, 0x0c, 0x06,
-       0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
-       0x0e, 0x77, 0xfe, 0x01,
-       0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
-       0x21, 0x2c, 0xfe, 0x00,
-       0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
-       0x06, 0x58, 0x03, 0xfe,
-       0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
-       0x03, 0xfe, 0xb2, 0x00,
-       0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
-       0x66, 0x10, 0x55, 0x10,
-       0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
-       0x54, 0x2b, 0xfe, 0x88,
-       0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
-       0x91, 0x54, 0x2b, 0xfe,
-       0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
-       0x00, 0x40, 0x8d, 0x2c,
-       0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
-       0x12, 0x1c, 0x75, 0xfe,
-       0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
-       0x14, 0xfe, 0x0e, 0x47,
-       0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
-       0xa7, 0x90, 0x34, 0x60,
-       0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
-       0x09, 0x56, 0xfe, 0x34,
-       0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
-       0xfe, 0x45, 0x48, 0x01,
-       0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
-       0x09, 0x1a, 0xa5, 0x0a,
-       0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
-       0xfe, 0x14, 0x56, 0xfe,
-       0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
-       0xec, 0xb8, 0xfe, 0x9e,
-       0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
-       0xf4, 0xfe, 0xdd, 0x10,
-       0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
-       0x12, 0x09, 0x0d, 0xfe,
-       0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
-       0x13, 0x09, 0xfe, 0x23,
-       0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
-       0x24, 0xfe, 0x12, 0x12,
-       0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
-       0xae, 0x41, 0x02, 0x32,
-       0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
-       0x35, 0x32, 0x01, 0x43,
-       0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
-       0x13, 0x01, 0x0c, 0x06,
-       0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
-       0xe5, 0x55, 0xb0, 0xfe,
-       0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
-       0xfe, 0xb6, 0x0e, 0x10,
-       0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
-       0x88, 0x20, 0x6e, 0x01,
-       0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
-       0x55, 0xfe, 0x04, 0xfa,
-       0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
-       0xfe, 0x40, 0x56, 0xfe,
-       0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
-       0x44, 0x55, 0xfe, 0xe5,
-       0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
-       0x68, 0x22, 0x69, 0x01,
-       0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
-       0x6b, 0xfe, 0x2c, 0x50,
-       0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
-       0x50, 0x03, 0x68, 0x3b,
-       0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
-       0x40, 0x50, 0xfe, 0xc2,
-       0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
-       0x16, 0x3d, 0x27, 0x25,
-       0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
-       0xa6, 0x23, 0x3f, 0x1b,
-       0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
-       0xfe, 0x0a, 0x55, 0x31,
-       0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
-       0x51, 0x05, 0x72, 0x01,
-       0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
-       0x2a, 0x3c, 0x16, 0xc0,
-       0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
-       0xfe, 0x66, 0x15, 0x05,
-       0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
-       0x2b, 0x3d, 0x01, 0x08,
-       0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
-       0xb6, 0x1e, 0x83, 0x01,
-       0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
-       0x07, 0x90, 0x3f, 0x01,
-       0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
-       0x01, 0x43, 0x09, 0x82,
-       0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
-       0x05, 0x72, 0xfe, 0xc0,
-       0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
-       0x32, 0x01, 0x08, 0x17,
-       0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
-       0x3d, 0x27, 0x25, 0xbd,
-       0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
-       0xe8, 0x14, 0x01, 0xa6,
-       0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
-       0x0e, 0x12, 0x01, 0x43,
-       0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
-       0x01, 0x08, 0x17, 0x73,
-       0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
-       0x27, 0x25, 0xbd, 0x09,
-       0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
-       0xb6, 0x14, 0x86, 0xa8,
-       0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
-       0x82, 0x4e, 0x05, 0x72,
-       0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
-       0xfe, 0xc0, 0x19, 0x05,
-       0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
-       0xcc, 0x01, 0x08, 0x26,
-       0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
-       0xcc, 0x15, 0x5e, 0x32,
-       0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
-       0xad, 0x23, 0xfe, 0xff,
-       0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
-       0x00, 0x57, 0x52, 0xad,
-       0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
-       0x02, 0x00, 0x57, 0x52,
-       0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
-       0x02, 0x13, 0x58, 0xff,
-       0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
-       0x5c, 0x0a, 0x55, 0x01,
-       0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
-       0xff, 0x03, 0x00, 0x54,
-       0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
-       0x7c, 0x3a, 0x0b, 0x0e,
-       0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
-       0xfe, 0x1a, 0xf7, 0x00,
-       0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
-       0xda, 0x6d, 0x02, 0xfe,
-       0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
-       0x02, 0x01, 0xc6, 0xfe,
-       0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
-       0x25, 0xbe, 0x01, 0x08,
-       0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
-       0x03, 0x9a, 0x1e, 0xfe,
-       0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
-       0x48, 0xfe, 0x08, 0x17,
-       0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
-       0x17, 0x4d, 0x13, 0x07,
-       0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
-       0xff, 0x02, 0x83, 0x55,
-       0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
-       0x17, 0x1c, 0x63, 0x13,
-       0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
-       0x00, 0xb0, 0xfe, 0x80,
-       0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
-       0x53, 0x07, 0xfe, 0x60,
-       0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
-       0x00, 0x1c, 0x95, 0x13,
-       0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
-       0xfe, 0x43, 0xf4, 0x96,
-       0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
-       0xf4, 0x94, 0xf6, 0x8b,
-       0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
-       0xda, 0x17, 0x62, 0x49,
-       0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
-       0x71, 0x50, 0x26, 0xfe,
-       0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
-       0x58, 0x02, 0x50, 0x13,
-       0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
-       0x25, 0xbe, 0xfe, 0x03,
-       0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
-       0x0a, 0x01, 0x08, 0x16,
-       0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
-       0x01, 0x08, 0x16, 0xa9,
-       0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
-       0x08, 0x16, 0xa9, 0x27,
-       0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
-       0x01, 0x38, 0x06, 0x24,
-       0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
-       0x78, 0x03, 0x9a, 0x1e,
-       0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
-       0xfe, 0x40, 0x5a, 0x23,
-       0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
-       0x80, 0x48, 0xfe, 0xaa,
-       0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
-       0xfe, 0xac, 0x1d, 0xfe,
-       0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
-       0x43, 0x48, 0x2d, 0x93,
-       0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
-       0x36, 0xfe, 0x34, 0xf4,
-       0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
-       0x28, 0x10, 0xfe, 0xc0,
-       0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
-       0x18, 0x45, 0xfe, 0x1c,
-       0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
-       0x19, 0xfe, 0x04, 0xf4,
-       0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
-       0x21, 0xfe, 0x7f, 0x01,
-       0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
-       0x7e, 0x01, 0xfe, 0xc8,
-       0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
-       0x21, 0xfe, 0x81, 0x01,
-       0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
-       0x13, 0x0d, 0x02, 0x14,
-       0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
-       0xfe, 0x82, 0x19, 0x14,
-       0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
-       0x08, 0x02, 0x14, 0x07,
-       0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
-       0x01, 0x08, 0x17, 0xc1,
-       0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
-       0x08, 0x02, 0x50, 0x02,
-       0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
-       0x14, 0x12, 0x01, 0x08,
-       0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
-       0x08, 0x17, 0x74, 0xfe,
-       0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
-       0x74, 0x5f, 0xcc, 0x01,
-       0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
-       0xfe, 0x49, 0xf4, 0x00,
-       0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
-       0x02, 0x00, 0x10, 0x2f,
-       0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
-       0x16, 0xfe, 0x64, 0x1a,
-       0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
-       0x61, 0x07, 0x44, 0x02,
-       0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
-       0x13, 0x0a, 0x9d, 0x01,
-       0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
-       0xfe, 0x80, 0xe7, 0x1a,
-       0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
-       0x0a, 0x5a, 0x01, 0x18,
-       0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
-       0x7e, 0x1e, 0xfe, 0x80,
-       0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
-       0xfe, 0x80, 0x4c, 0x0a,
-       0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
-       0xfe, 0x19, 0xde, 0xfe,
-       0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
-       0x2a, 0x1c, 0xfa, 0xb3,
-       0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
-       0xf4, 0x1a, 0xfe, 0xfa,
-       0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
-       0xfe, 0x18, 0x58, 0x03,
-       0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
-       0xfe, 0x30, 0xf4, 0x07,
-       0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
-       0xf7, 0x24, 0xb1, 0xfe,
-       0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
-       0xfe, 0xba, 0x10, 0x1c,
-       0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
-       0x1d, 0xf7, 0x54, 0xb1,
-       0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
-       0xaf, 0x19, 0xfe, 0x98,
-       0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
-       0x1a, 0x87, 0x8b, 0x0f,
-       0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
-       0xfe, 0x32, 0x90, 0x04,
-       0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
-       0x7c, 0x12, 0xfe, 0x0f,
-       0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
-       0x31, 0x02, 0xc9, 0x2b,
-       0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
-       0x6a, 0xfe, 0x19, 0xfe,
-       0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
-       0x1b, 0xfe, 0x36, 0x14,
-       0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
-       0xfe, 0x80, 0xe7, 0x1a,
-       0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
-       0x30, 0xfe, 0x12, 0x45,
-       0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
-       0x39, 0xf0, 0x75, 0x26,
-       0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
-       0xe3, 0x23, 0x07, 0xfe,
-       0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
-       0x56, 0xfe, 0x3c, 0x13,
-       0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
-       0x01, 0x18, 0xcb, 0xfe,
-       0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
-       0xfe, 0x00, 0xcc, 0xcb,
-       0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
-       0xfe, 0x80, 0x4c, 0x01,
-       0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
-       0x12, 0xfe, 0x14, 0x56,
-       0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
-       0x0d, 0x19, 0xfe, 0x15,
-       0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
-       0x83, 0xfe, 0x18, 0x80,
-       0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
-       0x90, 0xfe, 0xba, 0x90,
-       0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
-       0x21, 0xb9, 0x88, 0x20,
-       0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
-       0x18, 0xfe, 0x49, 0x44,
-       0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
-       0x1a, 0xa4, 0x0a, 0x67,
-       0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
-       0x1d, 0x7b, 0xfe, 0x52,
-       0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
-       0x4e, 0xe4, 0xdd, 0x7b,
-       0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
-       0xfe, 0x4e, 0xe4, 0xfe,
-       0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
-       0xfe, 0x08, 0x10, 0x03,
-       0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
-       0x68, 0x54, 0xfe, 0xf1,
-       0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
-       0xfe, 0x1a, 0xf4, 0xfe,
-       0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
-       0x09, 0x92, 0xfe, 0x5a,
-       0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
-       0x5a, 0xf0, 0xfe, 0xc8,
-       0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
-       0x1a, 0x10, 0x09, 0x0d,
-       0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
-       0x1f, 0x93, 0x01, 0x42,
-       0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
-       0xfe, 0x14, 0xf0, 0x08,
-       0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
-       0xfe, 0x82, 0xf0, 0xfe,
-       0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
-       0x02, 0x0f, 0xfe, 0x18,
-       0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
-       0x80, 0x04, 0xfe, 0x82,
-       0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
-       0x83, 0x33, 0x0b, 0x0e,
-       0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
-       0x02, 0x0f, 0xfe, 0x04,
-       0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
-       0x80, 0x04, 0xfe, 0x80,
-       0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
-       0xfe, 0x99, 0x83, 0xfe,
-       0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
-       0x83, 0xfe, 0xce, 0x47,
-       0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
-       0x0b, 0x0e, 0x02, 0x0f,
-       0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
-       0xfe, 0x08, 0x90, 0x04,
-       0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
-       0xfe, 0x8a, 0x93, 0x79,
-       0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
-       0x0b, 0x0e, 0x02, 0x0f,
-       0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
-       0xfe, 0x3c, 0x90, 0x04,
-       0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
-       0x04, 0xfe, 0x83, 0x83,
-       0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
-};
+               /*
+                * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+                * structure pointer using a macro provided by the driver.
+                * The ASC_SCSI_REQ pointer provides a pointer to the
+                * host ASC_SG_HEAD structure.
+                */
+               /* Read request's SRB pointer. */
+               scsiq = (ASC_SCSI_Q *)
+                   ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
+                                                                   (ushort)
+                                                                   (q_addr +
+                                                                    ASC_SCSIQ_D_SRBPTR))));
+
+               /*
+                * Get request's first and working SG queue.
+                */
+               sg_wk_q_no = AscReadLramByte(iop_base,
+                                            (ushort)(q_addr +
+                                                     ASC_SCSIQ_B_SG_WK_QP));
+
+               first_sg_wk_q_no = AscReadLramByte(iop_base,
+                                                  (ushort)(q_addr +
+                                                           ASC_SCSIQ_B_FIRST_SG_WK_QP));
+
+               /*
+                * Reset request's working SG queue back to the
+                * first SG queue.
+                */
+               AscWriteLramByte(iop_base,
+                                (ushort)(q_addr +
+                                         (ushort)ASC_SCSIQ_B_SG_WK_QP),
+                                first_sg_wk_q_no);
+
+               sg_head = scsiq->sg_head;
+
+               /*
+                * Set sg_entry_cnt to the number of SG elements
+                * that will be completed on this interrupt.
+                *
+                * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+                * SG elements. The data_cnt and data_addr fields which
+                * add 1 to the SG element capacity are not used when
+                * restarting SG handling after a halt.
+                */
+               if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
+                       sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+                       /*
+                        * Keep track of remaining number of SG elements that
+                        * will need to be handled on the next interrupt.
+                        */
+                       scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+               } else {
+                       sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+                       scsiq->remain_sg_entry_cnt = 0;
+               }
+
+               /*
+                * Copy SG elements into the list of allocated SG queues.
+                *
+                * Last index completed is saved in scsiq->next_sg_index.
+                */
+               next_qp = first_sg_wk_q_no;
+               q_addr = ASC_QNO_TO_QADDR(next_qp);
+               scsi_sg_q.sg_head_qp = q_no;
+               scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+               for (i = 0; i < sg_head->queue_cnt; i++) {
+                       scsi_sg_q.seq_no = i + 1;
+                       if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+                               sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
+                               sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                               /*
+                                * After very first SG queue RISC FW uses next
+                                * SG queue first element then checks sg_list_cnt
+                                * against zero and then decrements, so set
+                                * sg_list_cnt 1 less than number of SG elements
+                                * in each SG queue.
+                                */
+                               scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                               scsi_sg_q.sg_cur_list_cnt =
+                                   ASC_SG_LIST_PER_Q - 1;
+                       } else {
+                               /*
+                                * This is the last SG queue in the list of
+                                * allocated SG queues. If there are more
+                                * SG elements than will fit in the allocated
+                                * queues, then set the QCSG_SG_XFER_MORE flag.
+                                */
+                               if (scsiq->remain_sg_entry_cnt != 0) {
+                                       scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                               } else {
+                                       scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                               }
+                               /* equals sg_entry_cnt * 2 */
+                               sg_list_dwords = sg_entry_cnt << 1;
+                               scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+                               scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+                               sg_entry_cnt = 0;
+                       }
 
-static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf);      /* 0x1673 */
-static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
+                       scsi_sg_q.q_no = next_qp;
+                       AscMemWordCopyPtrToLram(iop_base,
+                                               q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+                                               (uchar *)&scsi_sg_q,
+                                               sizeof(ASC_SG_LIST_Q) >> 1);
+
+                       AscMemDWordCopyPtrToLram(iop_base,
+                                                q_addr + ASC_SGQ_LIST_BEG,
+                                                (uchar *)&sg_head->
+                                                sg_list[scsiq->next_sg_index],
+                                                sg_list_dwords);
+
+                       scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+
+                       /*
+                        * If the just completed SG queue contained the
+                        * last SG element, then no more SG queues need
+                        * to be written.
+                        */
+                       if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
+                               break;
+                       }
+
+                       next_qp = AscReadLramByte(iop_base,
+                                                 (ushort)(q_addr +
+                                                          ASC_SCSIQ_B_FWD));
+                       q_addr = ASC_QNO_TO_QADDR(next_qp);
+               }
+
+               /*
+                * Clear the halt condition so the RISC will be restarted
+                * after the return.
+                */
+               AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+               return (0);
+       }
+#endif /* CC_VERY_LONG_SG_LIST */
+       return (0);
+}
 
-/* a_init.c */
 /*
- * EEPROM Configuration.
+ * void
+ * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
  *
- * All drivers should use this structure to set the default EEPROM
- * configuration. The BIOS now uses this structure when it is built.
- * Additional structure information can be found in a_condor.h where
- * the structure is defined.
+ * Calling/Exit State:
+ *    none
  *
- * The *_Field_IsChar structs are needed to correct for endianness.
- * These values are read from the board 16 bits at a time directly
- * into the structs. Because some fields are char, the values will be
- * in the wrong order. The *_Field_IsChar tells when to flip the
- * bytes. Data read and written to PCI memory is automatically swapped
- * on big-endian platforms so char fields read as words are actually being
- * unswapped on big-endian platforms.
+ * Description:
+ *     Input an ASC_QDONE_INFO structure from the chip
  */
-static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
-       ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
-       0x0000,                 /* cfg_msw */
-       0xFFFF,                 /* disc_enable */
-       0xFFFF,                 /* wdtr_able */
-       0xFFFF,                 /* sdtr_able */
-       0xFFFF,                 /* start_motor */
-       0xFFFF,                 /* tagqng_able */
-       0xFFFF,                 /* bios_scan */
-       0,                      /* scam_tolerant */
-       7,                      /* adapter_scsi_id */
-       0,                      /* bios_boot_delay */
-       3,                      /* scsi_reset_delay */
-       0,                      /* bios_id_lun */
-       0,                      /* termination */
-       0,                      /* reserved1 */
-       0xFFE7,                 /* bios_ctrl */
-       0xFFFF,                 /* ultra_able */
-       0,                      /* reserved2 */
-       ASC_DEF_MAX_HOST_QNG,   /* max_host_qng */
-       ASC_DEF_MAX_DVC_QNG,    /* max_dvc_qng */
-       0,                      /* dvc_cntl */
-       0,                      /* bug_fix */
-       0,                      /* serial_number_word1 */
-       0,                      /* serial_number_word2 */
-       0,                      /* serial_number_word3 */
-       0,                      /* check_sum */
-       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-       ,                       /* oem_name[16] */
-       0,                      /* dvc_err_code */
-       0,                      /* adv_err_code */
-       0,                      /* adv_err_addr */
-       0,                      /* saved_dvc_err_code */
-       0,                      /* saved_adv_err_code */
-       0,                      /* saved_adv_err_addr */
-       0                       /* num_of_err */
-};
+static void
+DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+{
+       int i;
+       ushort word;
+
+       AscSetChipLramAddr(iop_base, s_addr);
+       for (i = 0; i < 2 * words; i += 2) {
+               if (i == 10) {
+                       continue;
+               }
+               word = inpw(iop_base + IOP_RAM_DATA);
+               inbuf[i] = word & 0xff;
+               inbuf[i + 1] = (word >> 8) & 0xff;
+       }
+       ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
+}
+
+static uchar
+_AscCopyLramScsiDoneQ(PortAddr iop_base,
+                     ushort q_addr,
+                     ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
+{
+       ushort _val;
+       uchar sg_queue_cnt;
+
+       DvcGetQinfo(iop_base,
+                   q_addr + ASC_SCSIQ_DONE_INFO_BEG,
+                   (uchar *)scsiq,
+                   (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
+
+       _val = AscReadLramWord(iop_base,
+                              (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
+       scsiq->q_status = (uchar)_val;
+       scsiq->q_no = (uchar)(_val >> 8);
+       _val = AscReadLramWord(iop_base,
+                              (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
+       scsiq->cntl = (uchar)_val;
+       sg_queue_cnt = (uchar)(_val >> 8);
+       _val = AscReadLramWord(iop_base,
+                              (ushort)(q_addr +
+                                       (ushort)ASC_SCSIQ_B_SENSE_LEN));
+       scsiq->sense_len = (uchar)_val;
+       scsiq->extra_bytes = (uchar)(_val >> 8);
+
+       /*
+        * Read high word of remain bytes from alternate location.
+        */
+       scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
+                                                         (ushort)(q_addr +
+                                                                  (ushort)
+                                                                  ASC_SCSIQ_W_ALT_DC1)))
+                              << 16);
+       /*
+        * Read low word of remain bytes from original location.
+        */
+       scsiq->remain_bytes += AscReadLramWord(iop_base,
+                                              (ushort)(q_addr + (ushort)
+                                                       ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
+       scsiq->remain_bytes &= max_dma_count;
+       return sg_queue_cnt;
+}
+
+/*
+ * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ *
+ * Interrupt callback function for the Narrow SCSI Asc Library.
+ */
+static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+{
+       struct asc_board *boardp;
+       struct scsi_cmnd *scp;
+       struct Scsi_Host *shost;
+
+       ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep);
+       ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+
+       scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr);
+       if (!scp)
+               return;
+
+       ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+       shost = scp->device->host;
+       ASC_STATS(shost, callback);
+       ASC_DBG(1, "shost 0x%p\n", shost);
+
+       boardp = shost_priv(shost);
+       BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
+
+       dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
+                       sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+       /*
+        * 'qdonep' contains the command's ending status.
+        */
+       switch (qdonep->d3.done_stat) {
+       case QD_NO_ERROR:
+               ASC_DBG(2, "QD_NO_ERROR\n");
+               scp->result = 0;
+
+               /*
+                * Check for an underrun condition.
+                *
+                * If there was no error and an underrun condition, then
+                * return the number of underrun bytes.
+                */
+               if (scsi_bufflen(scp) != 0 && qdonep->remain_bytes != 0 &&
+                   qdonep->remain_bytes <= scsi_bufflen(scp)) {
+                       ASC_DBG(1, "underrun condition %u bytes\n",
+                                (unsigned)qdonep->remain_bytes);
+                       scsi_set_resid(scp, qdonep->remain_bytes);
+               }
+               break;
+
+       case QD_WITH_ERROR:
+               ASC_DBG(2, "QD_WITH_ERROR\n");
+               switch (qdonep->d3.host_stat) {
+               case QHSTA_NO_ERROR:
+                       if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+                               ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+                               ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+                                                 sizeof(scp->sense_buffer));
+                               /*
+                                * Note: The 'status_byte()' macro used by
+                                * target drivers defined in scsi.h shifts the
+                                * status byte returned by host drivers right
+                                * by 1 bit.  This is why target drivers also
+                                * use right shifted status byte definitions.
+                                * For instance target drivers use
+                                * CHECK_CONDITION, defined to 0x1, instead of
+                                * the SCSI defined check condition value of
+                                * 0x2. Host drivers are supposed to return
+                                * the status byte as it is defined by SCSI.
+                                */
+                               scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+                                   STATUS_BYTE(qdonep->d3.scsi_stat);
+                       } else {
+                               scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
+                       }
+                       break;
+
+               default:
+                       /* QHSTA error occurred */
+                       ASC_DBG(1, "host_stat 0x%x\n", qdonep->d3.host_stat);
+                       scp->result = HOST_BYTE(DID_BAD_TARGET);
+                       break;
+               }
+               break;
 
-static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
-       0,                      /* cfg_lsw */
-       0,                      /* cfg_msw */
-       0,                      /* -disc_enable */
-       0,                      /* wdtr_able */
-       0,                      /* sdtr_able */
-       0,                      /* start_motor */
-       0,                      /* tagqng_able */
-       0,                      /* bios_scan */
-       0,                      /* scam_tolerant */
-       1,                      /* adapter_scsi_id */
-       1,                      /* bios_boot_delay */
-       1,                      /* scsi_reset_delay */
-       1,                      /* bios_id_lun */
-       1,                      /* termination */
-       1,                      /* reserved1 */
-       0,                      /* bios_ctrl */
-       0,                      /* ultra_able */
-       0,                      /* reserved2 */
-       1,                      /* max_host_qng */
-       1,                      /* max_dvc_qng */
-       0,                      /* dvc_cntl */
-       0,                      /* bug_fix */
-       0,                      /* serial_number_word1 */
-       0,                      /* serial_number_word2 */
-       0,                      /* serial_number_word3 */
-       0,                      /* check_sum */
-       {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
-       ,                       /* oem_name[16] */
-       0,                      /* dvc_err_code */
-       0,                      /* adv_err_code */
-       0,                      /* adv_err_addr */
-       0,                      /* saved_dvc_err_code */
-       0,                      /* saved_adv_err_code */
-       0,                      /* saved_adv_err_addr */
-       0                       /* num_of_err */
-};
+       case QD_ABORTED_BY_HOST:
+               ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
+               scp->result =
+                   HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
+                                                   scsi_msg) |
+                   STATUS_BYTE(qdonep->d3.scsi_stat);
+               break;
 
-static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
-       ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
-       0x0000,                 /* 01 cfg_msw */
-       0xFFFF,                 /* 02 disc_enable */
-       0xFFFF,                 /* 03 wdtr_able */
-       0x4444,                 /* 04 sdtr_speed1 */
-       0xFFFF,                 /* 05 start_motor */
-       0xFFFF,                 /* 06 tagqng_able */
-       0xFFFF,                 /* 07 bios_scan */
-       0,                      /* 08 scam_tolerant */
-       7,                      /* 09 adapter_scsi_id */
-       0,                      /*    bios_boot_delay */
-       3,                      /* 10 scsi_reset_delay */
-       0,                      /*    bios_id_lun */
-       0,                      /* 11 termination_se */
-       0,                      /*    termination_lvd */
-       0xFFE7,                 /* 12 bios_ctrl */
-       0x4444,                 /* 13 sdtr_speed2 */
-       0x4444,                 /* 14 sdtr_speed3 */
-       ASC_DEF_MAX_HOST_QNG,   /* 15 max_host_qng */
-       ASC_DEF_MAX_DVC_QNG,    /*    max_dvc_qng */
-       0,                      /* 16 dvc_cntl */
-       0x4444,                 /* 17 sdtr_speed4 */
-       0,                      /* 18 serial_number_word1 */
-       0,                      /* 19 serial_number_word2 */
-       0,                      /* 20 serial_number_word3 */
-       0,                      /* 21 check_sum */
-       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-       ,                       /* 22-29 oem_name[16] */
-       0,                      /* 30 dvc_err_code */
-       0,                      /* 31 adv_err_code */
-       0,                      /* 32 adv_err_addr */
-       0,                      /* 33 saved_dvc_err_code */
-       0,                      /* 34 saved_adv_err_code */
-       0,                      /* 35 saved_adv_err_addr */
-       0,                      /* 36 reserved */
-       0,                      /* 37 reserved */
-       0,                      /* 38 reserved */
-       0,                      /* 39 reserved */
-       0,                      /* 40 reserved */
-       0,                      /* 41 reserved */
-       0,                      /* 42 reserved */
-       0,                      /* 43 reserved */
-       0,                      /* 44 reserved */
-       0,                      /* 45 reserved */
-       0,                      /* 46 reserved */
-       0,                      /* 47 reserved */
-       0,                      /* 48 reserved */
-       0,                      /* 49 reserved */
-       0,                      /* 50 reserved */
-       0,                      /* 51 reserved */
-       0,                      /* 52 reserved */
-       0,                      /* 53 reserved */
-       0,                      /* 54 reserved */
-       0,                      /* 55 reserved */
-       0,                      /* 56 cisptr_lsw */
-       0,                      /* 57 cisprt_msw */
-       PCI_VENDOR_ID_ASP,      /* 58 subsysvid */
-       PCI_DEVICE_ID_38C0800_REV1,     /* 59 subsysid */
-       0,                      /* 60 reserved */
-       0,                      /* 61 reserved */
-       0,                      /* 62 reserved */
-       0                       /* 63 reserved */
-};
+       default:
+               ASC_DBG(1, "done_stat 0x%x\n", qdonep->d3.done_stat);
+               scp->result =
+                   HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
+                                                   scsi_msg) |
+                   STATUS_BYTE(qdonep->d3.scsi_stat);
+               break;
+       }
+
+       /*
+        * If the 'init_tidmask' bit isn't already set for the target and the
+        * current request finished normally, then set the bit for the target
+        * to indicate that a device is present.
+        */
+       if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+           qdonep->d3.done_stat == QD_NO_ERROR &&
+           qdonep->d3.host_stat == QHSTA_NO_ERROR) {
+               boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+       }
+
+       asc_scsi_done(scp);
+}
+
+static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
+{
+       uchar next_qp;
+       uchar n_q_used;
+       uchar sg_list_qp;
+       uchar sg_queue_cnt;
+       uchar q_cnt;
+       uchar done_q_tail;
+       uchar tid_no;
+       ASC_SCSI_BIT_ID_TYPE scsi_busy;
+       ASC_SCSI_BIT_ID_TYPE target_id;
+       PortAddr iop_base;
+       ushort q_addr;
+       ushort sg_q_addr;
+       uchar cur_target_qng;
+       ASC_QDONE_INFO scsiq_buf;
+       ASC_QDONE_INFO *scsiq;
+       int false_overrun;
+
+       iop_base = asc_dvc->iop_base;
+       n_q_used = 1;
+       scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
+       done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
+       q_addr = ASC_QNO_TO_QADDR(done_q_tail);
+       next_qp = AscReadLramByte(iop_base,
+                                 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
+       if (next_qp != ASC_QLINK_END) {
+               AscPutVarDoneQTail(iop_base, next_qp);
+               q_addr = ASC_QNO_TO_QADDR(next_qp);
+               sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
+                                                    asc_dvc->max_dma_count);
+               AscWriteLramByte(iop_base,
+                                (ushort)(q_addr +
+                                         (ushort)ASC_SCSIQ_B_STATUS),
+                                (uchar)(scsiq->
+                                        q_status & (uchar)~(QS_READY |
+                                                            QS_ABORTED)));
+               tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
+               target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
+               if ((scsiq->cntl & QC_SG_HEAD) != 0) {
+                       sg_q_addr = q_addr;
+                       sg_list_qp = next_qp;
+                       for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
+                               sg_list_qp = AscReadLramByte(iop_base,
+                                                            (ushort)(sg_q_addr
+                                                                     + (ushort)
+                                                                     ASC_SCSIQ_B_FWD));
+                               sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
+                               if (sg_list_qp == ASC_QLINK_END) {
+                                       AscSetLibErrorCode(asc_dvc,
+                                                          ASCQ_ERR_SG_Q_LINKS);
+                                       scsiq->d3.done_stat = QD_WITH_ERROR;
+                                       scsiq->d3.host_stat =
+                                           QHSTA_D_QDONE_SG_LIST_CORRUPTED;
+                                       goto FATAL_ERR_QDONE;
+                               }
+                               AscWriteLramByte(iop_base,
+                                                (ushort)(sg_q_addr + (ushort)
+                                                         ASC_SCSIQ_B_STATUS),
+                                                QS_FREE);
+                       }
+                       n_q_used = sg_queue_cnt + 1;
+                       AscPutVarDoneQTail(iop_base, sg_list_qp);
+               }
+               if (asc_dvc->queue_full_or_busy & target_id) {
+                       cur_target_qng = AscReadLramByte(iop_base,
+                                                        (ushort)((ushort)
+                                                                 ASC_QADR_BEG
+                                                                 + (ushort)
+                                                                 scsiq->d2.
+                                                                 target_ix));
+                       if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
+                               scsi_busy = AscReadLramByte(iop_base, (ushort)
+                                                           ASCV_SCSIBUSY_B);
+                               scsi_busy &= ~target_id;
+                               AscWriteLramByte(iop_base,
+                                                (ushort)ASCV_SCSIBUSY_B,
+                                                scsi_busy);
+                               asc_dvc->queue_full_or_busy &= ~target_id;
+                       }
+               }
+               if (asc_dvc->cur_total_qng >= n_q_used) {
+                       asc_dvc->cur_total_qng -= n_q_used;
+                       if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
+                               asc_dvc->cur_dvc_qng[tid_no]--;
+                       }
+               } else {
+                       AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
+                       scsiq->d3.done_stat = QD_WITH_ERROR;
+                       goto FATAL_ERR_QDONE;
+               }
+               if ((scsiq->d2.srb_ptr == 0UL) ||
+                   ((scsiq->q_status & QS_ABORTED) != 0)) {
+                       return (0x11);
+               } else if (scsiq->q_status == QS_DONE) {
+                       false_overrun = FALSE;
+                       if (scsiq->extra_bytes != 0) {
+                               scsiq->remain_bytes +=
+                                   (ADV_DCNT)scsiq->extra_bytes;
+                       }
+                       if (scsiq->d3.done_stat == QD_WITH_ERROR) {
+                               if (scsiq->d3.host_stat ==
+                                   QHSTA_M_DATA_OVER_RUN) {
+                                       if ((scsiq->
+                                            cntl & (QC_DATA_IN | QC_DATA_OUT))
+                                           == 0) {
+                                               scsiq->d3.done_stat =
+                                                   QD_NO_ERROR;
+                                               scsiq->d3.host_stat =
+                                                   QHSTA_NO_ERROR;
+                                       } else if (false_overrun) {
+                                               scsiq->d3.done_stat =
+                                                   QD_NO_ERROR;
+                                               scsiq->d3.host_stat =
+                                                   QHSTA_NO_ERROR;
+                                       }
+                               } else if (scsiq->d3.host_stat ==
+                                          QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
+                                       AscStopChip(iop_base);
+                                       AscSetChipControl(iop_base,
+                                                         (uchar)(CC_SCSI_RESET
+                                                                 | CC_HALT));
+                                       udelay(60);
+                                       AscSetChipControl(iop_base, CC_HALT);
+                                       AscSetChipStatus(iop_base,
+                                                        CIW_CLR_SCSI_RESET_INT);
+                                       AscSetChipStatus(iop_base, 0);
+                                       AscSetChipControl(iop_base, 0);
+                               }
+                       }
+                       if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+                               asc_isr_callback(asc_dvc, scsiq);
+                       } else {
+                               if ((AscReadLramByte(iop_base,
+                                                    (ushort)(q_addr + (ushort)
+                                                             ASC_SCSIQ_CDB_BEG))
+                                    == START_STOP)) {
+                                       asc_dvc->unit_not_ready &= ~target_id;
+                                       if (scsiq->d3.done_stat != QD_NO_ERROR) {
+                                               asc_dvc->start_motor &=
+                                                   ~target_id;
+                                       }
+                               }
+                       }
+                       return (1);
+               } else {
+                       AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
+ FATAL_ERR_QDONE:
+                       if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+                               asc_isr_callback(asc_dvc, scsiq);
+                       }
+                       return (0x80);
+               }
+       }
+       return (0);
+}
 
-static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
-       0,                      /* 00 cfg_lsw */
-       0,                      /* 01 cfg_msw */
-       0,                      /* 02 disc_enable */
-       0,                      /* 03 wdtr_able */
-       0,                      /* 04 sdtr_speed1 */
-       0,                      /* 05 start_motor */
-       0,                      /* 06 tagqng_able */
-       0,                      /* 07 bios_scan */
-       0,                      /* 08 scam_tolerant */
-       1,                      /* 09 adapter_scsi_id */
-       1,                      /*    bios_boot_delay */
-       1,                      /* 10 scsi_reset_delay */
-       1,                      /*    bios_id_lun */
-       1,                      /* 11 termination_se */
-       1,                      /*    termination_lvd */
-       0,                      /* 12 bios_ctrl */
-       0,                      /* 13 sdtr_speed2 */
-       0,                      /* 14 sdtr_speed3 */
-       1,                      /* 15 max_host_qng */
-       1,                      /*    max_dvc_qng */
-       0,                      /* 16 dvc_cntl */
-       0,                      /* 17 sdtr_speed4 */
-       0,                      /* 18 serial_number_word1 */
-       0,                      /* 19 serial_number_word2 */
-       0,                      /* 20 serial_number_word3 */
-       0,                      /* 21 check_sum */
-       {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
-       ,                       /* 22-29 oem_name[16] */
-       0,                      /* 30 dvc_err_code */
-       0,                      /* 31 adv_err_code */
-       0,                      /* 32 adv_err_addr */
-       0,                      /* 33 saved_dvc_err_code */
-       0,                      /* 34 saved_adv_err_code */
-       0,                      /* 35 saved_adv_err_addr */
-       0,                      /* 36 reserved */
-       0,                      /* 37 reserved */
-       0,                      /* 38 reserved */
-       0,                      /* 39 reserved */
-       0,                      /* 40 reserved */
-       0,                      /* 41 reserved */
-       0,                      /* 42 reserved */
-       0,                      /* 43 reserved */
-       0,                      /* 44 reserved */
-       0,                      /* 45 reserved */
-       0,                      /* 46 reserved */
-       0,                      /* 47 reserved */
-       0,                      /* 48 reserved */
-       0,                      /* 49 reserved */
-       0,                      /* 50 reserved */
-       0,                      /* 51 reserved */
-       0,                      /* 52 reserved */
-       0,                      /* 53 reserved */
-       0,                      /* 54 reserved */
-       0,                      /* 55 reserved */
-       0,                      /* 56 cisptr_lsw */
-       0,                      /* 57 cisprt_msw */
-       0,                      /* 58 subsysvid */
-       0,                      /* 59 subsysid */
-       0,                      /* 60 reserved */
-       0,                      /* 61 reserved */
-       0,                      /* 62 reserved */
-       0                       /* 63 reserved */
-};
+static int AscISR(ASC_DVC_VAR *asc_dvc)
+{
+       ASC_CS_TYPE chipstat;
+       PortAddr iop_base;
+       ushort saved_ram_addr;
+       uchar ctrl_reg;
+       uchar saved_ctrl_reg;
+       int int_pending;
+       int status;
+       uchar host_flag;
 
-static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
-       ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
-       0x0000,                 /* 01 cfg_msw */
-       0xFFFF,                 /* 02 disc_enable */
-       0xFFFF,                 /* 03 wdtr_able */
-       0x5555,                 /* 04 sdtr_speed1 */
-       0xFFFF,                 /* 05 start_motor */
-       0xFFFF,                 /* 06 tagqng_able */
-       0xFFFF,                 /* 07 bios_scan */
-       0,                      /* 08 scam_tolerant */
-       7,                      /* 09 adapter_scsi_id */
-       0,                      /*    bios_boot_delay */
-       3,                      /* 10 scsi_reset_delay */
-       0,                      /*    bios_id_lun */
-       0,                      /* 11 termination_se */
-       0,                      /*    termination_lvd */
-       0xFFE7,                 /* 12 bios_ctrl */
-       0x5555,                 /* 13 sdtr_speed2 */
-       0x5555,                 /* 14 sdtr_speed3 */
-       ASC_DEF_MAX_HOST_QNG,   /* 15 max_host_qng */
-       ASC_DEF_MAX_DVC_QNG,    /*    max_dvc_qng */
-       0,                      /* 16 dvc_cntl */
-       0x5555,                 /* 17 sdtr_speed4 */
-       0,                      /* 18 serial_number_word1 */
-       0,                      /* 19 serial_number_word2 */
-       0,                      /* 20 serial_number_word3 */
-       0,                      /* 21 check_sum */
-       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-       ,                       /* 22-29 oem_name[16] */
-       0,                      /* 30 dvc_err_code */
-       0,                      /* 31 adv_err_code */
-       0,                      /* 32 adv_err_addr */
-       0,                      /* 33 saved_dvc_err_code */
-       0,                      /* 34 saved_adv_err_code */
-       0,                      /* 35 saved_adv_err_addr */
-       0,                      /* 36 reserved */
-       0,                      /* 37 reserved */
-       0,                      /* 38 reserved */
-       0,                      /* 39 reserved */
-       0,                      /* 40 reserved */
-       0,                      /* 41 reserved */
-       0,                      /* 42 reserved */
-       0,                      /* 43 reserved */
-       0,                      /* 44 reserved */
-       0,                      /* 45 reserved */
-       0,                      /* 46 reserved */
-       0,                      /* 47 reserved */
-       0,                      /* 48 reserved */
-       0,                      /* 49 reserved */
-       0,                      /* 50 reserved */
-       0,                      /* 51 reserved */
-       0,                      /* 52 reserved */
-       0,                      /* 53 reserved */
-       0,                      /* 54 reserved */
-       0,                      /* 55 reserved */
-       0,                      /* 56 cisptr_lsw */
-       0,                      /* 57 cisprt_msw */
-       PCI_VENDOR_ID_ASP,      /* 58 subsysvid */
-       PCI_DEVICE_ID_38C1600_REV1,     /* 59 subsysid */
-       0,                      /* 60 reserved */
-       0,                      /* 61 reserved */
-       0,                      /* 62 reserved */
-       0                       /* 63 reserved */
-};
+       iop_base = asc_dvc->iop_base;
+       int_pending = FALSE;
 
-static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
-       0,                      /* 00 cfg_lsw */
-       0,                      /* 01 cfg_msw */
-       0,                      /* 02 disc_enable */
-       0,                      /* 03 wdtr_able */
-       0,                      /* 04 sdtr_speed1 */
-       0,                      /* 05 start_motor */
-       0,                      /* 06 tagqng_able */
-       0,                      /* 07 bios_scan */
-       0,                      /* 08 scam_tolerant */
-       1,                      /* 09 adapter_scsi_id */
-       1,                      /*    bios_boot_delay */
-       1,                      /* 10 scsi_reset_delay */
-       1,                      /*    bios_id_lun */
-       1,                      /* 11 termination_se */
-       1,                      /*    termination_lvd */
-       0,                      /* 12 bios_ctrl */
-       0,                      /* 13 sdtr_speed2 */
-       0,                      /* 14 sdtr_speed3 */
-       1,                      /* 15 max_host_qng */
-       1,                      /*    max_dvc_qng */
-       0,                      /* 16 dvc_cntl */
-       0,                      /* 17 sdtr_speed4 */
-       0,                      /* 18 serial_number_word1 */
-       0,                      /* 19 serial_number_word2 */
-       0,                      /* 20 serial_number_word3 */
-       0,                      /* 21 check_sum */
-       {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
-       ,                       /* 22-29 oem_name[16] */
-       0,                      /* 30 dvc_err_code */
-       0,                      /* 31 adv_err_code */
-       0,                      /* 32 adv_err_addr */
-       0,                      /* 33 saved_dvc_err_code */
-       0,                      /* 34 saved_adv_err_code */
-       0,                      /* 35 saved_adv_err_addr */
-       0,                      /* 36 reserved */
-       0,                      /* 37 reserved */
-       0,                      /* 38 reserved */
-       0,                      /* 39 reserved */
-       0,                      /* 40 reserved */
-       0,                      /* 41 reserved */
-       0,                      /* 42 reserved */
-       0,                      /* 43 reserved */
-       0,                      /* 44 reserved */
-       0,                      /* 45 reserved */
-       0,                      /* 46 reserved */
-       0,                      /* 47 reserved */
-       0,                      /* 48 reserved */
-       0,                      /* 49 reserved */
-       0,                      /* 50 reserved */
-       0,                      /* 51 reserved */
-       0,                      /* 52 reserved */
-       0,                      /* 53 reserved */
-       0,                      /* 54 reserved */
-       0,                      /* 55 reserved */
-       0,                      /* 56 cisptr_lsw */
-       0,                      /* 57 cisprt_msw */
-       0,                      /* 58 subsysvid */
-       0,                      /* 59 subsysid */
-       0,                      /* 60 reserved */
-       0,                      /* 61 reserved */
-       0,                      /* 62 reserved */
-       0                       /* 63 reserved */
-};
+       if (AscIsIntPending(iop_base) == 0)
+               return int_pending;
+
+       if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
+               return ERR;
+       }
+       if (asc_dvc->in_critical_cnt != 0) {
+               AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
+               return ERR;
+       }
+       if (asc_dvc->is_in_int) {
+               AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
+               return ERR;
+       }
+       asc_dvc->is_in_int = TRUE;
+       ctrl_reg = AscGetChipControl(iop_base);
+       saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
+                                      CC_SINGLE_STEP | CC_DIAG | CC_TEST));
+       chipstat = AscGetChipStatus(iop_base);
+       if (chipstat & CSW_SCSI_RESET_LATCH) {
+               if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+                       int i = 10;
+                       int_pending = TRUE;
+                       asc_dvc->sdtr_done = 0;
+                       saved_ctrl_reg &= (uchar)(~CC_HALT);
+                       while ((AscGetChipStatus(iop_base) &
+                               CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
+                               mdelay(100);
+                       }
+                       AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
+                       AscSetChipControl(iop_base, CC_HALT);
+                       AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+                       AscSetChipStatus(iop_base, 0);
+                       chipstat = AscGetChipStatus(iop_base);
+               }
+       }
+       saved_ram_addr = AscGetChipLramAddr(iop_base);
+       host_flag = AscReadLramByte(iop_base,
+                                   ASCV_HOST_FLAG_B) &
+           (uchar)(~ASC_HOST_FLAG_IN_ISR);
+       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+                        (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
+       if ((chipstat & CSW_INT_PENDING) || (int_pending)) {
+               AscAckInterrupt(iop_base);
+               int_pending = TRUE;
+               if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
+                       if (AscIsrChipHalted(asc_dvc) == ERR) {
+                               goto ISR_REPORT_QDONE_FATAL_ERROR;
+                       } else {
+                               saved_ctrl_reg &= (uchar)(~CC_HALT);
+                       }
+               } else {
+ ISR_REPORT_QDONE_FATAL_ERROR:
+                       if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
+                               while (((status =
+                                        AscIsrQDone(asc_dvc)) & 0x01) != 0) {
+                               }
+                       } else {
+                               do {
+                                       if ((status =
+                                            AscIsrQDone(asc_dvc)) == 1) {
+                                               break;
+                                       }
+                               } while (status == 0x11);
+                       }
+                       if ((status & 0x80) != 0)
+                               int_pending = ERR;
+               }
+       }
+       AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+       AscSetChipLramAddr(iop_base, saved_ram_addr);
+       AscSetChipControl(iop_base, saved_ctrl_reg);
+       asc_dvc->is_in_int = FALSE;
+       return int_pending;
+}
 
 /*
- * Initialize the ADV_DVC_VAR structure.
+ * advansys_reset()
  *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ * Reset the bus associated with the command 'scp'.
  *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * This function runs its own thread. Interrupts must be blocked but
+ * sleeping is allowed and no locking other than for host structures is
+ * required. Returns SUCCESS or FAILED.
  */
-static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+static int advansys_reset(struct scsi_cmnd *scp)
 {
-       ushort warn_code;
-       AdvPortAddr iop_base;
-       uchar pci_cmd_reg;
+       struct Scsi_Host *shost = scp->device->host;
+       struct asc_board *boardp = shost_priv(shost);
+       unsigned long flags;
        int status;
+       int ret = SUCCESS;
 
-       warn_code = 0;
-       asc_dvc->err_code = 0;
-       iop_base = asc_dvc->iop_base;
-
-       /*
-        * PCI Command Register
-        *
-        * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
-        * I/O Space Control, Memory Space Control and Bus Master Control bits.
-        */
-
-       if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
-                                                   AscPCIConfigCommandRegister))
-            & AscPCICmdRegBits_BusMastering)
-           != AscPCICmdRegBits_BusMastering) {
-               pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
-
-               DvcAdvWritePCIConfigByte(asc_dvc,
-                                        AscPCIConfigCommandRegister,
-                                        pci_cmd_reg);
-
-               if (((DvcAdvReadPCIConfigByte
-                     (asc_dvc, AscPCIConfigCommandRegister))
-                    & AscPCICmdRegBits_BusMastering)
-                   != AscPCICmdRegBits_BusMastering) {
-                       warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-               }
-       }
+       ASC_DBG(1, "0x%p\n", scp);
 
-       /*
-        * PCI Latency Timer
-        *
-        * If the "latency timer" register is 0x20 or above, then we don't need
-        * to change it.  Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
-        * comes up less than 0x20).
-        */
-       if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
-               DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
-                                        0x20);
-               if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
-                   0x20) {
-                       warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-               }
-       }
+       ASC_STATS(shost, reset);
 
-       /*
-        * Save the state of the PCI Configuration Command Register
-        * "Parity Error Response Control" Bit. If the bit is clear (0),
-        * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
-        * DMA parity errors.
-        */
-       asc_dvc->cfg->control_flag = 0;
-       if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
-             & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
-               asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
-       }
+       scmd_printk(KERN_INFO, scp, "SCSI bus reset started...\n");
 
-       asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
-           ADV_LIB_VERSION_MINOR;
-       asc_dvc->cfg->chip_version =
-           AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+       if (ASC_NARROW_BOARD(boardp)) {
+               ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
 
-       ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
-                (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
-                (ushort)ADV_CHIP_ID_BYTE);
+               /* Reset the chip and SCSI bus. */
+               ASC_DBG(1, "before AscInitAsc1000Driver()\n");
+               status = AscInitAsc1000Driver(asc_dvc);
 
-       ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
-                (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
-                (ushort)ADV_CHIP_ID_WORD);
+               /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+               if (asc_dvc->err_code) {
+                       scmd_printk(KERN_INFO, scp, "SCSI bus reset error: "
+                                   "0x%x\n", asc_dvc->err_code);
+                       ret = FAILED;
+               } else if (status) {
+                       scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: "
+                                   "0x%x\n", status);
+               } else {
+                       scmd_printk(KERN_INFO, scp, "SCSI bus reset "
+                                   "successful\n");
+               }
 
-       /*
-        * Reset the chip to start and allow register writes.
-        */
-       if (AdvFindSignature(iop_base) == 0) {
-               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-               return ADV_ERROR;
+               ASC_DBG(1, "after AscInitAsc1000Driver()\n");
+               spin_lock_irqsave(shost->host_lock, flags);
        } else {
                /*
-                * The caller must set 'chip_type' to a valid setting.
+                * If the suggest reset bus flags are set, then reset the bus.
+                * Otherwise only reset the device.
                 */
-               if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
-                   asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
-                   asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
-                       asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
-                       return ADV_ERROR;
-               }
+               ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
 
                /*
-                * Reset Chip.
+                * Reset the target's SCSI bus.
                 */
-               AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
-                                    ADV_CTRL_REG_CMD_RESET);
-               DvcSleepMilliSecond(100);
-               AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
-                                    ADV_CTRL_REG_CMD_WR_IO_REG);
-
-               if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
-                       if ((status =
-                            AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
-                               return ADV_ERROR;
-                       }
-               } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
-                       if ((status =
-                            AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
-                               return ADV_ERROR;
-                       }
-               } else {
-                       if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
-                               return ADV_ERROR;
-                       }
+               ASC_DBG(1, "before AdvResetChipAndSB()\n");
+               switch (AdvResetChipAndSB(adv_dvc)) {
+               case ASC_TRUE:
+                       scmd_printk(KERN_INFO, scp, "SCSI bus reset "
+                                   "successful\n");
+                       break;
+               case ASC_FALSE:
+               default:
+                       scmd_printk(KERN_INFO, scp, "SCSI bus reset error\n");
+                       ret = FAILED;
+                       break;
                }
-               warn_code |= status;
+               spin_lock_irqsave(shost->host_lock, flags);
+               AdvISR(adv_dvc);
        }
 
-       return warn_code;
+       /* Save the time of the most recently completed reset. */
+       boardp->last_reset = jiffies;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
+       ASC_DBG(1, "ret %d\n", ret);
+
+       return ret;
 }
 
 /*
- * Initialize the ASC-3550.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ * advansys_biosparam()
  *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * Translate disk drive geometry if the "BIOS greater than 1 GB"
+ * support is enabled for a drive.
  *
- * Needed after initialization for error recovery.
+ * ip (information pointer) is an int array with the following definition:
+ * ip[0]: heads
+ * ip[1]: sectors
+ * ip[2]: cylinders
  */
-static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+static int
+advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+                  sector_t capacity, int ip[])
 {
-       AdvPortAddr iop_base;
-       ushort warn_code;
-       ADV_DCNT sum;
-       int begin_addr;
-       int end_addr;
-       ushort code_sum;
-       int word;
-       int j;
-       int adv_asc3550_expanded_size;
-       ADV_CARR_T *carrp;
-       ADV_DCNT contig_len;
-       ADV_SDCNT buf_size;
-       ADV_PADDR carr_paddr;
-       int i;
-       ushort scsi_cfg1;
-       uchar tid;
-       ushort bios_mem[ASC_MC_BIOSLEN / 2];    /* BIOS RISC Memory 0x40-0x8F. */
-       ushort wdtr_able = 0, sdtr_able, tagqng_able;
-       uchar max_cmd[ADV_MAX_TID + 1];
-
-       /* If there is already an error, don't continue. */
-       if (asc_dvc->err_code != 0) {
-               return ADV_ERROR;
-       }
-
-       /*
-        * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
-        */
-       if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
-               asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
-               return ADV_ERROR;
-       }
-
-       warn_code = 0;
-       iop_base = asc_dvc->iop_base;
-
-       /*
-        * Save the RISC memory BIOS region before writing the microcode.
-        * The BIOS may already be loaded and using its RISC LRAM region
-        * so its region must be saved and restored.
-        *
-        * Note: This code makes the assumption, which is currently true,
-        * that a chip reset does not clear RISC LRAM.
-        */
-       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
-               AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
-                               bios_mem[i]);
-       }
-
-       /*
-        * Save current per TID negotiated values.
-        */
-       if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
-               ushort bios_version, major, minor;
+       struct asc_board *boardp = shost_priv(sdev->host);
 
-               bios_version =
-                   bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
-               major = (bios_version >> 12) & 0xF;
-               minor = (bios_version >> 8) & 0xF;
-               if (major < 3 || (major == 3 && minor == 1)) {
-                       /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
-                       AdvReadWordLram(iop_base, 0x120, wdtr_able);
+       ASC_DBG(1, "begin\n");
+       ASC_STATS(sdev->host, biosparam);
+       if (ASC_NARROW_BOARD(boardp)) {
+               if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+                    ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
+                       ip[0] = 255;
+                       ip[1] = 63;
                } else {
-                       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+                       ip[0] = 64;
+                       ip[1] = 32;
                }
-       }
-       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                               max_cmd[tid]);
-       }
-
-       /*
-        * Load the Microcode
-        *
-        * Write the microcode image to RISC memory starting at address 0.
-        */
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-       /* Assume the following compressed format of the microcode buffer:
-        *
-        *  254 word (508 byte) table indexed by byte code followed
-        *  by the following byte codes:
-        *
-        *    1-Byte Code:
-        *      00: Emit word 0 in table.
-        *      01: Emit word 1 in table.
-        *      .
-        *      FD: Emit word 253 in table.
-        *
-        *    Multi-Byte Code:
-        *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
-        *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
-        */
-       word = 0;
-       for (i = 253 * 2; i < _adv_asc3550_size; i++) {
-               if (_adv_asc3550_buf[i] == 0xff) {
-                       for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
-                               AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                                   _adv_asc3550_buf
-                                                                   [i +
-                                                                    3] << 8) |
-                                                                  _adv_asc3550_buf
-                                                                  [i + 2]));
-                               word++;
-                       }
-                       i += 3;
-               } else if (_adv_asc3550_buf[i] == 0xfe) {
-                       AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                           _adv_asc3550_buf[i +
-                                                                            2]
-                                                           << 8) |
-                                                          _adv_asc3550_buf[i +
-                                                                           1]));
-                       i += 2;
-                       word++;
+       } else {
+               if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+                    BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
+                       ip[0] = 255;
+                       ip[1] = 63;
                } else {
-                       AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                           _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
-                       word++;
+                       ip[0] = 64;
+                       ip[1] = 32;
                }
        }
+       ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+       ASC_DBG(1, "end\n");
+       return 0;
+}
 
-       /*
-        * Set 'word' for later use to clear the rest of memory and save
-        * the expanded mcode size.
-        */
-       word *= 2;
-       adv_asc3550_expanded_size = word;
-
-       /*
-        * Clear the rest of ASC-3550 Internal RAM (8KB).
-        */
-       for (; word < ADV_3550_MEMSIZE; word += 2) {
-               AdvWriteWordAutoIncLram(iop_base, 0);
-       }
-
-       /*
-        * Verify the microcode checksum.
-        */
-       sum = 0;
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
-       for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
-               sum += AdvReadWordAutoIncLram(iop_base);
-       }
-
-       if (sum != _adv_asc3550_chksum) {
-               asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-               return ADV_ERROR;
-       }
-
-       /*
-        * Restore the RISC memory BIOS region.
-        */
-       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
-               AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
-                                bios_mem[i]);
-       }
+/*
+ * First-level interrupt handler.
+ *
+ * 'dev_id' is a pointer to the interrupting adapter's Scsi_Host.
+ */
+static irqreturn_t advansys_interrupt(int irq, void *dev_id)
+{
+       struct Scsi_Host *shost = dev_id;
+       struct asc_board *boardp = shost_priv(shost);
+       irqreturn_t result = IRQ_NONE;
 
-       /*
-        * Calculate and write the microcode code checksum to the microcode
-        * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
-        */
-       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
-       AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
-       code_sum = 0;
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
-       for (word = begin_addr; word < end_addr; word += 2) {
-               code_sum += AdvReadWordAutoIncLram(iop_base);
+       ASC_DBG(2, "boardp 0x%p\n", boardp);
+       spin_lock(shost->host_lock);
+       if (ASC_NARROW_BOARD(boardp)) {
+               if (AscIsIntPending(shost->io_port)) {
+                       result = IRQ_HANDLED;
+                       ASC_STATS(shost, interrupt);
+                       ASC_DBG(1, "before AscISR()\n");
+                       AscISR(&boardp->dvc_var.asc_dvc_var);
+               }
+       } else {
+               ASC_DBG(1, "before AdvISR()\n");
+               if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+                       result = IRQ_HANDLED;
+                       ASC_STATS(shost, interrupt);
+               }
        }
-       AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+       spin_unlock(shost->host_lock);
 
-       /*
-        * Read and save microcode version and date.
-        */
-       AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
-                       asc_dvc->cfg->mcode_date);
-       AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
-                       asc_dvc->cfg->mcode_version);
+       ASC_DBG(1, "end\n");
+       return result;
+}
 
-       /*
-        * Set the chip type to indicate the ASC3550.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+static int AscHostReqRiscHalt(PortAddr iop_base)
+{
+       int count = 0;
+       int sta = 0;
+       uchar saved_stop_code;
 
-       /*
-        * If the PCI Configuration Command Register "Parity Error Response
-        * Control" Bit was clear (0), then set the microcode variable
-        * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
-        * to ignore DMA parity errors.
-        */
-       if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
-               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-               word |= CONTROL_FLAG_IGNORE_PERR;
-               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-       }
+       if (AscIsChipHalted(iop_base))
+               return (1);
+       saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+       AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                        ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
+       do {
+               if (AscIsChipHalted(iop_base)) {
+                       sta = 1;
+                       break;
+               }
+               mdelay(100);
+       } while (count++ < 20);
+       AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+       return (sta);
+}
 
-       /*
-        * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
-        * threshold of 128 bytes. This register is only accessible to the host.
-        */
-       AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-                            START_CTL_EMFU | READ_CMD_MRM);
+static int
+AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
+{
+       int sta = FALSE;
 
-       /*
-        * Microcode operating variables for WDTR, SDTR, and command tag
-        * queuing will be set in AdvInquiryHandling() based on what a
-        * device reports it is capable of in Inquiry byte 7.
-        *
-        * If SCSI Bus Resets have been disabled, then directly set
-        * SDTR and WDTR from the EEPROM configuration. This will allow
-        * the BIOS and warm boot to work without a SCSI bus hang on
-        * the Inquiry caused by host and target mismatched DTR values.
-        * Without the SCSI Bus Reset, before an Inquiry a device can't
-        * be assumed to be in Asynchronous, Narrow mode.
-        */
-       if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
-               AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
-                                asc_dvc->wdtr_able);
-               AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
-                                asc_dvc->sdtr_able);
+       if (AscHostReqRiscHalt(iop_base)) {
+               sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+               AscStartChip(iop_base);
        }
+       return sta;
+}
 
-       /*
-        * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
-        * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
-        * bitmask. These values determine the maximum SDTR speed negotiated
-        * with a device.
-        *
-        * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
-        * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
-        * without determining here whether the device supports SDTR.
-        *
-        * 4-bit speed  SDTR speed name
-        * ===========  ===============
-        * 0000b (0x0)  SDTR disabled
-        * 0001b (0x1)  5 Mhz
-        * 0010b (0x2)  10 Mhz
-        * 0011b (0x3)  20 Mhz (Ultra)
-        * 0100b (0x4)  40 Mhz (LVD/Ultra2)
-        * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
-        * 0110b (0x6)  Undefined
-        * .
-        * 1111b (0xF)  Undefined
-        */
-       word = 0;
-       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-               if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
-                       /* Set Ultra speed for TID 'tid'. */
-                       word |= (0x3 << (4 * (tid % 4)));
-               } else {
-                       /* Set Fast speed for TID 'tid'. */
-                       word |= (0x2 << (4 * (tid % 4)));
-               }
-               if (tid == 3) { /* Check if done with sdtr_speed1. */
-                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
-                       word = 0;
-               } else if (tid == 7) {  /* Check if done with sdtr_speed2. */
-                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
-                       word = 0;
-               } else if (tid == 11) { /* Check if done with sdtr_speed3. */
-                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
-                       word = 0;
-               } else if (tid == 15) { /* Check if done with sdtr_speed4. */
-                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
-                       /* End of loop. */
-               }
-       }
+static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
+{
+       char type = sdev->type;
+       ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
 
-       /*
-        * Set microcode operating variable for the disconnect per TID bitmask.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
-                        asc_dvc->cfg->disc_enable);
+       if (!(asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN))
+               return;
+       if (asc_dvc->init_sdtr & tid_bits)
+               return;
 
-       /*
-        * Set SCSI_CFG0 Microcode Default Value.
-        *
-        * The microcode will set the SCSI_CFG0 register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-                        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
-                        asc_dvc->chip_scsi_id);
+       if ((type == TYPE_ROM) && (strncmp(sdev->vendor, "HP ", 3) == 0))
+               asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
 
-       /*
-        * Determine SCSI_CFG1 Microcode Default Value.
-        *
-        * The microcode will set the SCSI_CFG1 register using this value
-        * after it is started below.
-        */
+       asc_dvc->pci_fix_asyn_xfer |= tid_bits;
+       if ((type == TYPE_PROCESSOR) || (type == TYPE_SCANNER) ||
+           (type == TYPE_ROM) || (type == TYPE_TAPE))
+               asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
 
-       /* Read current SCSI_CFG1 Register value. */
-       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+       if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
+               AscSetRunChipSynRegAtID(asc_dvc->iop_base, sdev->id,
+                                       ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+}
 
-       /*
-        * If all three connectors are in use, return an error.
-        */
-       if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
-           (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
-               asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
-               return ADV_ERROR;
-       }
+static void
+advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
+{
+       ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
+       ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
 
-       /*
-        * If the internal narrow cable is reversed all of the SCSI_CTRL
-        * register signals will be set. Check for and return an error if
-        * this condition is found.
-        */
-       if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
-               asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
-               return ADV_ERROR;
-       }
+       if (sdev->lun == 0) {
+               ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
+               if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
+                       asc_dvc->init_sdtr |= tid_bit;
+               } else {
+                       asc_dvc->init_sdtr &= ~tid_bit;
+               }
 
-       /*
-        * If this is a differential board and a single-ended device
-        * is attached to one of the connectors, return an error.
-        */
-       if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
-               asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
-               return ADV_ERROR;
+               if (orig_init_sdtr != asc_dvc->init_sdtr)
+                       AscAsyncFix(asc_dvc, sdev);
        }
 
-       /*
-        * If automatic termination control is enabled, then set the
-        * termination value based on a table listed in a_condor.h.
-        *
-        * If manual termination was specified with an EEPROM setting
-        * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
-        * is ready to be 'ored' into SCSI_CFG1.
-        */
-       if (asc_dvc->cfg->termination == 0) {
-               /*
-                * The software always controls termination by setting TERM_CTL_SEL.
-                * If TERM_CTL_SEL were set to 0, the hardware would set termination.
-                */
-               asc_dvc->cfg->termination |= TERM_CTL_SEL;
-
-               switch (scsi_cfg1 & CABLE_DETECT) {
-                       /* TERM_CTL_H: on, TERM_CTL_L: on */
-               case 0x3:
-               case 0x7:
-               case 0xB:
-               case 0xD:
-               case 0xE:
-               case 0xF:
-                       asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
-                       break;
+       if (sdev->tagged_supported) {
+               if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
+                       if (sdev->lun == 0) {
+                               asc_dvc->cfg->can_tagged_qng |= tid_bit;
+                               asc_dvc->use_tagged_qng |= tid_bit;
+                       }
+                       scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+                                               asc_dvc->max_dvc_qng[sdev->id]);
+               }
+       } else {
+               if (sdev->lun == 0) {
+                       asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
+                       asc_dvc->use_tagged_qng &= ~tid_bit;
+               }
+               scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+       }
 
-                       /* TERM_CTL_H: on, TERM_CTL_L: off */
-               case 0x1:
-               case 0x5:
-               case 0x9:
-               case 0xA:
-               case 0xC:
-                       asc_dvc->cfg->termination |= TERM_CTL_H;
-                       break;
+       if ((sdev->lun == 0) &&
+           (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
+               AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
+                                asc_dvc->cfg->disc_enable);
+               AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
+                                asc_dvc->use_tagged_qng);
+               AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
+                                asc_dvc->cfg->can_tagged_qng);
 
-                       /* TERM_CTL_H: off, TERM_CTL_L: off */
-               case 0x2:
-               case 0x6:
-                       break;
-               }
+               asc_dvc->max_dvc_qng[sdev->id] =
+                                       asc_dvc->cfg->max_tag_qng[sdev->id];
+               AscWriteLramByte(asc_dvc->iop_base,
+                                (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
+                                asc_dvc->max_dvc_qng[sdev->id]);
        }
+}
 
-       /*
-        * Clear any set TERM_CTL_H and TERM_CTL_L bits.
-        */
-       scsi_cfg1 &= ~TERM_CTL;
+/*
+ * Wide Transfers
+ *
+ * If the EEPROM enabled WDTR for the device and the device supports wide
+ * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
+ * write the new value to the microcode.
+ */
+static void
+advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
+{
+       unsigned short cfg_word;
+       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+       if ((cfg_word & tidmask) != 0)
+               return;
 
-       /*
-        * Invert the TERM_CTL_H and TERM_CTL_L bits and then
-        * set 'scsi_cfg1'. The TERM_POL bit does not need to be
-        * referenced, because the hardware internally inverts
-        * the Termination High and Low bits if TERM_POL is set.
-        */
-       scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+       cfg_word |= tidmask;
+       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
 
        /*
-        * Set SCSI_CFG1 Microcode Default Value
-        *
-        * Set filter value and possibly modified termination control
-        * bits in the Microcode SCSI_CFG1 Register Value.
-        *
-        * The microcode will set the SCSI_CFG1 register using this value
-        * after it is started below.
+        * Clear the microcode SDTR and WDTR negotiation done indicators for
+        * the target to cause it to negotiate with the new setting set above.
+        * WDTR when accepted causes the target to enter asynchronous mode, so
+        * SDTR must be negotiated.
         */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
-                        FLTR_DISABLE | scsi_cfg1);
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+       cfg_word &= ~tidmask;
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+       AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+       cfg_word &= ~tidmask;
+       AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+}
 
-       /*
-        * Set MEM_CFG Microcode Default Value
-        *
-        * The microcode will set the MEM_CFG register using this value
-        * after it is started below.
-        *
-        * MEM_CFG may be accessed as a word or byte, but only bits 0-7
-        * are defined.
-        *
-        * ASC-3550 has 8KB internal memory.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-                        BIOS_EN | RAM_SZ_8KB);
+/*
+ * Synchronous Transfers
+ *
+ * If the EEPROM enabled SDTR for the device and the device
+ * supports synchronous transfers, then turn on the device's
+ * 'sdtr_able' bit. Write the new value to the microcode.
+ */
+static void
+advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
+{
+       unsigned short cfg_word;
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+       if ((cfg_word & tidmask) != 0)
+               return;
 
-       /*
-        * Set SEL_MASK Microcode Default Value
-        *
-        * The microcode will set the SEL_MASK register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+       cfg_word |= tidmask;
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
 
        /*
-        * Build carrier freelist.
-        *
-        * Driver must have already allocated memory and set 'carrier_buf'.
+        * Clear the microcode "SDTR negotiation" done indicator for the
+        * target to cause it to negotiate with the new setting set above.
         */
-       ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+       AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+       cfg_word &= ~tidmask;
+       AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+}
 
-       carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
-       asc_dvc->carr_freelist = NULL;
-       if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
-               buf_size = ADV_CARRIER_BUFSIZE;
-       } else {
-               buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
-       }
+/*
+ * PPR (Parallel Protocol Request) Capable
+ *
+ * If the device supports DT mode, then it must be PPR capable.
+ * The PPR message will be used in place of the SDTR and WDTR
+ * messages to negotiate synchronous speed and offset, transfer
+ * width, and protocol options.
+ */
+static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
+                               AdvPortAddr iop_base, unsigned short tidmask)
+{
+       AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
+       adv_dvc->ppr_able |= tidmask;
+       AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
+}
 
-       do {
+static void
+advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
+{
+       AdvPortAddr iop_base = adv_dvc->iop_base;
+       unsigned short tidmask = 1 << sdev->id;
+
+       if (sdev->lun == 0) {
                /*
-                * Get physical address of the carrier 'carrp'.
+                * Handle WDTR, SDTR, and Tag Queuing. If the feature
+                * is enabled in the EEPROM and the device supports the
+                * feature, then enable it in the microcode.
                 */
-               contig_len = sizeof(ADV_CARR_T);
-               carr_paddr =
-                   cpu_to_le32(DvcGetPhyAddr
-                               (asc_dvc, NULL, (uchar *)carrp,
-                                (ADV_SDCNT *)&contig_len,
-                                ADV_IS_CARRIER_FLAG));
 
-               buf_size -= sizeof(ADV_CARR_T);
+               if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
+                       advansys_wide_enable_wdtr(iop_base, tidmask);
+               if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
+                       advansys_wide_enable_sdtr(iop_base, tidmask);
+               if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
+                       advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
 
                /*
-                * If the current carrier is not physically contiguous, then
-                * maybe there was a page crossing. Try the next carrier aligned
-                * start address.
+                * Tag Queuing is disabled for the BIOS which runs in polled
+                * mode and would see no benefit from Tag Queuing. Also by
+                * disabling Tag Queuing in the BIOS devices with Tag Queuing
+                * bugs will at least work with the BIOS.
                 */
-               if (contig_len < sizeof(ADV_CARR_T)) {
-                       carrp++;
-                       continue;
+               if ((adv_dvc->tagqng_able & tidmask) &&
+                   sdev->tagged_supported) {
+                       unsigned short cfg_word;
+                       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+                       cfg_word |= tidmask;
+                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+                                        cfg_word);
+                       AdvWriteByteLram(iop_base,
+                                        ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
+                                        adv_dvc->max_dvc_qng);
                }
+       }
 
-               carrp->carr_pa = carr_paddr;
-               carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+       if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
+               scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+                                       adv_dvc->max_dvc_qng);
+       } else {
+               scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+       }
+}
 
-               /*
-                * Insert the carrier at the beginning of the freelist.
-                */
-               carrp->next_vpa =
-                   cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-               asc_dvc->carr_freelist = carrp;
+/*
+ * Set the number of commands to queue per device for the
+ * specified host adapter.
+ */
+static int advansys_slave_configure(struct scsi_device *sdev)
+{
+       struct asc_board *boardp = shost_priv(sdev->host);
 
-               carrp++;
-       }
-       while (buf_size > 0);
+       if (ASC_NARROW_BOARD(boardp))
+               advansys_narrow_slave_configure(sdev,
+                                               &boardp->dvc_var.asc_dvc_var);
+       else
+               advansys_wide_slave_configure(sdev,
+                                               &boardp->dvc_var.adv_dvc_var);
 
-       /*
-        * Set-up the Host->RISC Initiator Command Queue (ICQ).
-        */
+       return 0;
+}
 
-       if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
-               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-               return ADV_ERROR;
-       }
-       asc_dvc->carr_freelist = (ADV_CARR_T *)
-           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
+{
+       struct asc_board *board = shost_priv(scp->device->host);
+       scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
+                               sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+       dma_cache_sync(board->dev, scp->sense_buffer,
+                               sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+       return cpu_to_le32(scp->SCp.dma_handle);
+}
 
-       /*
-        * The first command issued will be placed in the stopper carrier.
-        */
-       asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+                       struct asc_scsi_q *asc_scsi_q)
+{
+       struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+       int use_sg;
 
-       /*
-        * Set RISC ICQ physical address start value.
-        */
-       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+       memset(asc_scsi_q, 0, sizeof(*asc_scsi_q));
 
        /*
-        * Set-up the RISC->Host Initiator Response Queue (IRQ).
+        * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
         */
-       if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
-               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-               return ADV_ERROR;
+       asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp);
+       if (asc_scsi_q->q2.srb_ptr == BAD_SRB) {
+               scp->result = HOST_BYTE(DID_SOFT_ERROR);
+               return ASC_ERROR;
        }
-       asc_dvc->carr_freelist = (ADV_CARR_T *)
-           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
        /*
-        * The first command completed by the RISC will be placed in
-        * the stopper.
-        *
-        * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
-        * completed the RISC will set the ASC_RQ_STOPPER bit.
+        * Build the ASC_SCSI_Q request.
         */
-       asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+       asc_scsi_q->cdbptr = &scp->cmnd[0];
+       asc_scsi_q->q2.cdb_len = scp->cmd_len;
+       asc_scsi_q->q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
+       asc_scsi_q->q1.target_lun = scp->device->lun;
+       asc_scsi_q->q2.target_ix =
+           ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
+       asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
+       asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
 
        /*
-        * Set RISC IRQ physical address start value.
+        * If there are any outstanding requests for the current target,
+        * then every 255th request send an ORDERED request. This heuristic
+        * tries to retain the benefit of request sorting while preventing
+        * request starvation. 255 is the max number of tags or pending commands
+        * a device may have outstanding.
+        *
+        * The request count is incremented below for every successfully
+        * started request.
+        *
         */
-       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
-       asc_dvc->carr_pending_cnt = 0;
+       if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) &&
+           (boardp->reqcnt[scp->device->id] % 255) == 0) {
+               asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG;
+       } else {
+               asc_scsi_q->q2.tag_code = MSG_SIMPLE_TAG;
+       }
 
-       AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-                            (ADV_INTR_ENABLE_HOST_INTR |
-                             ADV_INTR_ENABLE_GLOBAL_INTR));
+       /* Build ASC_SCSI_Q */
+       use_sg = scsi_dma_map(scp);
+       if (use_sg != 0) {
+               int sgcnt;
+               struct scatterlist *slp;
+               struct asc_sg_head *asc_sg_head;
 
-       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
-       AdvWriteWordRegister(iop_base, IOPW_PC, word);
+               if (use_sg > scp->device->host->sg_tablesize) {
+                       scmd_printk(KERN_ERR, scp, "use_sg %d > "
+                               "sg_tablesize %d\n", use_sg,
+                               scp->device->host->sg_tablesize);
+                       scsi_dma_unmap(scp);
+                       scp->result = HOST_BYTE(DID_ERROR);
+                       return ASC_ERROR;
+               }
 
-       /* finally, finally, gentlemen, start your engine */
-       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+               asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) +
+                       use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC);
+               if (!asc_sg_head) {
+                       scsi_dma_unmap(scp);
+                       scp->result = HOST_BYTE(DID_SOFT_ERROR);
+                       return ASC_ERROR;
+               }
+
+               asc_scsi_q->q1.cntl |= QC_SG_HEAD;
+               asc_scsi_q->sg_head = asc_sg_head;
+               asc_scsi_q->q1.data_cnt = 0;
+               asc_scsi_q->q1.data_addr = 0;
+               /* This is a byte value, otherwise it would need to be swapped. */
+               asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg;
+               ASC_STATS_ADD(scp->device->host, xfer_elem,
+                             asc_sg_head->entry_cnt);
 
-       /*
-        * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-        * Resets should be performed. The RISC has to be running
-        * to issue a SCSI Bus Reset.
-        */
-       if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
                /*
-                * If the BIOS Signature is present in memory, restore the
-                * BIOS Handshake Configuration Table and do not perform
-                * a SCSI Bus Reset.
+                * Convert scatter-gather list into ASC_SG_HEAD list.
                 */
-               if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
-                   0x55AA) {
+               scsi_for_each_sg(scp, slp, use_sg, sgcnt) {
+                       asc_sg_head->sg_list[sgcnt].addr =
+                           cpu_to_le32(sg_dma_address(slp));
+                       asc_sg_head->sg_list[sgcnt].bytes =
+                           cpu_to_le32(sg_dma_len(slp));
+                       ASC_STATS_ADD(scp->device->host, xfer_sect,
+                                     DIV_ROUND_UP(sg_dma_len(slp), 512));
+               }
+       }
+
+       ASC_STATS(scp->device->host, xfer_cnt);
+
+       ASC_DBG_PRT_ASC_SCSI_Q(2, asc_scsi_q);
+       ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+       return ASC_NOERROR;
+}
+
+/*
+ * Build scatter-gather list for Adv Library (Wide Board).
+ *
+ * Additional ADV_SG_BLOCK structures will need to be allocated
+ * if the total number of scatter-gather elements exceeds
+ * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
+ * assumed to be physically contiguous.
+ *
+ * Return:
+ *      ADV_SUCCESS(1) - SG List successfully created
+ *      ADV_ERROR(-1) - SG List creation failed
+ */
+static int
+adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
+              int use_sg)
+{
+       adv_sgblk_t *sgblkp;
+       ADV_SCSI_REQ_Q *scsiqp;
+       struct scatterlist *slp;
+       int sg_elem_cnt;
+       ADV_SG_BLOCK *sg_block, *prev_sg_block;
+       ADV_PADDR sg_block_paddr;
+       int i;
+
+       scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+       slp = scsi_sglist(scp);
+       sg_elem_cnt = use_sg;
+       prev_sg_block = NULL;
+       reqp->sgblkp = NULL;
+
+       for (;;) {
+               /*
+                * Allocate a 'adv_sgblk_t' structure from the board free
+                * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
+                * (15) scatter-gather elements.
+                */
+               if ((sgblkp = boardp->adv_sgblkp) == NULL) {
+                       ASC_DBG(1, "no free adv_sgblk_t\n");
+                       ASC_STATS(scp->device->host, adv_build_nosg);
+
                        /*
-                        * Restore per TID negotiated values.
+                        * Allocation failed. Free 'adv_sgblk_t' structures
+                        * already allocated for the request.
                         */
-                       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
-                                        tagqng_able);
-                       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-                               AdvWriteByteLram(iop_base,
-                                                ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                                                max_cmd[tid]);
+                       while ((sgblkp = reqp->sgblkp) != NULL) {
+                               /* Remove 'sgblkp' from the request list. */
+                               reqp->sgblkp = sgblkp->next_sgblkp;
+
+                               /* Add 'sgblkp' to the board free list. */
+                               sgblkp->next_sgblkp = boardp->adv_sgblkp;
+                               boardp->adv_sgblkp = sgblkp;
                        }
+                       return ASC_BUSY;
+               }
+
+               /* Complete 'adv_sgblk_t' board allocation. */
+               boardp->adv_sgblkp = sgblkp->next_sgblkp;
+               sgblkp->next_sgblkp = NULL;
+
+               /*
+                * Get 8 byte aligned virtual and physical addresses
+                * for the allocated ADV_SG_BLOCK structure.
+                */
+               sg_block = (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
+               sg_block_paddr = virt_to_bus(sg_block);
+
+               /*
+                * Check if this is the first 'adv_sgblk_t' for the
+                * request.
+                */
+               if (reqp->sgblkp == NULL) {
+                       /* Request's first scatter-gather block. */
+                       reqp->sgblkp = sgblkp;
+
+                       /*
+                        * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
+                        * address pointers.
+                        */
+                       scsiqp->sg_list_ptr = sg_block;
+                       scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
                } else {
-                       if (AdvResetSB(asc_dvc) != ADV_TRUE) {
-                               warn_code = ASC_WARN_BUSRESET_ERROR;
+                       /* Request's second or later scatter-gather block. */
+                       sgblkp->next_sgblkp = reqp->sgblkp;
+                       reqp->sgblkp = sgblkp;
+
+                       /*
+                        * Point the previous ADV_SG_BLOCK structure to
+                        * the newly allocated ADV_SG_BLOCK structure.
+                        */
+                       prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
+               }
+
+               for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
+                       sg_block->sg_list[i].sg_addr =
+                                       cpu_to_le32(sg_dma_address(slp));
+                       sg_block->sg_list[i].sg_count =
+                                       cpu_to_le32(sg_dma_len(slp));
+                       ASC_STATS_ADD(scp->device->host, xfer_sect,
+                                     DIV_ROUND_UP(sg_dma_len(slp), 512));
+
+                       if (--sg_elem_cnt == 0) {       /* Last ADV_SG_BLOCK and scatter-gather entry. */
+                               sg_block->sg_cnt = i + 1;
+                               sg_block->sg_ptr = 0L;  /* Last ADV_SG_BLOCK in list. */
+                               return ADV_SUCCESS;
                        }
+                       slp++;
                }
+               sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
+               prev_sg_block = sg_block;
        }
-
-       return warn_code;
 }
 
 /*
- * Initialize the ASC-38C0800.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ * Build a request structure for the Adv Library (Wide Board).
  *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * If an adv_req_t can not be allocated to issue the request,
+ * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
  *
- * Needed after initialization for error recovery.
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
+ * microcode for DMA addresses or math operations are byte swapped
+ * to little-endian order.
  */
-static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+static int
+adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+             ADV_SCSI_REQ_Q **adv_scsiqpp)
 {
-       AdvPortAddr iop_base;
-       ushort warn_code;
-       ADV_DCNT sum;
-       int begin_addr;
-       int end_addr;
-       ushort code_sum;
-       int word;
-       int j;
-       int adv_asc38C0800_expanded_size;
-       ADV_CARR_T *carrp;
-       ADV_DCNT contig_len;
-       ADV_SDCNT buf_size;
-       ADV_PADDR carr_paddr;
+       adv_req_t *reqp;
+       ADV_SCSI_REQ_Q *scsiqp;
        int i;
-       ushort scsi_cfg1;
-       uchar byte;
-       uchar tid;
-       ushort bios_mem[ASC_MC_BIOSLEN / 2];    /* BIOS RISC Memory 0x40-0x8F. */
-       ushort wdtr_able, sdtr_able, tagqng_able;
-       uchar max_cmd[ADV_MAX_TID + 1];
-
-       /* If there is already an error, don't continue. */
-       if (asc_dvc->err_code != 0) {
-               return ADV_ERROR;
-       }
+       int ret;
+       int use_sg;
 
        /*
-        * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+        * Allocate an adv_req_t structure from the board to execute
+        * the command.
         */
-       if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
-               asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
-               return ADV_ERROR;
+       if (boardp->adv_reqp == NULL) {
+               ASC_DBG(1, "no free adv_req_t\n");
+               ASC_STATS(scp->device->host, adv_build_noreq);
+               return ASC_BUSY;
+       } else {
+               reqp = boardp->adv_reqp;
+               boardp->adv_reqp = reqp->next_reqp;
+               reqp->next_reqp = NULL;
        }
 
-       warn_code = 0;
-       iop_base = asc_dvc->iop_base;
+       /*
+        * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+        */
+       scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
 
        /*
-        * Save the RISC memory BIOS region before writing the microcode.
-        * The BIOS may already be loaded and using its RISC LRAM region
-        * so its region must be saved and restored.
-        *
-        * Note: This code makes the assumption, which is currently true,
-        * that a chip reset does not clear RISC LRAM.
+        * Initialize the structure.
         */
-       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
-               AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
-                               bios_mem[i]);
-       }
+       scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
 
        /*
-        * Save current per TID negotiated values.
+        * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
         */
-       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                               max_cmd[tid]);
-       }
+       scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp);
 
        /*
-        * RAM BIST (RAM Built-In Self Test)
-        *
-        * Address : I/O base + offset 0x38h register (byte).
-        * Function: Bit 7-6(RW) : RAM mode
-        *                          Normal Mode   : 0x00
-        *                          Pre-test Mode : 0x40
-        *                          RAM Test Mode : 0x80
-        *           Bit 5       : unused
-        *           Bit 4(RO)   : Done bit
-        *           Bit 3-0(RO) : Status
-        *                          Host Error    : 0x08
-        *                          Int_RAM Error : 0x04
-        *                          RISC Error    : 0x02
-        *                          SCSI Error    : 0x01
-        *                          No Error      : 0x00
-        *
-        * Note: RAM BIST code should be put right here, before loading the
-        * microcode and after saving the RISC memory BIOS region.
+        * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
         */
+       reqp->cmndp = scp;
 
        /*
-        * LRAM Pre-test
-        *
-        * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
-        * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
-        * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
-        * to NORMAL_MODE, return an error too.
+        * Build the ADV_SCSI_REQ_Q request.
         */
-       for (i = 0; i < 2; i++) {
-               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
-               DvcSleepMilliSecond(10);        /* Wait for 10ms before reading back. */
-               byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-               if ((byte & RAM_TEST_DONE) == 0
-                   || (byte & 0x0F) != PRE_TEST_VALUE) {
-                       asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-                       return ADV_ERROR;
+
+       /* Set CDB length and copy it to the request structure.  */
+       scsiqp->cdb_len = scp->cmd_len;
+       /* Copy first 12 CDB bytes to cdb[]. */
+       for (i = 0; i < scp->cmd_len && i < 12; i++) {
+               scsiqp->cdb[i] = scp->cmnd[i];
+       }
+       /* Copy last 4 CDB bytes, if present, to cdb16[]. */
+       for (; i < scp->cmd_len; i++) {
+               scsiqp->cdb16[i - 12] = scp->cmnd[i];
+       }
+
+       scsiqp->target_id = scp->device->id;
+       scsiqp->target_lun = scp->device->lun;
+
+       scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+       scsiqp->sense_len = sizeof(scp->sense_buffer);
+
+       /* Build ADV_SCSI_REQ_Q */
+
+       use_sg = scsi_dma_map(scp);
+       if (use_sg == 0) {
+               /* Zero-length transfer */
+               reqp->sgblkp = NULL;
+               scsiqp->data_cnt = 0;
+               scsiqp->vdata_addr = NULL;
+
+               scsiqp->data_addr = 0;
+               scsiqp->sg_list_ptr = NULL;
+               scsiqp->sg_real_addr = 0;
+       } else {
+               if (use_sg > ADV_MAX_SG_LIST) {
+                       scmd_printk(KERN_ERR, scp, "use_sg %d > "
+                                  "ADV_MAX_SG_LIST %d\n", use_sg,
+                                  scp->device->host->sg_tablesize);
+                       scsi_dma_unmap(scp);
+                       scp->result = HOST_BYTE(DID_ERROR);
+
+                       /*
+                        * Free the 'adv_req_t' structure by adding it back
+                        * to the board free list.
+                        */
+                       reqp->next_reqp = boardp->adv_reqp;
+                       boardp->adv_reqp = reqp;
+
+                       return ASC_ERROR;
                }
 
-               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
-               DvcSleepMilliSecond(10);        /* Wait for 10ms before reading back. */
-               if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
-                   != NORMAL_VALUE) {
-                       asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-                       return ADV_ERROR;
+               scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp));
+
+               ret = adv_get_sglist(boardp, reqp, scp, use_sg);
+               if (ret != ADV_SUCCESS) {
+                       /*
+                        * Free the adv_req_t structure by adding it back to
+                        * the board free list.
+                        */
+                       reqp->next_reqp = boardp->adv_reqp;
+                       boardp->adv_reqp = reqp;
+
+                       return ret;
                }
+
+               ASC_STATS_ADD(scp->device->host, xfer_elem, use_sg);
        }
 
-       /*
-        * LRAM Test - It takes about 1.5 ms to run through the test.
-        *
-        * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
-        * If Done bit not set or Status not 0, save register byte, set the
-        * err_code, and return an error.
-        */
-       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
-       DvcSleepMilliSecond(10);        /* Wait for 10ms before checking status. */
+       ASC_STATS(scp->device->host, xfer_cnt);
 
-       byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-       if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
-               /* Get here if Done bit not set or Status not 0. */
-               asc_dvc->bist_err_code = byte;  /* for BIOS display message */
-               asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
-               return ADV_ERROR;
-       }
+       ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+       ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
 
-       /* We need to reset back to normal mode after LRAM test passes. */
-       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+       *adv_scsiqpp = scsiqp;
 
-       /*
-        * Load the Microcode
-        *
-        * Write the microcode image to RISC memory starting at address 0.
-        *
-        */
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+       return ASC_NOERROR;
+}
 
-       /* Assume the following compressed format of the microcode buffer:
-        *
-        *  254 word (508 byte) table indexed by byte code followed
-        *  by the following byte codes:
-        *
-        *    1-Byte Code:
-        *      00: Emit word 0 in table.
-        *      01: Emit word 1 in table.
-        *      .
-        *      FD: Emit word 253 in table.
-        *
-        *    Multi-Byte Code:
-        *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
-        *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
-        */
-       word = 0;
-       for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
-               if (_adv_asc38C0800_buf[i] == 0xff) {
-                       for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
-                               AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                                   _adv_asc38C0800_buf
-                                                                   [i +
-                                                                    3] << 8) |
-                                                                  _adv_asc38C0800_buf
-                                                                  [i + 2]));
-                               word++;
-                       }
-                       i += 3;
-               } else if (_adv_asc38C0800_buf[i] == 0xfe) {
-                       AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                           _adv_asc38C0800_buf
-                                                           [i +
-                                                            2] << 8) |
-                                                          _adv_asc38C0800_buf[i
-                                                                              +
-                                                                              1]));
-                       i += 2;
-                       word++;
-               } else {
-                       AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                           _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
-                       word++;
+static int AscSgListToQueue(int sg_list)
+{
+       int n_sg_list_qs;
+
+       n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
+       if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
+               n_sg_list_qs++;
+       return n_sg_list_qs + 1;
+}
+
+static uint
+AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
+{
+       uint cur_used_qs;
+       uint cur_free_qs;
+       ASC_SCSI_BIT_ID_TYPE target_id;
+       uchar tid_no;
+
+       target_id = ASC_TIX_TO_TARGET_ID(target_ix);
+       tid_no = ASC_TIX_TO_TID(target_ix);
+       if ((asc_dvc->unit_not_ready & target_id) ||
+           (asc_dvc->queue_full_or_busy & target_id)) {
+               return 0;
+       }
+       if (n_qs == 1) {
+               cur_used_qs = (uint) asc_dvc->cur_total_qng +
+                   (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
+       } else {
+               cur_used_qs = (uint) asc_dvc->cur_total_qng +
+                   (uint) ASC_MIN_FREE_Q;
+       }
+       if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
+               cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
+               if (asc_dvc->cur_dvc_qng[tid_no] >=
+                   asc_dvc->max_dvc_qng[tid_no]) {
+                       return 0;
+               }
+               return cur_free_qs;
+       }
+       if (n_qs > 1) {
+               if ((n_qs > asc_dvc->last_q_shortage)
+                   && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
+                       asc_dvc->last_q_shortage = n_qs;
                }
        }
+       return 0;
+}
 
-       /*
-        * Set 'word' for later use to clear the rest of memory and save
-        * the expanded mcode size.
-        */
-       word *= 2;
-       adv_asc38C0800_expanded_size = word;
-
-       /*
-        * Clear the rest of ASC-38C0800 Internal RAM (16KB).
-        */
-       for (; word < ADV_38C0800_MEMSIZE; word += 2) {
-               AdvWriteWordAutoIncLram(iop_base, 0);
-       }
-
-       /*
-        * Verify the microcode checksum.
-        */
-       sum = 0;
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
+{
+       ushort q_addr;
+       uchar next_qp;
+       uchar q_status;
 
-       for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
-               sum += AdvReadWordAutoIncLram(iop_base);
-       }
-       ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
+       q_addr = ASC_QNO_TO_QADDR(free_q_head);
+       q_status = (uchar)AscReadLramByte(iop_base,
+                                         (ushort)(q_addr +
+                                                  ASC_SCSIQ_B_STATUS));
+       next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
+       if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END))
+               return next_qp;
+       return ASC_QLINK_END;
+}
 
-       ASC_DBG2(1,
-                "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
-                (ulong)sum, (ulong)_adv_asc38C0800_chksum);
+static uchar
+AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
+{
+       uchar i;
 
-       if (sum != _adv_asc38C0800_chksum) {
-               asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-               return ADV_ERROR;
+       for (i = 0; i < n_free_q; i++) {
+               free_q_head = AscAllocFreeQueue(iop_base, free_q_head);
+               if (free_q_head == ASC_QLINK_END)
+                       break;
        }
+       return free_q_head;
+}
 
-       /*
-        * Restore the RISC memory BIOS region.
-        */
-       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
-               AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
-                                bios_mem[i]);
-       }
+/*
+ * void
+ * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+ *
+ * Calling/Exit State:
+ *    none
+ *
+ * Description:
+ *     Output an ASC_SCSI_Q structure to the chip
+ */
+static void
+DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+{
+       int i;
 
-       /*
-        * Calculate and write the microcode code checksum to the microcode
-        * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
-        */
-       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
-       AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
-       code_sum = 0;
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
-       for (word = begin_addr; word < end_addr; word += 2) {
-               code_sum += AdvReadWordAutoIncLram(iop_base);
+       ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
+       AscSetChipLramAddr(iop_base, s_addr);
+       for (i = 0; i < 2 * words; i += 2) {
+               if (i == 4 || i == 20) {
+                       continue;
+               }
+               outpw(iop_base + IOP_RAM_DATA,
+                     ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
        }
-       AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
-       /*
-        * Read microcode version and date.
-        */
-       AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
-                       asc_dvc->cfg->mcode_date);
-       AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
-                       asc_dvc->cfg->mcode_version);
-
-       /*
-        * Set the chip type to indicate the ASC38C0800.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+}
 
-       /*
-        * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
-        * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
-        * cable detection and then we are able to read C_DET[3:0].
-        *
-        * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
-        * Microcode Default Value' section below.
-        */
-       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-       AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
-                            scsi_cfg1 | DIS_TERM_DRV);
+static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
+{
+       ushort q_addr;
+       uchar tid_no;
+       uchar sdtr_data;
+       uchar syn_period_ix;
+       uchar syn_offset;
+       PortAddr iop_base;
 
-       /*
-        * If the PCI Configuration Command Register "Parity Error Response
-        * Control" Bit was clear (0), then set the microcode variable
-        * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
-        * to ignore DMA parity errors.
-        */
-       if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
-               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-               word |= CONTROL_FLAG_IGNORE_PERR;
-               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+       iop_base = asc_dvc->iop_base;
+       if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
+           ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
+               tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
+               sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+               syn_period_ix =
+                   (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
+               syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
+               AscMsgOutSDTR(asc_dvc,
+                             asc_dvc->sdtr_period_tbl[syn_period_ix],
+                             syn_offset);
+               scsiq->q1.cntl |= QC_MSG_OUT;
        }
-
-       /*
-        * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
-        * bits for the default FIFO threshold.
-        *
-        * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
-        *
-        * For DMA Errata #4 set the BC_THRESH_ENB bit.
-        */
-       AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-                            BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
-                            READ_CMD_MRM);
-
-       /*
-        * Microcode operating variables for WDTR, SDTR, and command tag
-        * queuing will be set in AdvInquiryHandling() based on what a
-        * device reports it is capable of in Inquiry byte 7.
-        *
-        * If SCSI Bus Resets have been disabled, then directly set
-        * SDTR and WDTR from the EEPROM configuration. This will allow
-        * the BIOS and warm boot to work without a SCSI bus hang on
-        * the Inquiry caused by host and target mismatched DTR values.
-        * Without the SCSI Bus Reset, before an Inquiry a device can't
-        * be assumed to be in Asynchronous, Narrow mode.
-        */
-       if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
-               AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
-                                asc_dvc->wdtr_able);
-               AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
-                                asc_dvc->sdtr_able);
+       q_addr = ASC_QNO_TO_QADDR(q_no);
+       if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
+               scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
        }
+       scsiq->q1.status = QS_FREE;
+       AscMemWordCopyPtrToLram(iop_base,
+                               q_addr + ASC_SCSIQ_CDB_BEG,
+                               (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
 
-       /*
-        * Set microcode operating variables for DISC and SDTR_SPEED1,
-        * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
-        * configuration values.
-        *
-        * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
-        * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
-        * without determining here whether the device supports SDTR.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
-                        asc_dvc->cfg->disc_enable);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
-
-       /*
-        * Set SCSI_CFG0 Microcode Default Value.
-        *
-        * The microcode will set the SCSI_CFG0 register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-                        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
-                        asc_dvc->chip_scsi_id);
-
-       /*
-        * Determine SCSI_CFG1 Microcode Default Value.
-        *
-        * The microcode will set the SCSI_CFG1 register using this value
-        * after it is started below.
-        */
-
-       /* Read current SCSI_CFG1 Register value. */
-       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-
-       /*
-        * If the internal narrow cable is reversed all of the SCSI_CTRL
-        * register signals will be set. Check for and return an error if
-        * this condition is found.
-        */
-       if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
-               asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
-               return ADV_ERROR;
-       }
+       DvcPutScsiQ(iop_base,
+                   q_addr + ASC_SCSIQ_CPY_BEG,
+                   (uchar *)&scsiq->q1.cntl,
+                   ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
+       AscWriteLramWord(iop_base,
+                        (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
+                        (ushort)(((ushort)scsiq->q1.
+                                  q_no << 8) | (ushort)QS_READY));
+       return 1;
+}
 
-       /*
-        * All kind of combinations of devices attached to one of four connectors
-        * are acceptable except HVD device attached. For example, LVD device can
-        * be attached to SE connector while SE device attached to LVD connector.
-        * If LVD device attached to SE connector, it only runs up to Ultra speed.
-        *
-        * If an HVD device is attached to one of LVD connectors, return an error.
-        * However, there is no way to detect HVD device attached to SE connectors.
-        */
-       if (scsi_cfg1 & HVD) {
-               asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
-               return ADV_ERROR;
-       }
+static int
+AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
+{
+       int sta;
+       int i;
+       ASC_SG_HEAD *sg_head;
+       ASC_SG_LIST_Q scsi_sg_q;
+       ASC_DCNT saved_data_addr;
+       ASC_DCNT saved_data_cnt;
+       PortAddr iop_base;
+       ushort sg_list_dwords;
+       ushort sg_index;
+       ushort sg_entry_cnt;
+       ushort q_addr;
+       uchar next_qp;
 
+       iop_base = asc_dvc->iop_base;
+       sg_head = scsiq->sg_head;
+       saved_data_addr = scsiq->q1.data_addr;
+       saved_data_cnt = scsiq->q1.data_cnt;
+       scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
+       scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
+#if CC_VERY_LONG_SG_LIST
        /*
-        * If either SE or LVD automatic termination control is enabled, then
-        * set the termination value based on a table listed in a_condor.h.
-        *
-        * If manual termination was specified with an EEPROM setting then
-        * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
-        * be 'ored' into SCSI_CFG1.
+        * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
+        * then not all SG elements will fit in the allocated queues.
+        * The rest of the SG elements will be copied when the RISC
+        * completes the SG elements that fit and halts.
         */
-       if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
-               /* SE automatic termination control is enabled. */
-               switch (scsi_cfg1 & C_DET_SE) {
-                       /* TERM_SE_HI: on, TERM_SE_LO: on */
-               case 0x1:
-               case 0x2:
-               case 0x3:
-                       asc_dvc->cfg->termination |= TERM_SE;
-                       break;
+       if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
+               /*
+                * Set sg_entry_cnt to be the number of SG elements that
+                * will fit in the allocated SG queues. It is minus 1, because
+                * the first SG element is handled above. ASC_MAX_SG_LIST is
+                * already inflated by 1 to account for this. For example it
+                * may be 50 which is 1 + 7 queues * 7 SG elements.
+                */
+               sg_entry_cnt = ASC_MAX_SG_LIST - 1;
 
-                       /* TERM_SE_HI: on, TERM_SE_LO: off */
-               case 0x0:
-                       asc_dvc->cfg->termination |= TERM_SE_HI;
-                       break;
+               /*
+                * Keep track of remaining number of SG elements that will
+                * need to be handled from a_isr.c.
+                */
+               scsiq->remain_sg_entry_cnt =
+                   sg_head->entry_cnt - ASC_MAX_SG_LIST;
+       } else {
+#endif /* CC_VERY_LONG_SG_LIST */
+               /*
+                * Set sg_entry_cnt to be the number of SG elements that
+                * will fit in the allocated SG queues. It is minus 1, because
+                * the first SG element is handled above.
+                */
+               sg_entry_cnt = sg_head->entry_cnt - 1;
+#if CC_VERY_LONG_SG_LIST
+       }
+#endif /* CC_VERY_LONG_SG_LIST */
+       if (sg_entry_cnt != 0) {
+               scsiq->q1.cntl |= QC_SG_HEAD;
+               q_addr = ASC_QNO_TO_QADDR(q_no);
+               sg_index = 1;
+               scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
+               scsi_sg_q.sg_head_qp = q_no;
+               scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+               for (i = 0; i < sg_head->queue_cnt; i++) {
+                       scsi_sg_q.seq_no = i + 1;
+                       if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+                               sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
+                               sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                               if (i == 0) {
+                                       scsi_sg_q.sg_list_cnt =
+                                           ASC_SG_LIST_PER_Q;
+                                       scsi_sg_q.sg_cur_list_cnt =
+                                           ASC_SG_LIST_PER_Q;
+                               } else {
+                                       scsi_sg_q.sg_list_cnt =
+                                           ASC_SG_LIST_PER_Q - 1;
+                                       scsi_sg_q.sg_cur_list_cnt =
+                                           ASC_SG_LIST_PER_Q - 1;
+                               }
+                       } else {
+#if CC_VERY_LONG_SG_LIST
+                               /*
+                                * This is the last SG queue in the list of
+                                * allocated SG queues. If there are more
+                                * SG elements than will fit in the allocated
+                                * queues, then set the QCSG_SG_XFER_MORE flag.
+                                */
+                               if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
+                                       scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                               } else {
+#endif /* CC_VERY_LONG_SG_LIST */
+                                       scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+#if CC_VERY_LONG_SG_LIST
+                               }
+#endif /* CC_VERY_LONG_SG_LIST */
+                               sg_list_dwords = sg_entry_cnt << 1;
+                               if (i == 0) {
+                                       scsi_sg_q.sg_list_cnt = sg_entry_cnt;
+                                       scsi_sg_q.sg_cur_list_cnt =
+                                           sg_entry_cnt;
+                               } else {
+                                       scsi_sg_q.sg_list_cnt =
+                                           sg_entry_cnt - 1;
+                                       scsi_sg_q.sg_cur_list_cnt =
+                                           sg_entry_cnt - 1;
+                               }
+                               sg_entry_cnt = 0;
+                       }
+                       next_qp = AscReadLramByte(iop_base,
+                                                 (ushort)(q_addr +
+                                                          ASC_SCSIQ_B_FWD));
+                       scsi_sg_q.q_no = next_qp;
+                       q_addr = ASC_QNO_TO_QADDR(next_qp);
+                       AscMemWordCopyPtrToLram(iop_base,
+                                               q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+                                               (uchar *)&scsi_sg_q,
+                                               sizeof(ASC_SG_LIST_Q) >> 1);
+                       AscMemDWordCopyPtrToLram(iop_base,
+                                                q_addr + ASC_SGQ_LIST_BEG,
+                                                (uchar *)&sg_head->
+                                                sg_list[sg_index],
+                                                sg_list_dwords);
+                       sg_index += ASC_SG_LIST_PER_Q;
+                       scsiq->next_sg_index = sg_index;
                }
+       } else {
+               scsiq->q1.cntl &= ~QC_SG_HEAD;
        }
+       sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
+       scsiq->q1.data_addr = saved_data_addr;
+       scsiq->q1.data_cnt = saved_data_cnt;
+       return (sta);
+}
 
-       if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
-               /* LVD automatic termination control is enabled. */
-               switch (scsi_cfg1 & C_DET_LVD) {
-                       /* TERM_LVD_HI: on, TERM_LVD_LO: on */
-               case 0x4:
-               case 0x8:
-               case 0xC:
-                       asc_dvc->cfg->termination |= TERM_LVD;
-                       break;
+static int
+AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
+{
+       PortAddr iop_base;
+       uchar free_q_head;
+       uchar next_qp;
+       uchar tid_no;
+       uchar target_ix;
+       int sta;
 
-                       /* TERM_LVD_HI: off, TERM_LVD_LO: off */
-               case 0x0:
-                       break;
+       iop_base = asc_dvc->iop_base;
+       target_ix = scsiq->q2.target_ix;
+       tid_no = ASC_TIX_TO_TID(target_ix);
+       sta = 0;
+       free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
+       if (n_q_required > 1) {
+               next_qp = AscAllocMultipleFreeQueue(iop_base, free_q_head,
+                                                   (uchar)n_q_required);
+               if (next_qp != ASC_QLINK_END) {
+                       asc_dvc->last_q_shortage = 0;
+                       scsiq->sg_head->queue_cnt = n_q_required - 1;
+                       scsiq->q1.q_no = free_q_head;
+                       sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+                                                    free_q_head);
+               }
+       } else if (n_q_required == 1) {
+               next_qp = AscAllocFreeQueue(iop_base, free_q_head);
+               if (next_qp != ASC_QLINK_END) {
+                       scsiq->q1.q_no = free_q_head;
+                       sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head);
                }
        }
+       if (sta == 1) {
+               AscPutVarFreeQHead(iop_base, next_qp);
+               asc_dvc->cur_total_qng += n_q_required;
+               asc_dvc->cur_dvc_qng[tid_no]++;
+       }
+       return sta;
+}
 
-       /*
-        * Clear any set TERM_SE and TERM_LVD bits.
-        */
-       scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
-
-       /*
-        * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
-        */
-       scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
-
-       /*
-        * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
-        * and set possibly modified termination control bits in the Microcode
-        * SCSI_CFG1 Register Value.
-        */
-       scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
-
-       /*
-        * Set SCSI_CFG1 Microcode Default Value
-        *
-        * Set possibly modified termination control and reset DIS_TERM_DRV
-        * bits in the Microcode SCSI_CFG1 Register Value.
-        *
-        * The microcode will set the SCSI_CFG1 register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
-
-       /*
-        * Set MEM_CFG Microcode Default Value
-        *
-        * The microcode will set the MEM_CFG register using this value
-        * after it is started below.
-        *
-        * MEM_CFG may be accessed as a word or byte, but only bits 0-7
-        * are defined.
-        *
-        * ASC-38C0800 has 16KB internal memory.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-                        BIOS_EN | RAM_SZ_16KB);
-
-       /*
-        * Set SEL_MASK Microcode Default Value
-        *
-        * The microcode will set the SEL_MASK register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+#define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
+static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
+       INQUIRY,
+       REQUEST_SENSE,
+       READ_CAPACITY,
+       READ_TOC,
+       MODE_SELECT,
+       MODE_SENSE,
+       MODE_SELECT_10,
+       MODE_SENSE_10,
+       0xFF,
+       0xFF,
+       0xFF,
+       0xFF,
+       0xFF,
+       0xFF,
+       0xFF,
+       0xFF
+};
 
-       /*
-        * Build the carrier freelist.
-        *
-        * Driver must have already allocated memory and set 'carrier_buf'.
-        */
-       ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
+{
+       PortAddr iop_base;
+       int sta;
+       int n_q_required;
+       int disable_syn_offset_one_fix;
+       int i;
+       ASC_PADDR addr;
+       ushort sg_entry_cnt = 0;
+       ushort sg_entry_cnt_minus_one = 0;
+       uchar target_ix;
+       uchar tid_no;
+       uchar sdtr_data;
+       uchar extra_bytes;
+       uchar scsi_cmd;
+       uchar disable_cmd;
+       ASC_SG_HEAD *sg_head;
+       ASC_DCNT data_cnt;
 
-       carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
-       asc_dvc->carr_freelist = NULL;
-       if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
-               buf_size = ADV_CARRIER_BUFSIZE;
-       } else {
-               buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+       iop_base = asc_dvc->iop_base;
+       sg_head = scsiq->sg_head;
+       if (asc_dvc->err_code != 0)
+               return (ERR);
+       scsiq->q1.q_no = 0;
+       if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+               scsiq->q1.extra_bytes = 0;
+       }
+       sta = 0;
+       target_ix = scsiq->q2.target_ix;
+       tid_no = ASC_TIX_TO_TID(target_ix);
+       n_q_required = 1;
+       if (scsiq->cdbptr[0] == REQUEST_SENSE) {
+               if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
+                       asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
+                       sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+                       AscMsgOutSDTR(asc_dvc,
+                                     asc_dvc->
+                                     sdtr_period_tbl[(sdtr_data >> 4) &
+                                                     (uchar)(asc_dvc->
+                                                             max_sdtr_index -
+                                                             1)],
+                                     (uchar)(sdtr_data & (uchar)
+                                             ASC_SYN_MAX_OFFSET));
+                       scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+               }
        }
-
-       do {
-               /*
-                * Get physical address for the carrier 'carrp'.
-                */
-               contig_len = sizeof(ADV_CARR_T);
-               carr_paddr =
-                   cpu_to_le32(DvcGetPhyAddr
-                               (asc_dvc, NULL, (uchar *)carrp,
-                                (ADV_SDCNT *)&contig_len,
-                                ADV_IS_CARRIER_FLAG));
-
-               buf_size -= sizeof(ADV_CARR_T);
-
-               /*
-                * If the current carrier is not physically contiguous, then
-                * maybe there was a page crossing. Try the next carrier aligned
-                * start address.
-                */
-               if (contig_len < sizeof(ADV_CARR_T)) {
-                       carrp++;
-                       continue;
+       if (asc_dvc->in_critical_cnt != 0) {
+               AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+               return (ERR);
+       }
+       asc_dvc->in_critical_cnt++;
+       if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+               if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
+                       asc_dvc->in_critical_cnt--;
+                       return (ERR);
                }
-
-               carrp->carr_pa = carr_paddr;
-               carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
-               /*
-                * Insert the carrier at the beginning of the freelist.
-                */
-               carrp->next_vpa =
-                   cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-               asc_dvc->carr_freelist = carrp;
-
-               carrp++;
+#if !CC_VERY_LONG_SG_LIST
+               if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+                       asc_dvc->in_critical_cnt--;
+                       return (ERR);
+               }
+#endif /* !CC_VERY_LONG_SG_LIST */
+               if (sg_entry_cnt == 1) {
+                       scsiq->q1.data_addr =
+                           (ADV_PADDR)sg_head->sg_list[0].addr;
+                       scsiq->q1.data_cnt =
+                           (ADV_DCNT)sg_head->sg_list[0].bytes;
+                       scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+               }
+               sg_entry_cnt_minus_one = sg_entry_cnt - 1;
        }
-       while (buf_size > 0);
-
-       /*
-        * Set-up the Host->RISC Initiator Command Queue (ICQ).
-        */
-
-       if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
-               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-               return ADV_ERROR;
+       scsi_cmd = scsiq->cdbptr[0];
+       disable_syn_offset_one_fix = FALSE;
+       if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
+           !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
+               if (scsiq->q1.cntl & QC_SG_HEAD) {
+                       data_cnt = 0;
+                       for (i = 0; i < sg_entry_cnt; i++) {
+                               data_cnt +=
+                                   (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
+                                                         bytes);
+                       }
+               } else {
+                       data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+               }
+               if (data_cnt != 0UL) {
+                       if (data_cnt < 512UL) {
+                               disable_syn_offset_one_fix = TRUE;
+                       } else {
+                               for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
+                                    i++) {
+                                       disable_cmd =
+                                           _syn_offset_one_disable_cmd[i];
+                                       if (disable_cmd == 0xFF) {
+                                               break;
+                                       }
+                                       if (scsi_cmd == disable_cmd) {
+                                               disable_syn_offset_one_fix =
+                                                   TRUE;
+                                               break;
+                                       }
+                               }
+                       }
+               }
        }
-       asc_dvc->carr_freelist = (ADV_CARR_T *)
-           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
-
-       /*
-        * The first command issued will be placed in the stopper carrier.
-        */
-       asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
-       /*
-        * Set RISC ICQ physical address start value.
-        * carr_pa is LE, must be native before write
-        */
-       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
-
-       /*
-        * Set-up the RISC->Host Initiator Response Queue (IRQ).
-        */
-       if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
-               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-               return ADV_ERROR;
+       if (disable_syn_offset_one_fix) {
+               scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+               scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
+                                      ASC_TAG_FLAG_DISABLE_DISCONNECT);
+       } else {
+               scsiq->q2.tag_code &= 0x27;
        }
-       asc_dvc->carr_freelist = (ADV_CARR_T *)
-           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
-
-       /*
-        * The first command completed by the RISC will be placed in
-        * the stopper.
-        *
-        * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
-        * completed the RISC will set the ASC_RQ_STOPPER bit.
-        */
-       asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
-       /*
-        * Set RISC IRQ physical address start value.
-        *
-        * carr_pa is LE, must be native before write *
-        */
-       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
-       asc_dvc->carr_pending_cnt = 0;
-
-       AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-                            (ADV_INTR_ENABLE_HOST_INTR |
-                             ADV_INTR_ENABLE_GLOBAL_INTR));
-
-       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
-       AdvWriteWordRegister(iop_base, IOPW_PC, word);
-
-       /* finally, finally, gentlemen, start your engine */
-       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
-
-       /*
-        * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-        * Resets should be performed. The RISC has to be running
-        * to issue a SCSI Bus Reset.
-        */
-       if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+       if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+               if (asc_dvc->bug_fix_cntl) {
+                       if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+                               if ((scsi_cmd == READ_6) ||
+                                   (scsi_cmd == READ_10)) {
+                                       addr =
+                                           (ADV_PADDR)le32_to_cpu(sg_head->
+                                                                  sg_list
+                                                                  [sg_entry_cnt_minus_one].
+                                                                  addr) +
+                                           (ADV_DCNT)le32_to_cpu(sg_head->
+                                                                 sg_list
+                                                                 [sg_entry_cnt_minus_one].
+                                                                 bytes);
+                                       extra_bytes =
+                                           (uchar)((ushort)addr & 0x0003);
+                                       if ((extra_bytes != 0)
+                                           &&
+                                           ((scsiq->q2.
+                                             tag_code &
+                                             ASC_TAG_FLAG_EXTRA_BYTES)
+                                            == 0)) {
+                                               scsiq->q2.tag_code |=
+                                                   ASC_TAG_FLAG_EXTRA_BYTES;
+                                               scsiq->q1.extra_bytes =
+                                                   extra_bytes;
+                                               data_cnt =
+                                                   le32_to_cpu(sg_head->
+                                                               sg_list
+                                                               [sg_entry_cnt_minus_one].
+                                                               bytes);
+                                               data_cnt -=
+                                                   (ASC_DCNT) extra_bytes;
+                                               sg_head->
+                                                   sg_list
+                                                   [sg_entry_cnt_minus_one].
+                                                   bytes =
+                                                   cpu_to_le32(data_cnt);
+                                       }
+                               }
+                       }
+               }
+               sg_head->entry_to_copy = sg_head->entry_cnt;
+#if CC_VERY_LONG_SG_LIST
                /*
-                * If the BIOS Signature is present in memory, restore the
-                * BIOS Handshake Configuration Table and do not perform
-                * a SCSI Bus Reset.
+                * Set the sg_entry_cnt to the maximum possible. The rest of
+                * the SG elements will be copied when the RISC completes the
+                * SG elements that fit and halts.
                 */
-               if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
-                   0x55AA) {
-                       /*
-                        * Restore per TID negotiated values.
-                        */
-                       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
-                                        tagqng_able);
-                       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-                               AdvWriteByteLram(iop_base,
-                                                ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                                                max_cmd[tid]);
+               if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+                       sg_entry_cnt = ASC_MAX_SG_LIST;
+               }
+#endif /* CC_VERY_LONG_SG_LIST */
+               n_q_required = AscSgListToQueue(sg_entry_cnt);
+               if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
+                    (uint) n_q_required)
+                   || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+                       if ((sta =
+                            AscSendScsiQueue(asc_dvc, scsiq,
+                                             n_q_required)) == 1) {
+                               asc_dvc->in_critical_cnt--;
+                               return (sta);
+                       }
+               }
+       } else {
+               if (asc_dvc->bug_fix_cntl) {
+                       if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+                               if ((scsi_cmd == READ_6) ||
+                                   (scsi_cmd == READ_10)) {
+                                       addr =
+                                           le32_to_cpu(scsiq->q1.data_addr) +
+                                           le32_to_cpu(scsiq->q1.data_cnt);
+                                       extra_bytes =
+                                           (uchar)((ushort)addr & 0x0003);
+                                       if ((extra_bytes != 0)
+                                           &&
+                                           ((scsiq->q2.
+                                             tag_code &
+                                             ASC_TAG_FLAG_EXTRA_BYTES)
+                                            == 0)) {
+                                               data_cnt =
+                                                   le32_to_cpu(scsiq->q1.
+                                                               data_cnt);
+                                               if (((ushort)data_cnt & 0x01FF)
+                                                   == 0) {
+                                                       scsiq->q2.tag_code |=
+                                                           ASC_TAG_FLAG_EXTRA_BYTES;
+                                                       data_cnt -= (ASC_DCNT)
+                                                           extra_bytes;
+                                                       scsiq->q1.data_cnt =
+                                                           cpu_to_le32
+                                                           (data_cnt);
+                                                       scsiq->q1.extra_bytes =
+                                                           extra_bytes;
+                                               }
+                                       }
+                               }
                        }
-               } else {
-                       if (AdvResetSB(asc_dvc) != ADV_TRUE) {
-                               warn_code = ASC_WARN_BUSRESET_ERROR;
+               }
+               n_q_required = 1;
+               if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+                   ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+                       if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+                                                   n_q_required)) == 1) {
+                               asc_dvc->in_critical_cnt--;
+                               return (sta);
                        }
                }
        }
-
-       return warn_code;
+       asc_dvc->in_critical_cnt--;
+       return (sta);
 }
 
 /*
- * Initialize the ASC-38C1600.
+ * AdvExeScsiQueue() - Send a request to the RISC microcode program.
  *
- * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *   Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
+ *   add the carrier to the ICQ (Initiator Command Queue), and tickle the
+ *   RISC to notify it a new command is ready to be executed.
  *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
+ * set to SCSI_MAX_RETRY.
  *
- * Needed after initialization for error recovery.
- */
-static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
-{
-       AdvPortAddr iop_base;
-       ushort warn_code;
-       ADV_DCNT sum;
-       int begin_addr;
-       int end_addr;
-       ushort code_sum;
-       long word;
-       int j;
-       int adv_asc38C1600_expanded_size;
-       ADV_CARR_T *carrp;
-       ADV_DCNT contig_len;
-       ADV_SDCNT buf_size;
-       ADV_PADDR carr_paddr;
-       int i;
-       ushort scsi_cfg1;
-       uchar byte;
-       uchar tid;
-       ushort bios_mem[ASC_MC_BIOSLEN / 2];    /* BIOS RISC Memory 0x40-0x8F. */
-       ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
-       uchar max_cmd[ASC_MAX_TID + 1];
-
-       /* If there is already an error, don't continue. */
-       if (asc_dvc->err_code != 0) {
-               return ADV_ERROR;
-       }
-
-       /*
-        * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
-        */
-       if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
-               asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
-               return ADV_ERROR;
-       }
-
-       warn_code = 0;
-       iop_base = asc_dvc->iop_base;
-
-       /*
-        * Save the RISC memory BIOS region before writing the microcode.
-        * The BIOS may already be loaded and using its RISC LRAM region
-        * so its region must be saved and restored.
-        *
-        * Note: This code makes the assumption, which is currently true,
-        * that a chip reset does not clear RISC LRAM.
-        */
-       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
-               AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
-                               bios_mem[i]);
-       }
-
-       /*
-        * Save current per TID negotiated values.
-        */
-       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-       AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
-       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-       for (tid = 0; tid <= ASC_MAX_TID; tid++) {
-               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                               max_cmd[tid]);
-       }
-
-       /*
-        * RAM BIST (Built-In Self Test)
-        *
-        * Address : I/O base + offset 0x38h register (byte).
-        * Function: Bit 7-6(RW) : RAM mode
-        *                          Normal Mode   : 0x00
-        *                          Pre-test Mode : 0x40
-        *                          RAM Test Mode : 0x80
-        *           Bit 5       : unused
-        *           Bit 4(RO)   : Done bit
-        *           Bit 3-0(RO) : Status
-        *                          Host Error    : 0x08
-        *                          Int_RAM Error : 0x04
-        *                          RISC Error    : 0x02
-        *                          SCSI Error    : 0x01
-        *                          No Error      : 0x00
-        *
-        * Note: RAM BIST code should be put right here, before loading the
-        * microcode and after saving the RISC memory BIOS region.
-        */
-
-       /*
-        * LRAM Pre-test
-        *
-        * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
-        * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
-        * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
-        * to NORMAL_MODE, return an error too.
-        */
-       for (i = 0; i < 2; i++) {
-               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
-               DvcSleepMilliSecond(10);        /* Wait for 10ms before reading back. */
-               byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-               if ((byte & RAM_TEST_DONE) == 0
-                   || (byte & 0x0F) != PRE_TEST_VALUE) {
-                       asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-                       return ADV_ERROR;
-               }
-
-               AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
-               DvcSleepMilliSecond(10);        /* Wait for 10ms before reading back. */
-               if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
-                   != NORMAL_VALUE) {
-                       asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-                       return ADV_ERROR;
-               }
-       }
-
-       /*
-        * LRAM Test - It takes about 1.5 ms to run through the test.
-        *
-        * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
-        * If Done bit not set or Status not 0, save register byte, set the
-        * err_code, and return an error.
-        */
-       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
-       DvcSleepMilliSecond(10);        /* Wait for 10ms before checking status. */
-
-       byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-       if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
-               /* Get here if Done bit not set or Status not 0. */
-               asc_dvc->bist_err_code = byte;  /* for BIOS display message */
-               asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
-               return ADV_ERROR;
-       }
-
-       /* We need to reset back to normal mode after LRAM test passes. */
-       AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
-
-       /*
-        * Load the Microcode
-        *
-        * Write the microcode image to RISC memory starting at address 0.
-        *
-        */
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
-       /*
-        * Assume the following compressed format of the microcode buffer:
-        *
-        *  254 word (508 byte) table indexed by byte code followed
-        *  by the following byte codes:
-        *
-        *    1-Byte Code:
-        *      00: Emit word 0 in table.
-        *      01: Emit word 1 in table.
-        *      .
-        *      FD: Emit word 253 in table.
-        *
-        *    Multi-Byte Code:
-        *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
-        *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
-        */
-       word = 0;
-       for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
-               if (_adv_asc38C1600_buf[i] == 0xff) {
-                       for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
-                               AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                                   _adv_asc38C1600_buf
-                                                                   [i +
-                                                                    3] << 8) |
-                                                                  _adv_asc38C1600_buf
-                                                                  [i + 2]));
-                               word++;
-                       }
-                       i += 3;
-               } else if (_adv_asc38C1600_buf[i] == 0xfe) {
-                       AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                           _adv_asc38C1600_buf
-                                                           [i +
-                                                            2] << 8) |
-                                                          _adv_asc38C1600_buf[i
-                                                                              +
-                                                                              1]));
-                       i += 2;
-                       word++;
-               } else {
-                       AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                                                           _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
-                       word++;
-               }
-       }
-
-       /*
-        * Set 'word' for later use to clear the rest of memory and save
-        * the expanded mcode size.
-        */
-       word *= 2;
-       adv_asc38C1600_expanded_size = word;
-
-       /*
-        * Clear the rest of ASC-38C1600 Internal RAM (32KB).
-        */
-       for (; word < ADV_38C1600_MEMSIZE; word += 2) {
-               AdvWriteWordAutoIncLram(iop_base, 0);
-       }
-
-       /*
-        * Verify the microcode checksum.
-        */
-       sum = 0;
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
-       for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
-               sum += AdvReadWordAutoIncLram(iop_base);
-       }
-
-       if (sum != _adv_asc38C1600_chksum) {
-               asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-               return ADV_ERROR;
-       }
-
-       /*
-        * Restore the RISC memory BIOS region.
-        */
-       for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
-               AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
-                                bios_mem[i]);
-       }
-
-       /*
-        * Calculate and write the microcode code checksum to the microcode
-        * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
-        */
-       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
-       AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
-       code_sum = 0;
-       AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
-       for (word = begin_addr; word < end_addr; word += 2) {
-               code_sum += AdvReadWordAutoIncLram(iop_base);
-       }
-       AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
-       /*
-        * Read microcode version and date.
-        */
-       AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
-                       asc_dvc->cfg->mcode_date);
-       AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
-                       asc_dvc->cfg->mcode_version);
-
-       /*
-        * Set the chip type to indicate the ASC38C1600.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
-
-       /*
-        * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
-        * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
-        * cable detection and then we are able to read C_DET[3:0].
-        *
-        * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
-        * Microcode Default Value' section below.
-        */
-       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-       AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
-                            scsi_cfg1 | DIS_TERM_DRV);
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
+ * for DMA addresses or math operations are byte swapped to little-endian
+ * order.
+ *
+ * Return:
+ *      ADV_SUCCESS(1) - The request was successfully queued.
+ *      ADV_BUSY(0) -    Resource unavailable; Retry again after pending
+ *                       request completes.
+ *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
+ *                       host IC error.
+ */
+static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
+{
+       AdvPortAddr iop_base;
+       ADV_PADDR req_paddr;
+       ADV_CARR_T *new_carrp;
 
        /*
-        * If the PCI Configuration Command Register "Parity Error Response
-        * Control" Bit was clear (0), then set the microcode variable
-        * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
-        * to ignore DMA parity errors.
+        * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
         */
-       if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
-               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-               word |= CONTROL_FLAG_IGNORE_PERR;
-               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+       if (scsiq->target_id > ADV_MAX_TID) {
+               scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+               scsiq->done_status = QD_WITH_ERROR;
+               return ADV_ERROR;
        }
 
+       iop_base = asc_dvc->iop_base;
+
        /*
-        * If the BIOS control flag AIPP (Asynchronous Information
-        * Phase Protection) disable bit is not set, then set the firmware
-        * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
-        * AIPP checking and encoding.
+        * Allocate a carrier ensuring at least one carrier always
+        * remains on the freelist and initialize fields.
         */
-       if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
-               AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-               word |= CONTROL_FLAG_ENABLE_AIPP;
-               AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+       if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
+               return ADV_BUSY;
        }
+       asc_dvc->carr_freelist = (ADV_CARR_T *)
+           ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
+       asc_dvc->carr_pending_cnt++;
 
        /*
-        * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
-        * and START_CTL_TH [3:2].
+        * Set the carrier to be a stopper by setting 'next_vpa'
+        * to the stopper value. The current stopper will be changed
+        * below to point to the new stopper.
         */
-       AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-                            FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+       new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
        /*
-        * Microcode operating variables for WDTR, SDTR, and command tag
-        * queuing will be set in AdvInquiryHandling() based on what a
-        * device reports it is capable of in Inquiry byte 7.
-        *
-        * If SCSI Bus Resets have been disabled, then directly set
-        * SDTR and WDTR from the EEPROM configuration. This will allow
-        * the BIOS and warm boot to work without a SCSI bus hang on
-        * the Inquiry caused by host and target mismatched DTR values.
-        * Without the SCSI Bus Reset, before an Inquiry a device can't
-        * be assumed to be in Asynchronous, Narrow mode.
+        * Clear the ADV_SCSI_REQ_Q done flag.
         */
-       if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
-               AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
-                                asc_dvc->wdtr_able);
-               AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
-                                asc_dvc->sdtr_able);
-       }
+       scsiq->a_flag &= ~ADV_SCSIQ_DONE;
 
-       /*
-        * Set microcode operating variables for DISC and SDTR_SPEED1,
-        * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
-        * configuration values.
-        *
-        * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
-        * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
-        * without determining here whether the device supports SDTR.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
-                        asc_dvc->cfg->disc_enable);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+       req_paddr = virt_to_bus(scsiq);
+       BUG_ON(req_paddr & 31);
+       /* Wait for assertion before making little-endian */
+       req_paddr = cpu_to_le32(req_paddr);
 
-       /*
-        * Set SCSI_CFG0 Microcode Default Value.
-        *
-        * The microcode will set the SCSI_CFG0 register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-                        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
-                        asc_dvc->chip_scsi_id);
+       /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
+       scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
+       scsiq->scsiq_rptr = req_paddr;
 
+       scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
        /*
-        * Calculate SCSI_CFG1 Microcode Default Value.
-        *
-        * The microcode will set the SCSI_CFG1 register using this value
-        * after it is started below.
-        *
-        * Each ASC-38C1600 function has only two cable detect bits.
-        * The bus mode override bits are in IOPB_SOFT_OVER_WR.
+        * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
+        * order during initialization.
         */
-       scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+       scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
 
        /*
-        * If the cable is reversed all of the SCSI_CTRL register signals
-        * will be set. Check for and return an error if this condition is
-        * found.
+        * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+        * the microcode. The newly allocated stopper will become the new
+        * stopper.
         */
-       if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
-               asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
-               return ADV_ERROR;
-       }
+       asc_dvc->icq_sp->areq_vpa = req_paddr;
 
        /*
-        * Each ASC-38C1600 function has two connectors. Only an HVD device
-        * can not be connected to either connector. An LVD device or SE device
-        * may be connected to either connecor. If an SE device is connected,
-        * then at most Ultra speed (20 Mhz) can be used on both connectors.
-        *
-        * If an HVD device is attached, return an error.
+        * Set the 'next_vpa' pointer for the old stopper to be the
+        * physical address of the new stopper. The RISC can only
+        * follow physical addresses.
         */
-       if (scsi_cfg1 & HVD) {
-               asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
-               return ADV_ERROR;
-       }
+       asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
 
        /*
-        * Each function in the ASC-38C1600 uses only the SE cable detect and
-        * termination because there are two connectors for each function. Each
-        * function may use either LVD or SE mode. Corresponding the SE automatic
-        * termination control EEPROM bits are used for each function. Each
-        * function has its own EEPROM. If SE automatic control is enabled for
-        * the function, then set the termination value based on a table listed
-        * in a_condor.h.
-        *
-        * If manual termination is specified in the EEPROM for the function,
-        * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
-        * ready to be 'ored' into SCSI_CFG1.
+        * Set the host adapter stopper pointer to point to the new carrier.
         */
-       if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
-               /* SE automatic termination control is enabled. */
-               switch (scsi_cfg1 & C_DET_SE) {
-                       /* TERM_SE_HI: on, TERM_SE_LO: on */
-               case 0x1:
-               case 0x2:
-               case 0x3:
-                       asc_dvc->cfg->termination |= TERM_SE;
-                       break;
+       asc_dvc->icq_sp = new_carrp;
 
-               case 0x0:
-                       if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
-                               /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
-                       } else {
-                               /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
-                               asc_dvc->cfg->termination |= TERM_SE_HI;
-                       }
-                       break;
+       if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+           asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+               /*
+                * Tickle the RISC to tell it to read its Command Queue Head pointer.
+                */
+               AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+               if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+                       /*
+                        * Clear the tickle value. In the ASC-3550 the RISC flag
+                        * command 'clr_tickle_a' does not work unless the host
+                        * value is cleared.
+                        */
+                       AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+                                            ADV_TICKLE_NOP);
                }
+       } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+               /*
+                * Notify the RISC a carrier is ready by writing the physical
+                * address of the new carrier stopper to the COMMA register.
+                */
+               AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+                                     le32_to_cpu(new_carrp->carr_pa));
        }
 
-       /*
-        * Clear any set TERM_SE bits.
-        */
-       scsi_cfg1 &= ~TERM_SE;
-
-       /*
-        * Invert the TERM_SE bits and then set 'scsi_cfg1'.
-        */
-       scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
-
-       /*
-        * Clear Big Endian and Terminator Polarity bits and set possibly
-        * modified termination control bits in the Microcode SCSI_CFG1
-        * Register Value.
-        *
-        * Big Endian bit is not used even on big endian machines.
-        */
-       scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
-
-       /*
-        * Set SCSI_CFG1 Microcode Default Value
-        *
-        * Set possibly modified termination control bits in the Microcode
-        * SCSI_CFG1 Register Value.
-        *
-        * The microcode will set the SCSI_CFG1 register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+       return ADV_SUCCESS;
+}
 
-       /*
-        * Set MEM_CFG Microcode Default Value
-        *
-        * The microcode will set the MEM_CFG register using this value
-        * after it is started below.
-        *
-        * MEM_CFG may be accessed as a word or byte, but only bits 0-7
-        * are defined.
-        *
-        * ASC-38C1600 has 32KB internal memory.
-        *
-        * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
-        * out a special 16K Adv Library and Microcode version. After the issue
-        * resolved, we should turn back to the 32K support. Both a_condor.h and
-        * mcode.sas files also need to be updated.
-        *
-        * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-        *  BIOS_EN | RAM_SZ_32KB);
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-                        BIOS_EN | RAM_SZ_16KB);
+/*
+ * Execute a single 'Scsi_Cmnd'.
+ */
+static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
+{
+       int ret, err_code;
+       struct asc_board *boardp = shost_priv(scp->device->host);
 
-       /*
-        * Set SEL_MASK Microcode Default Value
-        *
-        * The microcode will set the SEL_MASK register using this value
-        * after it is started below.
-        */
-       AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+       ASC_DBG(1, "scp 0x%p\n", scp);
 
-       /*
-        * Build the carrier freelist.
-        *
-        * Driver must have already allocated memory and set 'carrier_buf'.
-        */
+       if (ASC_NARROW_BOARD(boardp)) {
+               ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+               struct asc_scsi_q asc_scsi_q;
 
-       ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+               /* asc_build_req() can not return ASC_BUSY. */
+               ret = asc_build_req(boardp, scp, &asc_scsi_q);
+               if (ret == ASC_ERROR) {
+                       ASC_STATS(scp->device->host, build_error);
+                       return ASC_ERROR;
+               }
 
-       carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
-       asc_dvc->carr_freelist = NULL;
-       if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
-               buf_size = ADV_CARRIER_BUFSIZE;
+               ret = AscExeScsiQueue(asc_dvc, &asc_scsi_q);
+               kfree(asc_scsi_q.sg_head);
+               err_code = asc_dvc->err_code;
        } else {
-               buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+               ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
+               ADV_SCSI_REQ_Q *adv_scsiqp;
+
+               switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+               case ASC_NOERROR:
+                       ASC_DBG(3, "adv_build_req ASC_NOERROR\n");
+                       break;
+               case ASC_BUSY:
+                       ASC_DBG(1, "adv_build_req ASC_BUSY\n");
+                       /*
+                        * The asc_stats fields 'adv_build_noreq' and
+                        * 'adv_build_nosg' count wide board busy conditions.
+                        * They are updated in adv_build_req and
+                        * adv_get_sglist, respectively.
+                        */
+                       return ASC_BUSY;
+               case ASC_ERROR:
+               default:
+                       ASC_DBG(1, "adv_build_req ASC_ERROR\n");
+                       ASC_STATS(scp->device->host, build_error);
+                       return ASC_ERROR;
+               }
+
+               ret = AdvExeScsiQueue(adv_dvc, adv_scsiqp);
+               err_code = adv_dvc->err_code;
        }
 
-       do {
+       switch (ret) {
+       case ASC_NOERROR:
+               ASC_STATS(scp->device->host, exe_noerror);
                /*
-                * Get physical address for the carrier 'carrp'.
+                * Increment monotonically increasing per device
+                * successful request counter. Wrapping doesn't matter.
                 */
-               contig_len = sizeof(ADV_CARR_T);
-               carr_paddr =
-                   cpu_to_le32(DvcGetPhyAddr
-                               (asc_dvc, NULL, (uchar *)carrp,
-                                (ADV_SDCNT *)&contig_len,
-                                ADV_IS_CARRIER_FLAG));
+               boardp->reqcnt[scp->device->id]++;
+               ASC_DBG(1, "ExeScsiQueue() ASC_NOERROR\n");
+               break;
+       case ASC_BUSY:
+               ASC_STATS(scp->device->host, exe_busy);
+               break;
+       case ASC_ERROR:
+               scmd_printk(KERN_ERR, scp, "ExeScsiQueue() ASC_ERROR, "
+                       "err_code 0x%x\n", err_code);
+               ASC_STATS(scp->device->host, exe_error);
+               scp->result = HOST_BYTE(DID_ERROR);
+               break;
+       default:
+               scmd_printk(KERN_ERR, scp, "ExeScsiQueue() unknown, "
+                       "err_code 0x%x\n", err_code);
+               ASC_STATS(scp->device->host, exe_unknown);
+               scp->result = HOST_BYTE(DID_ERROR);
+               break;
+       }
 
-               buf_size -= sizeof(ADV_CARR_T);
+       ASC_DBG(1, "end\n");
+       return ret;
+}
 
-               /*
-                * If the current carrier is not physically contiguous, then
-                * maybe there was a page crossing. Try the next carrier aligned
-                * start address.
-                */
-               if (contig_len < sizeof(ADV_CARR_T)) {
-                       carrp++;
-                       continue;
-               }
+/*
+ * advansys_queuecommand() - interrupt-driven I/O entrypoint.
+ *
+ * This function always returns 0. Command return status is saved
+ * in the 'scp' result field.
+ */
+static int
+advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+{
+       struct Scsi_Host *shost = scp->device->host;
+       int asc_res, result = 0;
 
-               carrp->carr_pa = carr_paddr;
-               carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+       ASC_STATS(shost, queuecommand);
+       scp->scsi_done = done;
 
-               /*
-                * Insert the carrier at the beginning of the freelist.
-                */
-               carrp->next_vpa =
-                   cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-               asc_dvc->carr_freelist = carrp;
+       asc_res = asc_execute_scsi_cmnd(scp);
 
-               carrp++;
+       switch (asc_res) {
+       case ASC_NOERROR:
+               break;
+       case ASC_BUSY:
+               result = SCSI_MLQUEUE_HOST_BUSY;
+               break;
+       case ASC_ERROR:
+       default:
+               asc_scsi_done(scp);
+               break;
        }
-       while (buf_size > 0);
+
+       return result;
+}
+
+static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
+{
+       PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+           (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+       return inpw(eisa_cfg_iop);
+}
+
+/*
+ * Return the BIOS address of the adapter at the specified
+ * I/O port and with the specified bus type.
+ */
+static unsigned short __devinit
+AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
+{
+       unsigned short cfg_lsw;
+       unsigned short bios_addr;
 
        /*
-        * Set-up the Host->RISC Initiator Command Queue (ICQ).
+        * The PCI BIOS is re-located by the motherboard BIOS. Because
+        * of this the driver can not determine where a PCI BIOS is
+        * loaded and executes.
         */
-       if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
-               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-               return ADV_ERROR;
+       if (bus_type & ASC_IS_PCI)
+               return 0;
+
+       if ((bus_type & ASC_IS_EISA) != 0) {
+               cfg_lsw = AscGetEisaChipCfg(iop_base);
+               cfg_lsw &= 0x000F;
+               bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
+               return bios_addr;
        }
-       asc_dvc->carr_freelist = (ADV_CARR_T *)
-           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
-       /*
-        * The first command issued will be placed in the stopper carrier.
-        */
-       asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+       cfg_lsw = AscGetChipCfgLsw(iop_base);
 
        /*
-        * Set RISC ICQ physical address start value. Initialize the
-        * COMMA register to the same value otherwise the RISC will
-        * prematurely detect a command is available.
+        *  ISA PnP uses the top bit as the 32K BIOS flag
         */
-       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
-       AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
-                             le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+       if (bus_type == ASC_IS_ISAPNP)
+               cfg_lsw &= 0x7FFF;
+       bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
+       return bios_addr;
+}
 
-       /*
-        * Set-up the RISC->Host Initiator Response Queue (IRQ).
-        */
-       if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
-               asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-               return ADV_ERROR;
+static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
+{
+       ushort cfg_lsw;
+
+       if (AscGetChipScsiID(iop_base) == new_host_id) {
+               return (new_host_id);
        }
-       asc_dvc->carr_freelist = (ADV_CARR_T *)
-           ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+       cfg_lsw = AscGetChipCfgLsw(iop_base);
+       cfg_lsw &= 0xF8FF;
+       cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
+       AscSetChipCfgLsw(iop_base, cfg_lsw);
+       return (AscGetChipScsiID(iop_base));
+}
 
-       /*
-        * The first command completed by the RISC will be placed in
-        * the stopper.
-        *
-        * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
-        * completed the RISC will set the ASC_RQ_STOPPER bit.
-        */
-       asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
+{
+       unsigned char sc;
 
-       /*
-        * Set RISC IRQ physical address start value.
-        */
-       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
-       asc_dvc->carr_pending_cnt = 0;
+       AscSetBank(iop_base, 1);
+       sc = inp(iop_base + IOP_REG_SC);
+       AscSetBank(iop_base, 0);
+       return sc;
+}
 
-       AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-                            (ADV_INTR_ENABLE_HOST_INTR |
-                             ADV_INTR_ENABLE_GLOBAL_INTR));
-       AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
-       AdvWriteWordRegister(iop_base, IOPW_PC, word);
+static unsigned char __devinit
+AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
+{
+       if (bus_type & ASC_IS_EISA) {
+               PortAddr eisa_iop;
+               unsigned char revision;
+               eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+                   (PortAddr) ASC_EISA_REV_IOP_MASK;
+               revision = inp(eisa_iop);
+               return ASC_CHIP_MIN_VER_EISA - 1 + revision;
+       }
+       return AscGetChipVerNo(iop_base);
+}
 
-       /* finally, finally, gentlemen, start your engine */
-       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+#ifdef CONFIG_ISA
+static void __devinit AscEnableIsaDma(uchar dma_channel)
+{
+       if (dma_channel < 4) {
+               outp(0x000B, (ushort)(0xC0 | dma_channel));
+               outp(0x000A, dma_channel);
+       } else if (dma_channel < 8) {
+               outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
+               outp(0x00D4, (ushort)(dma_channel - 4));
+       }
+}
+#endif /* CONFIG_ISA */
 
-       /*
-        * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-        * Resets should be performed. The RISC has to be running
-        * to issue a SCSI Bus Reset.
-        */
-       if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
-               /*
-                * If the BIOS Signature is present in memory, restore the
-                * per TID microcode operating variables.
-                */
-               if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
-                   0x55AA) {
-                       /*
-                        * Restore per TID negotiated values.
-                        */
-                       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-                       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-                       AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
-                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
-                                        tagqng_able);
-                       for (tid = 0; tid <= ASC_MAX_TID; tid++) {
-                               AdvWriteByteLram(iop_base,
-                                                ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                                                max_cmd[tid]);
-                       }
-               } else {
-                       if (AdvResetSB(asc_dvc) != ADV_TRUE) {
-                               warn_code = ASC_WARN_BUSRESET_ERROR;
+static int AscStopQueueExe(PortAddr iop_base)
+{
+       int count = 0;
+
+       if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+               AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                                ASC_STOP_REQ_RISC_STOP);
+               do {
+                       if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+                           ASC_STOP_ACK_RISC_STOP) {
+                               return (1);
                        }
-               }
+                       mdelay(100);
+               } while (count++ < 20);
        }
+       return (0);
+}
 
-       return warn_code;
+static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
+{
+       if (bus_type & ASC_IS_ISA)
+               return ASC_MAX_ISA_DMA_COUNT;
+       else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
+               return ASC_MAX_VL_DMA_COUNT;
+       return ASC_MAX_PCI_DMA_COUNT;
 }
 
-/*
- * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
- * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
- * all of this is done.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
- *
- * Note: Chip is stopped on entry.
- */
-static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+#ifdef CONFIG_ISA
+static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
 {
-       AdvPortAddr iop_base;
-       ushort warn_code;
-       ADVEEP_3550_CONFIG eep_config;
-       int i;
+       ushort channel;
 
-       iop_base = asc_dvc->iop_base;
+       channel = AscGetChipCfgLsw(iop_base) & 0x0003;
+       if (channel == 0x03)
+               return (0);
+       else if (channel == 0x00)
+               return (7);
+       return (channel + 4);
+}
 
-       warn_code = 0;
+static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
+{
+       ushort cfg_lsw;
+       uchar value;
 
-       /*
-        * Read the board's EEPROM configuration.
-        *
-        * Set default values if a bad checksum is found.
-        */
-       if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
-               warn_code |= ASC_WARN_EEPROM_CHKSUM;
+       if ((dma_channel >= 5) && (dma_channel <= 7)) {
+               if (dma_channel == 7)
+                       value = 0x00;
+               else
+                       value = dma_channel - 4;
+               cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
+               cfg_lsw |= value;
+               AscSetChipCfgLsw(iop_base, cfg_lsw);
+               return (AscGetIsaDmaChannel(iop_base));
+       }
+       return 0;
+}
 
-               /*
-                * Set EEPROM default values.
-                */
-               for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
-                       *((uchar *)&eep_config + i) =
-                           *((uchar *)&Default_3550_EEPROM_Config + i);
-               }
+static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
+{
+       uchar speed_value;
 
-               /*
-                * Assume the 6 byte board serial number that was read
-                * from EEPROM is correct even if the EEPROM checksum
-                * failed.
-                */
-               eep_config.serial_number_word3 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+       AscSetBank(iop_base, 1);
+       speed_value = AscReadChipDmaSpeed(iop_base);
+       speed_value &= 0x07;
+       AscSetBank(iop_base, 0);
+       return speed_value;
+}
 
-               eep_config.serial_number_word2 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
+{
+       speed_value &= 0x07;
+       AscSetBank(iop_base, 1);
+       AscWriteChipDmaSpeed(iop_base, speed_value);
+       AscSetBank(iop_base, 0);
+       return AscGetIsaDmaSpeed(iop_base);
+}
+#endif /* CONFIG_ISA */
 
-               eep_config.serial_number_word1 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
+{
+       int i;
+       PortAddr iop_base;
+       ushort warn_code;
+       uchar chip_version;
 
-               AdvSet3550EEPConfig(iop_base, &eep_config);
+       iop_base = asc_dvc->iop_base;
+       warn_code = 0;
+       asc_dvc->err_code = 0;
+       if ((asc_dvc->bus_type &
+            (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
+               asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
        }
-       /*
-        * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
-        * EEPROM configuration that was read.
-        *
-        * This is the mapping of EEPROM fields to Adv Library fields.
-        */
-       asc_dvc->wdtr_able = eep_config.wdtr_able;
-       asc_dvc->sdtr_able = eep_config.sdtr_able;
-       asc_dvc->ultra_able = eep_config.ultra_able;
-       asc_dvc->tagqng_able = eep_config.tagqng_able;
-       asc_dvc->cfg->disc_enable = eep_config.disc_enable;
-       asc_dvc->max_host_qng = eep_config.max_host_qng;
-       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-       asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
-       asc_dvc->start_motor = eep_config.start_motor;
-       asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-       asc_dvc->bios_ctrl = eep_config.bios_ctrl;
-       asc_dvc->no_scam = eep_config.scam_tolerant;
-       asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
-       asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
-       asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
-
-       /*
-        * Set the host maximum queuing (max. 253, min. 16) and the per device
-        * maximum queuing (max. 63, min. 4).
-        */
-       if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
-               eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-       } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
-               /* If the value is zero, assume it is uninitialized. */
-               if (eep_config.max_host_qng == 0) {
-                       eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-               } else {
-                       eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+       AscSetChipControl(iop_base, CC_HALT);
+       AscSetChipStatus(iop_base, 0);
+       asc_dvc->bug_fix_cntl = 0;
+       asc_dvc->pci_fix_asyn_xfer = 0;
+       asc_dvc->pci_fix_asyn_xfer_always = 0;
+       /* asc_dvc->init_state initalized in AscInitGetConfig(). */
+       asc_dvc->sdtr_done = 0;
+       asc_dvc->cur_total_qng = 0;
+       asc_dvc->is_in_int = 0;
+       asc_dvc->in_critical_cnt = 0;
+       asc_dvc->last_q_shortage = 0;
+       asc_dvc->use_tagged_qng = 0;
+       asc_dvc->no_scam = 0;
+       asc_dvc->unit_not_ready = 0;
+       asc_dvc->queue_full_or_busy = 0;
+       asc_dvc->redo_scam = 0;
+       asc_dvc->res2 = 0;
+       asc_dvc->min_sdtr_index = 0;
+       asc_dvc->cfg->can_tagged_qng = 0;
+       asc_dvc->cfg->cmd_qng_enabled = 0;
+       asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
+       asc_dvc->init_sdtr = 0;
+       asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
+       asc_dvc->scsi_reset_wait = 3;
+       asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
+       asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
+       asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
+       asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
+       asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
+       chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
+       asc_dvc->cfg->chip_version = chip_version;
+       asc_dvc->sdtr_period_tbl = asc_syn_xfer_period;
+       asc_dvc->max_sdtr_index = 7;
+       if ((asc_dvc->bus_type & ASC_IS_PCI) &&
+           (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
+               asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
+               asc_dvc->sdtr_period_tbl = asc_syn_ultra_xfer_period;
+               asc_dvc->max_sdtr_index = 15;
+               if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
+                       AscSetExtraControl(iop_base,
+                                          (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+               } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
+                       AscSetExtraControl(iop_base,
+                                          (SEC_ACTIVE_NEGATE |
+                                           SEC_ENABLE_FILTER));
                }
        }
+       if (asc_dvc->bus_type == ASC_IS_PCI) {
+               AscSetExtraControl(iop_base,
+                                  (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+       }
 
-       if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
-               eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-       } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
-               /* If the value is zero, assume it is uninitialized. */
-               if (eep_config.max_dvc_qng == 0) {
-                       eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-               } else {
-                       eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+       asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
+#ifdef CONFIG_ISA
+       if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+               if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
+                       AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
+                       asc_dvc->bus_type = ASC_IS_ISAPNP;
                }
+               asc_dvc->cfg->isa_dma_channel =
+                   (uchar)AscGetIsaDmaChannel(iop_base);
+       }
+#endif /* CONFIG_ISA */
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               asc_dvc->cur_dvc_qng[i] = 0;
+               asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
+               asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
+               asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
+               asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
        }
+       return warn_code;
+}
 
-       /*
-        * If 'max_dvc_qng' is greater than 'max_host_qng', then
-        * set 'max_dvc_qng' to 'max_host_qng'.
-        */
-       if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
-               eep_config.max_dvc_qng = eep_config.max_host_qng;
+static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
+{
+       int retry;
+
+       for (retry = 0; retry < ASC_EEP_MAX_RETRY; retry++) {
+               unsigned char read_back;
+               AscSetChipEEPCmd(iop_base, cmd_reg);
+               mdelay(1);
+               read_back = AscGetChipEEPCmd(iop_base);
+               if (read_back == cmd_reg)
+                       return 1;
        }
+       return 0;
+}
 
-       /*
-        * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
-        * values based on possibly adjusted EEPROM values.
-        */
-       asc_dvc->max_host_qng = eep_config.max_host_qng;
-       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+static void __devinit AscWaitEEPRead(void)
+{
+       mdelay(1);
+}
 
-       /*
-        * If the EEPROM 'termination' field is set to automatic (0), then set
-        * the ADV_DVC_CFG 'termination' field to automatic also.
-        *
-        * If the termination is specified with a non-zero 'termination'
-        * value check that a legal value is set and set the ADV_DVC_CFG
-        * 'termination' field appropriately.
-        */
-       if (eep_config.termination == 0) {
-               asc_dvc->cfg->termination = 0;  /* auto termination */
-       } else {
-               /* Enable manual control with low off / high off. */
-               if (eep_config.termination == 1) {
-                       asc_dvc->cfg->termination = TERM_CTL_SEL;
+static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
+{
+       ushort read_wval;
+       uchar cmd_reg;
 
-                       /* Enable manual control with low off / high on. */
-               } else if (eep_config.termination == 2) {
-                       asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+       AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+       AscWaitEEPRead();
+       cmd_reg = addr | ASC_EEP_CMD_READ;
+       AscWriteEEPCmdReg(iop_base, cmd_reg);
+       AscWaitEEPRead();
+       read_wval = AscGetChipEEPData(iop_base);
+       AscWaitEEPRead();
+       return read_wval;
+}
 
-                       /* Enable manual control with low on / high on. */
-               } else if (eep_config.termination == 3) {
-                       asc_dvc->cfg->termination =
-                           TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
-               } else {
+static ushort __devinit
+AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+{
+       ushort wval;
+       ushort sum;
+       ushort *wbuf;
+       int cfg_beg;
+       int cfg_end;
+       int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+       int s_addr;
+
+       wbuf = (ushort *)cfg_buf;
+       sum = 0;
+       /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
+       for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+               *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+               sum += *wbuf;
+       }
+       if (bus_type & ASC_IS_VL) {
+               cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+               cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+       } else {
+               cfg_beg = ASC_EEP_DVC_CFG_BEG;
+               cfg_end = ASC_EEP_MAX_DVC_ADDR;
+       }
+       for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+               wval = AscReadEEPWord(iop_base, (uchar)s_addr);
+               if (s_addr <= uchar_end_in_config) {
                        /*
-                        * The EEPROM 'termination' field contains a bad value. Use
-                        * automatic termination instead.
+                        * Swap all char fields - must unswap bytes already swapped
+                        * by AscReadEEPWord().
                         */
-                       asc_dvc->cfg->termination = 0;
-                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
+                       *wbuf = le16_to_cpu(wval);
+               } else {
+                       /* Don't swap word field at the end - cntl field. */
+                       *wbuf = wval;
                }
-       }
-
-       return warn_code;
-}
-
-/*
- * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
- * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
- * all of this is done.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
- *
- * Note: Chip is stopped on entry.
- */
-static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+               sum += wval;    /* Checksum treats all EEPROM data as words. */
+       }
+       /*
+        * Read the checksum word which will be compared against 'sum'
+        * by the caller. Word field already swapped.
+        */
+       *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+       return sum;
+}
+
+static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
 {
-       AdvPortAddr iop_base;
-       ushort warn_code;
-       ADVEEP_38C0800_CONFIG eep_config;
-       int i;
-       uchar tid, termination;
-       ushort sdtr_speed = 0;
+       PortAddr iop_base;
+       ushort q_addr;
+       ushort saved_word;
+       int sta;
 
        iop_base = asc_dvc->iop_base;
+       sta = 0;
+       q_addr = ASC_QNO_TO_QADDR(241);
+       saved_word = AscReadLramWord(iop_base, q_addr);
+       AscSetChipLramAddr(iop_base, q_addr);
+       AscSetChipLramData(iop_base, 0x55AA);
+       mdelay(10);
+       AscSetChipLramAddr(iop_base, q_addr);
+       if (AscGetChipLramData(iop_base) == 0x55AA) {
+               sta = 1;
+               AscWriteLramWord(iop_base, q_addr, saved_word);
+       }
+       return (sta);
+}
 
-       warn_code = 0;
+static void __devinit AscWaitEEPWrite(void)
+{
+       mdelay(20);
+}
 
-       /*
-        * Read the board's EEPROM configuration.
-        *
-        * Set default values if a bad checksum is found.
-        */
-       if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
-           eep_config.check_sum) {
-               warn_code |= ASC_WARN_EEPROM_CHKSUM;
+static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
+{
+       ushort read_back;
+       int retry;
 
-               /*
-                * Set EEPROM default values.
-                */
-               for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
-                       *((uchar *)&eep_config + i) =
-                           *((uchar *)&Default_38C0800_EEPROM_Config + i);
+       retry = 0;
+       while (TRUE) {
+               AscSetChipEEPData(iop_base, data_reg);
+               mdelay(1);
+               read_back = AscGetChipEEPData(iop_base);
+               if (read_back == data_reg) {
+                       return (1);
                }
+               if (retry++ > ASC_EEP_MAX_RETRY) {
+                       return (0);
+               }
+       }
+}
 
-               /*
-                * Assume the 6 byte board serial number that was read
-                * from EEPROM is correct even if the EEPROM checksum
-                * failed.
-                */
-               eep_config.serial_number_word3 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
-
-               eep_config.serial_number_word2 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
-
-               eep_config.serial_number_word1 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+static ushort __devinit
+AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
+{
+       ushort read_wval;
 
-               AdvSet38C0800EEPConfig(iop_base, &eep_config);
+       read_wval = AscReadEEPWord(iop_base, addr);
+       if (read_wval != word_val) {
+               AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
+               AscWaitEEPRead();
+               AscWriteEEPDataReg(iop_base, word_val);
+               AscWaitEEPRead();
+               AscWriteEEPCmdReg(iop_base,
+                                 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
+               AscWaitEEPWrite();
+               AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+               AscWaitEEPRead();
+               return (AscReadEEPWord(iop_base, addr));
        }
-       /*
-        * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
-        * EEPROM configuration that was read.
-        *
-        * This is the mapping of EEPROM fields to Adv Library fields.
-        */
-       asc_dvc->wdtr_able = eep_config.wdtr_able;
-       asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
-       asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
-       asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
-       asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
-       asc_dvc->tagqng_able = eep_config.tagqng_able;
-       asc_dvc->cfg->disc_enable = eep_config.disc_enable;
-       asc_dvc->max_host_qng = eep_config.max_host_qng;
-       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-       asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
-       asc_dvc->start_motor = eep_config.start_motor;
-       asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-       asc_dvc->bios_ctrl = eep_config.bios_ctrl;
-       asc_dvc->no_scam = eep_config.scam_tolerant;
-       asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
-       asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
-       asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+       return (read_wval);
+}
 
-       /*
-        * For every Target ID if any of its 'sdtr_speed[1234]' bits
-        * are set, then set an 'sdtr_able' bit for it.
-        */
-       asc_dvc->sdtr_able = 0;
-       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-               if (tid == 0) {
-                       sdtr_speed = asc_dvc->sdtr_speed1;
-               } else if (tid == 4) {
-                       sdtr_speed = asc_dvc->sdtr_speed2;
-               } else if (tid == 8) {
-                       sdtr_speed = asc_dvc->sdtr_speed3;
-               } else if (tid == 12) {
-                       sdtr_speed = asc_dvc->sdtr_speed4;
-               }
-               if (sdtr_speed & ADV_MAX_TID) {
-                       asc_dvc->sdtr_able |= (1 << tid);
-               }
-               sdtr_speed >>= 4;
-       }
+static int __devinit
+AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+{
+       int n_error;
+       ushort *wbuf;
+       ushort word;
+       ushort sum;
+       int s_addr;
+       int cfg_beg;
+       int cfg_end;
+       int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
 
-       /*
-        * Set the host maximum queuing (max. 253, min. 16) and the per device
-        * maximum queuing (max. 63, min. 4).
-        */
-       if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
-               eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-       } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
-               /* If the value is zero, assume it is uninitialized. */
-               if (eep_config.max_host_qng == 0) {
-                       eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-               } else {
-                       eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+       wbuf = (ushort *)cfg_buf;
+       n_error = 0;
+       sum = 0;
+       /* Write two config words; AscWriteEEPWord() will swap bytes. */
+       for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+               sum += *wbuf;
+               if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
+                       n_error++;
                }
        }
-
-       if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
-               eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-       } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
-               /* If the value is zero, assume it is uninitialized. */
-               if (eep_config.max_dvc_qng == 0) {
-                       eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+       if (bus_type & ASC_IS_VL) {
+               cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+               cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+       } else {
+               cfg_beg = ASC_EEP_DVC_CFG_BEG;
+               cfg_end = ASC_EEP_MAX_DVC_ADDR;
+       }
+       for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+               if (s_addr <= uchar_end_in_config) {
+                       /*
+                        * This is a char field. Swap char fields before they are
+                        * swapped again by AscWriteEEPWord().
+                        */
+                       word = cpu_to_le16(*wbuf);
+                       if (word !=
+                           AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
+                               n_error++;
+                       }
                } else {
-                       eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+                       /* Don't swap word field at the end - cntl field. */
+                       if (*wbuf !=
+                           AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
+                               n_error++;
+                       }
                }
+               sum += *wbuf;   /* Checksum calculated from word values. */
        }
-
-       /*
-        * If 'max_dvc_qng' is greater than 'max_host_qng', then
-        * set 'max_dvc_qng' to 'max_host_qng'.
-        */
-       if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
-               eep_config.max_dvc_qng = eep_config.max_host_qng;
+       /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
+       *wbuf = sum;
+       if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
+               n_error++;
        }
 
+       /* Read EEPROM back again. */
+       wbuf = (ushort *)cfg_buf;
        /*
-        * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
-        * values based on possibly adjusted EEPROM values.
-        */
-       asc_dvc->max_host_qng = eep_config.max_host_qng;
-       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-
-       /*
-        * If the EEPROM 'termination' field is set to automatic (0), then set
-        * the ADV_DVC_CFG 'termination' field to automatic also.
-        *
-        * If the termination is specified with a non-zero 'termination'
-        * value check that a legal value is set and set the ADV_DVC_CFG
-        * 'termination' field appropriately.
+        * Read two config words; Byte-swapping done by AscReadEEPWord().
         */
-       if (eep_config.termination_se == 0) {
-               termination = 0;        /* auto termination for SE */
+       for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+               if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
+                       n_error++;
+               }
+       }
+       if (bus_type & ASC_IS_VL) {
+               cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+               cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
        } else {
-               /* Enable manual control with low off / high off. */
-               if (eep_config.termination_se == 1) {
-                       termination = 0;
-
-                       /* Enable manual control with low off / high on. */
-               } else if (eep_config.termination_se == 2) {
-                       termination = TERM_SE_HI;
-
-                       /* Enable manual control with low on / high on. */
-               } else if (eep_config.termination_se == 3) {
-                       termination = TERM_SE;
-               } else {
+               cfg_beg = ASC_EEP_DVC_CFG_BEG;
+               cfg_end = ASC_EEP_MAX_DVC_ADDR;
+       }
+       for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+               if (s_addr <= uchar_end_in_config) {
                        /*
-                        * The EEPROM 'termination_se' field contains a bad value.
-                        * Use automatic termination instead.
+                        * Swap all char fields. Must unswap bytes already swapped
+                        * by AscReadEEPWord().
                         */
-                       termination = 0;
-                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
+                       word =
+                           le16_to_cpu(AscReadEEPWord
+                                       (iop_base, (uchar)s_addr));
+               } else {
+                       /* Don't swap word field at the end - cntl field. */
+                       word = AscReadEEPWord(iop_base, (uchar)s_addr);
+               }
+               if (*wbuf != word) {
+                       n_error++;
                }
        }
+       /* Read checksum; Byte swapping not needed. */
+       if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
+               n_error++;
+       }
+       return n_error;
+}
 
-       if (eep_config.termination_lvd == 0) {
-               asc_dvc->cfg->termination = termination;        /* auto termination for LVD */
-       } else {
-               /* Enable manual control with low off / high off. */
-               if (eep_config.termination_lvd == 1) {
-                       asc_dvc->cfg->termination = termination;
-
-                       /* Enable manual control with low off / high on. */
-               } else if (eep_config.termination_lvd == 2) {
-                       asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+static int __devinit
+AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+{
+       int retry;
+       int n_error;
 
-                       /* Enable manual control with low on / high on. */
-               } else if (eep_config.termination_lvd == 3) {
-                       asc_dvc->cfg->termination = termination | TERM_LVD;
-               } else {
-                       /*
-                        * The EEPROM 'termination_lvd' field contains a bad value.
-                        * Use automatic termination instead.
-                        */
-                       asc_dvc->cfg->termination = termination;
-                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
+       retry = 0;
+       while (TRUE) {
+               if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
+                                                  bus_type)) == 0) {
+                       break;
+               }
+               if (++retry > ASC_EEP_MAX_RETRY) {
+                       break;
                }
        }
-
-       return warn_code;
+       return n_error;
 }
 
-/*
- * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
- * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
- * all of this is done.
- *
- * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
- *
- * Note: Chip is stopped on entry.
- */
-static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
+static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
 {
-       AdvPortAddr iop_base;
+       ASCEEP_CONFIG eep_config_buf;
+       ASCEEP_CONFIG *eep_config;
+       PortAddr iop_base;
+       ushort chksum;
        ushort warn_code;
-       ADVEEP_38C1600_CONFIG eep_config;
+       ushort cfg_msw, cfg_lsw;
        int i;
-       uchar tid, termination;
-       ushort sdtr_speed = 0;
+       int write_eep = 0;
 
        iop_base = asc_dvc->iop_base;
-
        warn_code = 0;
-
-       /*
-        * Read the board's EEPROM configuration.
-        *
-        * Set default values if a bad checksum is found.
-        */
-       if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
-           eep_config.check_sum) {
-               warn_code |= ASC_WARN_EEPROM_CHKSUM;
-
-               /*
-                * Set EEPROM default values.
-                */
-               for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
-                       if (i == 1
-                           && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
-                           0) {
-                               /*
-                                * Set Function 1 EEPROM Word 0 MSB
-                                *
-                                * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
-                                * EEPROM bits.
-                                *
-                                * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
-                                * old Mac system booting problem. The Expansion ROM must
-                                * be disabled in Function 1 for these systems.
-                                *
-                                */
-                               *((uchar *)&eep_config + i) =
-                                   ((*
-                                     ((uchar *)&Default_38C1600_EEPROM_Config
-                                      +
-                                      i)) &
-                                    (~
-                                     (((ADV_EEPROM_BIOS_ENABLE |
-                                        ADV_EEPROM_INTAB) >> 8) & 0xFF)));
-
-                               /*
-                                * Set the INTAB (bit 11) if the GPIO 0 input indicates
-                                * the Function 1 interrupt line is wired to INTA.
-                                *
-                                * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
-                                *   1 - Function 1 interrupt line wired to INT A.
-                                *   0 - Function 1 interrupt line wired to INT B.
-                                *
-                                * Note: Adapter boards always have Function 0 wired to INTA.
-                                * Put all 5 GPIO bits in input mode and then read
-                                * their input values.
-                                */
-                               AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
-                                                    0);
-                               if (AdvReadByteRegister
-                                   (iop_base, IOPB_GPIO_DATA) & 0x01) {
-                                       /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
-                                       *((uchar *)&eep_config + i) |=
-                                           ((ADV_EEPROM_INTAB >> 8) & 0xFF);
-                               }
-                       } else {
-                               *((uchar *)&eep_config + i) =
-                                   *((uchar *)&Default_38C1600_EEPROM_Config
-                                     + i);
+       AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+       AscStopQueueExe(iop_base);
+       if ((AscStopChip(iop_base) == FALSE) ||
+           (AscGetChipScsiCtrl(iop_base) != 0)) {
+               asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+               AscResetChipAndScsiBus(asc_dvc);
+               mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
+       }
+       if (AscIsChipHalted(iop_base) == FALSE) {
+               asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+               return (warn_code);
+       }
+       AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+       if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+               asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+               return (warn_code);
+       }
+       eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
+       cfg_msw = AscGetChipCfgMsw(iop_base);
+       cfg_lsw = AscGetChipCfgLsw(iop_base);
+       if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+               cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+               warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+               AscSetChipCfgMsw(iop_base, cfg_msw);
+       }
+       chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+       ASC_DBG(1, "chksum 0x%x\n", chksum);
+       if (chksum == 0) {
+               chksum = 0xaa55;
+       }
+       if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+               warn_code |= ASC_WARN_AUTO_CONFIG;
+               if (asc_dvc->cfg->chip_version == 3) {
+                       if (eep_config->cfg_lsw != cfg_lsw) {
+                               warn_code |= ASC_WARN_EEPROM_RECOVER;
+                               eep_config->cfg_lsw =
+                                   AscGetChipCfgLsw(iop_base);
+                       }
+                       if (eep_config->cfg_msw != cfg_msw) {
+                               warn_code |= ASC_WARN_EEPROM_RECOVER;
+                               eep_config->cfg_msw =
+                                   AscGetChipCfgMsw(iop_base);
                        }
                }
-
-               /*
-                * Assume the 6 byte board serial number that was read
-                * from EEPROM is correct even if the EEPROM checksum
-                * failed.
-                */
-               eep_config.serial_number_word3 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
-
-               eep_config.serial_number_word2 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
-
-               eep_config.serial_number_word1 =
-                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
-
-               AdvSet38C1600EEPConfig(iop_base, &eep_config);
        }
-
-       /*
-        * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
-        * EEPROM configuration that was read.
-        *
-        * This is the mapping of EEPROM fields to Adv Library fields.
-        */
-       asc_dvc->wdtr_able = eep_config.wdtr_able;
-       asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
-       asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
-       asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
-       asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
-       asc_dvc->ppr_able = 0;
-       asc_dvc->tagqng_able = eep_config.tagqng_able;
-       asc_dvc->cfg->disc_enable = eep_config.disc_enable;
-       asc_dvc->max_host_qng = eep_config.max_host_qng;
-       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-       asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
-       asc_dvc->start_motor = eep_config.start_motor;
-       asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-       asc_dvc->bios_ctrl = eep_config.bios_ctrl;
-       asc_dvc->no_scam = eep_config.scam_tolerant;
-
-       /*
-        * For every Target ID if any of its 'sdtr_speed[1234]' bits
-        * are set, then set an 'sdtr_able' bit for it.
-        */
-       asc_dvc->sdtr_able = 0;
-       for (tid = 0; tid <= ASC_MAX_TID; tid++) {
-               if (tid == 0) {
-                       sdtr_speed = asc_dvc->sdtr_speed1;
-               } else if (tid == 4) {
-                       sdtr_speed = asc_dvc->sdtr_speed2;
-               } else if (tid == 8) {
-                       sdtr_speed = asc_dvc->sdtr_speed3;
-               } else if (tid == 12) {
-                       sdtr_speed = asc_dvc->sdtr_speed4;
+       eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+       eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+       ASC_DBG(1, "eep_config->chksum 0x%x\n", eep_config->chksum);
+       if (chksum != eep_config->chksum) {
+               if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+                   ASC_CHIP_VER_PCI_ULTRA_3050) {
+                       ASC_DBG(1, "chksum error ignored; EEPROM-less board\n");
+                       eep_config->init_sdtr = 0xFF;
+                       eep_config->disc_enable = 0xFF;
+                       eep_config->start_motor = 0xFF;
+                       eep_config->use_cmd_qng = 0;
+                       eep_config->max_total_qng = 0xF0;
+                       eep_config->max_tag_qng = 0x20;
+                       eep_config->cntl = 0xBFFF;
+                       ASC_EEP_SET_CHIP_ID(eep_config, 7);
+                       eep_config->no_scam = 0;
+                       eep_config->adapter_info[0] = 0;
+                       eep_config->adapter_info[1] = 0;
+                       eep_config->adapter_info[2] = 0;
+                       eep_config->adapter_info[3] = 0;
+                       eep_config->adapter_info[4] = 0;
+                       /* Indicate EEPROM-less board. */
+                       eep_config->adapter_info[5] = 0xBB;
+               } else {
+                       ASC_PRINT
+                           ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
+                       write_eep = 1;
+                       warn_code |= ASC_WARN_EEPROM_CHKSUM;
                }
-               if (sdtr_speed & ASC_MAX_TID) {
-                       asc_dvc->sdtr_able |= (1 << tid);
+       }
+       asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
+       asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+       asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+       asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
+       asc_dvc->start_motor = eep_config->start_motor;
+       asc_dvc->dvc_cntl = eep_config->cntl;
+       asc_dvc->no_scam = eep_config->no_scam;
+       asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+       asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+       asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+       asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+       asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+       asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
+       if (!AscTestExternalLram(asc_dvc)) {
+               if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
+                    ASC_IS_PCI_ULTRA)) {
+                       eep_config->max_total_qng =
+                           ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+                       eep_config->max_tag_qng =
+                           ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+               } else {
+                       eep_config->cfg_msw |= 0x0800;
+                       cfg_msw |= 0x0800;
+                       AscSetChipCfgMsw(iop_base, cfg_msw);
+                       eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+                       eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
                }
-               sdtr_speed >>= 4;
+       } else {
+       }
+       if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+               eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
+       }
+       if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+               eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
+       }
+       if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+               eep_config->max_tag_qng = eep_config->max_total_qng;
+       }
+       if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+               eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+       }
+       asc_dvc->max_total_qng = eep_config->max_total_qng;
+       if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+           eep_config->use_cmd_qng) {
+               eep_config->disc_enable = eep_config->use_cmd_qng;
+               warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+       }
+       ASC_EEP_SET_CHIP_ID(eep_config,
+                           ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
+       asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
+       if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
+           !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+               asc_dvc->min_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
        }
 
-       /*
-        * Set the host maximum queuing (max. 253, min. 16) and the per device
-        * maximum queuing (max. 63, min. 4).
-        */
-       if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
-               eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-       } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
-               /* If the value is zero, assume it is uninitialized. */
-               if (eep_config.max_host_qng == 0) {
-                       eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-               } else {
-                       eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
-               }
+       for (i = 0; i <= ASC_MAX_TID; i++) {
+               asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
+               asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+               asc_dvc->cfg->sdtr_period_offset[i] =
+                   (uchar)(ASC_DEF_SDTR_OFFSET |
+                           (asc_dvc->min_sdtr_index << 4));
        }
-
-       if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
-               eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-       } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
-               /* If the value is zero, assume it is uninitialized. */
-               if (eep_config.max_dvc_qng == 0) {
-                       eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+       eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+       if (write_eep) {
+               if ((i = AscSetEEPConfig(iop_base, eep_config,
+                                    asc_dvc->bus_type)) != 0) {
+                       ASC_PRINT1
+                           ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
+                            i);
                } else {
-                       eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+                       ASC_PRINT
+                           ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
                }
        }
+       return (warn_code);
+}
 
-       /*
-        * If 'max_dvc_qng' is greater than 'max_host_qng', then
-        * set 'max_dvc_qng' to 'max_host_qng'.
-        */
-       if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
-               eep_config.max_dvc_qng = eep_config.max_host_qng;
-       }
+static int __devinit AscInitGetConfig(struct Scsi_Host *shost)
+{
+       struct asc_board *board = shost_priv(shost);
+       ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
+       unsigned short warn_code = 0;
 
-       /*
-        * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
-        * values based on possibly adjusted EEPROM values.
-        */
-       asc_dvc->max_host_qng = eep_config.max_host_qng;
-       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+       asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+       if (asc_dvc->err_code != 0)
+               return asc_dvc->err_code;
 
-       /*
-        * If the EEPROM 'termination' field is set to automatic (0), then set
-        * the ASC_DVC_CFG 'termination' field to automatic also.
-        *
-        * If the termination is specified with a non-zero 'termination'
-        * value check that a legal value is set and set the ASC_DVC_CFG
-        * 'termination' field appropriately.
-        */
-       if (eep_config.termination_se == 0) {
-               termination = 0;        /* auto termination for SE */
+       if (AscFindSignature(asc_dvc->iop_base)) {
+               warn_code |= AscInitAscDvcVar(asc_dvc);
+               warn_code |= AscInitFromEEP(asc_dvc);
+               asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+               if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
+                       asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
        } else {
-               /* Enable manual control with low off / high off. */
-               if (eep_config.termination_se == 1) {
-                       termination = 0;
-
-                       /* Enable manual control with low off / high on. */
-               } else if (eep_config.termination_se == 2) {
-                       termination = TERM_SE_HI;
-
-                       /* Enable manual control with low on / high on. */
-               } else if (eep_config.termination_se == 3) {
-                       termination = TERM_SE;
-               } else {
-                       /*
-                        * The EEPROM 'termination_se' field contains a bad value.
-                        * Use automatic termination instead.
-                        */
-                       termination = 0;
-                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
-               }
+               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
        }
 
-       if (eep_config.termination_lvd == 0) {
-               asc_dvc->cfg->termination = termination;        /* auto termination for LVD */
-       } else {
-               /* Enable manual control with low off / high off. */
-               if (eep_config.termination_lvd == 1) {
-                       asc_dvc->cfg->termination = termination;
-
-                       /* Enable manual control with low off / high on. */
-               } else if (eep_config.termination_lvd == 2) {
-                       asc_dvc->cfg->termination = termination | TERM_LVD_HI;
-
-                       /* Enable manual control with low on / high on. */
-               } else if (eep_config.termination_lvd == 3) {
-                       asc_dvc->cfg->termination = termination | TERM_LVD;
-               } else {
-                       /*
-                        * The EEPROM 'termination_lvd' field contains a bad value.
-                        * Use automatic termination instead.
-                        */
-                       asc_dvc->cfg->termination = termination;
-                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
-               }
+       switch (warn_code) {
+       case 0: /* No error */
+               break;
+       case ASC_WARN_IO_PORT_ROTATE:
+               shost_printk(KERN_WARNING, shost, "I/O port address "
+                               "modified\n");
+               break;
+       case ASC_WARN_AUTO_CONFIG:
+               shost_printk(KERN_WARNING, shost, "I/O port increment switch "
+                               "enabled\n");
+               break;
+       case ASC_WARN_EEPROM_CHKSUM:
+               shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n");
+               break;
+       case ASC_WARN_IRQ_MODIFIED:
+               shost_printk(KERN_WARNING, shost, "IRQ modified\n");
+               break;
+       case ASC_WARN_CMD_QNG_CONFLICT:
+               shost_printk(KERN_WARNING, shost, "tag queuing enabled w/o "
+                               "disconnects\n");
+               break;
+       default:
+               shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n",
+                               warn_code);
+               break;
        }
 
-       return warn_code;
+       if (asc_dvc->err_code != 0)
+               shost_printk(KERN_ERR, shost, "error 0x%x at init_state "
+                       "0x%x\n", asc_dvc->err_code, asc_dvc->init_state);
+
+       return asc_dvc->err_code;
 }
 
-/*
- * Read EEPROM configuration into the specified buffer.
- *
- * Return a checksum based on the EEPROM configuration read.
- */
-static ushort __init
-AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
 {
-       ushort wval, chksum;
-       ushort *wbuf;
-       int eep_addr;
-       ushort *charfields;
+       struct asc_board *board = shost_priv(shost);
+       ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
+       PortAddr iop_base = asc_dvc->iop_base;
+       unsigned short cfg_msw;
+       unsigned short warn_code = 0;
 
-       charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
-       wbuf = (ushort *)cfg_buf;
-       chksum = 0;
+       asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+       if (asc_dvc->err_code != 0)
+               return asc_dvc->err_code;
+       if (!AscFindSignature(asc_dvc->iop_base)) {
+               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+               return asc_dvc->err_code;
+       }
 
-       for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
-            eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
-               wval = AdvReadEEPWord(iop_base, eep_addr);
-               chksum += wval; /* Checksum is calculated from word values. */
-               if (*charfields++) {
-                       *wbuf = le16_to_cpu(wval);
+       cfg_msw = AscGetChipCfgMsw(iop_base);
+       if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+               cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+               warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+               AscSetChipCfgMsw(iop_base, cfg_msw);
+       }
+       if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+           asc_dvc->cfg->cmd_qng_enabled) {
+               asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+               warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+       }
+       if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+               warn_code |= ASC_WARN_AUTO_CONFIG;
+       }
+#ifdef CONFIG_PCI
+       if (asc_dvc->bus_type & ASC_IS_PCI) {
+               cfg_msw &= 0xFFC0;
+               AscSetChipCfgMsw(iop_base, cfg_msw);
+               if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
                } else {
-                       *wbuf = wval;
+                       if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
+                           (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
+                               asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+                               asc_dvc->bug_fix_cntl |=
+                                   ASC_BUG_FIX_ASYN_USE_SYN;
+                       }
+               }
+       } else
+#endif /* CONFIG_PCI */
+       if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
+               if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+                   == ASC_CHIP_VER_ASYN_BUG) {
+                       asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
                }
        }
-       /* Read checksum word. */
-       *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-       wbuf++;
-       charfields++;
+       if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+           asc_dvc->cfg->chip_scsi_id) {
+               asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+       }
+#ifdef CONFIG_ISA
+       if (asc_dvc->bus_type & ASC_IS_ISA) {
+               AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+               AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+       }
+#endif /* CONFIG_ISA */
 
-       /* Read rest of EEPROM not covered by the checksum. */
-       for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
-            eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
-               *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-               if (*charfields++) {
-                       *wbuf = le16_to_cpu(*wbuf);
-               }
+       asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
+
+       switch (warn_code) {
+       case 0: /* No error. */
+               break;
+       case ASC_WARN_IO_PORT_ROTATE:
+               shost_printk(KERN_WARNING, shost, "I/O port address "
+                               "modified\n");
+               break;
+       case ASC_WARN_AUTO_CONFIG:
+               shost_printk(KERN_WARNING, shost, "I/O port increment switch "
+                               "enabled\n");
+               break;
+       case ASC_WARN_EEPROM_CHKSUM:
+               shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n");
+               break;
+       case ASC_WARN_IRQ_MODIFIED:
+               shost_printk(KERN_WARNING, shost, "IRQ modified\n");
+               break;
+       case ASC_WARN_CMD_QNG_CONFLICT:
+               shost_printk(KERN_WARNING, shost, "tag queuing w/o "
+                               "disconnects\n");
+               break;
+       default:
+               shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n",
+                               warn_code);
+               break;
        }
-       return chksum;
+
+       if (asc_dvc->err_code != 0)
+               shost_printk(KERN_ERR, shost, "error 0x%x at init_state "
+                       "0x%x\n", asc_dvc->err_code, asc_dvc->init_state);
+
+       return asc_dvc->err_code;
 }
 
 /*
- * Read EEPROM configuration into the specified buffer.
+ * EEPROM Configuration.
  *
- * Return a checksum based on the EEPROM configuration read.
+ * All drivers should use this structure to set the default EEPROM
+ * configuration. The BIOS now uses this structure when it is built.
+ * Additional structure information can be found in a_condor.h where
+ * the structure is defined.
+ *
+ * The *_Field_IsChar structs are needed to correct for endianness.
+ * These values are read from the board 16 bits at a time directly
+ * into the structs. Because some fields are char, the values will be
+ * in the wrong order. The *_Field_IsChar tells when to flip the
+ * bytes. Data read and written to PCI memory is automatically swapped
+ * on big-endian platforms so char fields read as words are actually being
+ * unswapped on big-endian platforms.
  */
-static ushort __init
-AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
-{
-       ushort wval, chksum;
-       ushort *wbuf;
-       int eep_addr;
-       ushort *charfields;
+static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
+       ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
+       0x0000,                 /* cfg_msw */
+       0xFFFF,                 /* disc_enable */
+       0xFFFF,                 /* wdtr_able */
+       0xFFFF,                 /* sdtr_able */
+       0xFFFF,                 /* start_motor */
+       0xFFFF,                 /* tagqng_able */
+       0xFFFF,                 /* bios_scan */
+       0,                      /* scam_tolerant */
+       7,                      /* adapter_scsi_id */
+       0,                      /* bios_boot_delay */
+       3,                      /* scsi_reset_delay */
+       0,                      /* bios_id_lun */
+       0,                      /* termination */
+       0,                      /* reserved1 */
+       0xFFE7,                 /* bios_ctrl */
+       0xFFFF,                 /* ultra_able */
+       0,                      /* reserved2 */
+       ASC_DEF_MAX_HOST_QNG,   /* max_host_qng */
+       ASC_DEF_MAX_DVC_QNG,    /* max_dvc_qng */
+       0,                      /* dvc_cntl */
+       0,                      /* bug_fix */
+       0,                      /* serial_number_word1 */
+       0,                      /* serial_number_word2 */
+       0,                      /* serial_number_word3 */
+       0,                      /* check_sum */
+       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+       ,                       /* oem_name[16] */
+       0,                      /* dvc_err_code */
+       0,                      /* adv_err_code */
+       0,                      /* adv_err_addr */
+       0,                      /* saved_dvc_err_code */
+       0,                      /* saved_adv_err_code */
+       0,                      /* saved_adv_err_addr */
+       0                       /* num_of_err */
+};
 
-       charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
-       wbuf = (ushort *)cfg_buf;
-       chksum = 0;
+static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
+       0,                      /* cfg_lsw */
+       0,                      /* cfg_msw */
+       0,                      /* -disc_enable */
+       0,                      /* wdtr_able */
+       0,                      /* sdtr_able */
+       0,                      /* start_motor */
+       0,                      /* tagqng_able */
+       0,                      /* bios_scan */
+       0,                      /* scam_tolerant */
+       1,                      /* adapter_scsi_id */
+       1,                      /* bios_boot_delay */
+       1,                      /* scsi_reset_delay */
+       1,                      /* bios_id_lun */
+       1,                      /* termination */
+       1,                      /* reserved1 */
+       0,                      /* bios_ctrl */
+       0,                      /* ultra_able */
+       0,                      /* reserved2 */
+       1,                      /* max_host_qng */
+       1,                      /* max_dvc_qng */
+       0,                      /* dvc_cntl */
+       0,                      /* bug_fix */
+       0,                      /* serial_number_word1 */
+       0,                      /* serial_number_word2 */
+       0,                      /* serial_number_word3 */
+       0,                      /* check_sum */
+       {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+       ,                       /* oem_name[16] */
+       0,                      /* dvc_err_code */
+       0,                      /* adv_err_code */
+       0,                      /* adv_err_addr */
+       0,                      /* saved_dvc_err_code */
+       0,                      /* saved_adv_err_code */
+       0,                      /* saved_adv_err_addr */
+       0                       /* num_of_err */
+};
 
-       for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
-            eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
-               wval = AdvReadEEPWord(iop_base, eep_addr);
-               chksum += wval; /* Checksum is calculated from word values. */
-               if (*charfields++) {
-                       *wbuf = le16_to_cpu(wval);
-               } else {
-                       *wbuf = wval;
-               }
-       }
-       /* Read checksum word. */
-       *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-       wbuf++;
-       charfields++;
+static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
+       ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
+       0x0000,                 /* 01 cfg_msw */
+       0xFFFF,                 /* 02 disc_enable */
+       0xFFFF,                 /* 03 wdtr_able */
+       0x4444,                 /* 04 sdtr_speed1 */
+       0xFFFF,                 /* 05 start_motor */
+       0xFFFF,                 /* 06 tagqng_able */
+       0xFFFF,                 /* 07 bios_scan */
+       0,                      /* 08 scam_tolerant */
+       7,                      /* 09 adapter_scsi_id */
+       0,                      /*    bios_boot_delay */
+       3,                      /* 10 scsi_reset_delay */
+       0,                      /*    bios_id_lun */
+       0,                      /* 11 termination_se */
+       0,                      /*    termination_lvd */
+       0xFFE7,                 /* 12 bios_ctrl */
+       0x4444,                 /* 13 sdtr_speed2 */
+       0x4444,                 /* 14 sdtr_speed3 */
+       ASC_DEF_MAX_HOST_QNG,   /* 15 max_host_qng */
+       ASC_DEF_MAX_DVC_QNG,    /*    max_dvc_qng */
+       0,                      /* 16 dvc_cntl */
+       0x4444,                 /* 17 sdtr_speed4 */
+       0,                      /* 18 serial_number_word1 */
+       0,                      /* 19 serial_number_word2 */
+       0,                      /* 20 serial_number_word3 */
+       0,                      /* 21 check_sum */
+       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+       ,                       /* 22-29 oem_name[16] */
+       0,                      /* 30 dvc_err_code */
+       0,                      /* 31 adv_err_code */
+       0,                      /* 32 adv_err_addr */
+       0,                      /* 33 saved_dvc_err_code */
+       0,                      /* 34 saved_adv_err_code */
+       0,                      /* 35 saved_adv_err_addr */
+       0,                      /* 36 reserved */
+       0,                      /* 37 reserved */
+       0,                      /* 38 reserved */
+       0,                      /* 39 reserved */
+       0,                      /* 40 reserved */
+       0,                      /* 41 reserved */
+       0,                      /* 42 reserved */
+       0,                      /* 43 reserved */
+       0,                      /* 44 reserved */
+       0,                      /* 45 reserved */
+       0,                      /* 46 reserved */
+       0,                      /* 47 reserved */
+       0,                      /* 48 reserved */
+       0,                      /* 49 reserved */
+       0,                      /* 50 reserved */
+       0,                      /* 51 reserved */
+       0,                      /* 52 reserved */
+       0,                      /* 53 reserved */
+       0,                      /* 54 reserved */
+       0,                      /* 55 reserved */
+       0,                      /* 56 cisptr_lsw */
+       0,                      /* 57 cisprt_msw */
+       PCI_VENDOR_ID_ASP,      /* 58 subsysvid */
+       PCI_DEVICE_ID_38C0800_REV1,     /* 59 subsysid */
+       0,                      /* 60 reserved */
+       0,                      /* 61 reserved */
+       0,                      /* 62 reserved */
+       0                       /* 63 reserved */
+};
 
-       /* Read rest of EEPROM not covered by the checksum. */
-       for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
-            eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
-               *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-               if (*charfields++) {
-                       *wbuf = le16_to_cpu(*wbuf);
-               }
-       }
-       return chksum;
-}
+static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
+       0,                      /* 00 cfg_lsw */
+       0,                      /* 01 cfg_msw */
+       0,                      /* 02 disc_enable */
+       0,                      /* 03 wdtr_able */
+       0,                      /* 04 sdtr_speed1 */
+       0,                      /* 05 start_motor */
+       0,                      /* 06 tagqng_able */
+       0,                      /* 07 bios_scan */
+       0,                      /* 08 scam_tolerant */
+       1,                      /* 09 adapter_scsi_id */
+       1,                      /*    bios_boot_delay */
+       1,                      /* 10 scsi_reset_delay */
+       1,                      /*    bios_id_lun */
+       1,                      /* 11 termination_se */
+       1,                      /*    termination_lvd */
+       0,                      /* 12 bios_ctrl */
+       0,                      /* 13 sdtr_speed2 */
+       0,                      /* 14 sdtr_speed3 */
+       1,                      /* 15 max_host_qng */
+       1,                      /*    max_dvc_qng */
+       0,                      /* 16 dvc_cntl */
+       0,                      /* 17 sdtr_speed4 */
+       0,                      /* 18 serial_number_word1 */
+       0,                      /* 19 serial_number_word2 */
+       0,                      /* 20 serial_number_word3 */
+       0,                      /* 21 check_sum */
+       {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+       ,                       /* 22-29 oem_name[16] */
+       0,                      /* 30 dvc_err_code */
+       0,                      /* 31 adv_err_code */
+       0,                      /* 32 adv_err_addr */
+       0,                      /* 33 saved_dvc_err_code */
+       0,                      /* 34 saved_adv_err_code */
+       0,                      /* 35 saved_adv_err_addr */
+       0,                      /* 36 reserved */
+       0,                      /* 37 reserved */
+       0,                      /* 38 reserved */
+       0,                      /* 39 reserved */
+       0,                      /* 40 reserved */
+       0,                      /* 41 reserved */
+       0,                      /* 42 reserved */
+       0,                      /* 43 reserved */
+       0,                      /* 44 reserved */
+       0,                      /* 45 reserved */
+       0,                      /* 46 reserved */
+       0,                      /* 47 reserved */
+       0,                      /* 48 reserved */
+       0,                      /* 49 reserved */
+       0,                      /* 50 reserved */
+       0,                      /* 51 reserved */
+       0,                      /* 52 reserved */
+       0,                      /* 53 reserved */
+       0,                      /* 54 reserved */
+       0,                      /* 55 reserved */
+       0,                      /* 56 cisptr_lsw */
+       0,                      /* 57 cisprt_msw */
+       0,                      /* 58 subsysvid */
+       0,                      /* 59 subsysid */
+       0,                      /* 60 reserved */
+       0,                      /* 61 reserved */
+       0,                      /* 62 reserved */
+       0                       /* 63 reserved */
+};
+
+static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
+       ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
+       0x0000,                 /* 01 cfg_msw */
+       0xFFFF,                 /* 02 disc_enable */
+       0xFFFF,                 /* 03 wdtr_able */
+       0x5555,                 /* 04 sdtr_speed1 */
+       0xFFFF,                 /* 05 start_motor */
+       0xFFFF,                 /* 06 tagqng_able */
+       0xFFFF,                 /* 07 bios_scan */
+       0,                      /* 08 scam_tolerant */
+       7,                      /* 09 adapter_scsi_id */
+       0,                      /*    bios_boot_delay */
+       3,                      /* 10 scsi_reset_delay */
+       0,                      /*    bios_id_lun */
+       0,                      /* 11 termination_se */
+       0,                      /*    termination_lvd */
+       0xFFE7,                 /* 12 bios_ctrl */
+       0x5555,                 /* 13 sdtr_speed2 */
+       0x5555,                 /* 14 sdtr_speed3 */
+       ASC_DEF_MAX_HOST_QNG,   /* 15 max_host_qng */
+       ASC_DEF_MAX_DVC_QNG,    /*    max_dvc_qng */
+       0,                      /* 16 dvc_cntl */
+       0x5555,                 /* 17 sdtr_speed4 */
+       0,                      /* 18 serial_number_word1 */
+       0,                      /* 19 serial_number_word2 */
+       0,                      /* 20 serial_number_word3 */
+       0,                      /* 21 check_sum */
+       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+       ,                       /* 22-29 oem_name[16] */
+       0,                      /* 30 dvc_err_code */
+       0,                      /* 31 adv_err_code */
+       0,                      /* 32 adv_err_addr */
+       0,                      /* 33 saved_dvc_err_code */
+       0,                      /* 34 saved_adv_err_code */
+       0,                      /* 35 saved_adv_err_addr */
+       0,                      /* 36 reserved */
+       0,                      /* 37 reserved */
+       0,                      /* 38 reserved */
+       0,                      /* 39 reserved */
+       0,                      /* 40 reserved */
+       0,                      /* 41 reserved */
+       0,                      /* 42 reserved */
+       0,                      /* 43 reserved */
+       0,                      /* 44 reserved */
+       0,                      /* 45 reserved */
+       0,                      /* 46 reserved */
+       0,                      /* 47 reserved */
+       0,                      /* 48 reserved */
+       0,                      /* 49 reserved */
+       0,                      /* 50 reserved */
+       0,                      /* 51 reserved */
+       0,                      /* 52 reserved */
+       0,                      /* 53 reserved */
+       0,                      /* 54 reserved */
+       0,                      /* 55 reserved */
+       0,                      /* 56 cisptr_lsw */
+       0,                      /* 57 cisprt_msw */
+       PCI_VENDOR_ID_ASP,      /* 58 subsysvid */
+       PCI_DEVICE_ID_38C1600_REV1,     /* 59 subsysid */
+       0,                      /* 60 reserved */
+       0,                      /* 61 reserved */
+       0,                      /* 62 reserved */
+       0                       /* 63 reserved */
+};
+
+static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
+       0,                      /* 00 cfg_lsw */
+       0,                      /* 01 cfg_msw */
+       0,                      /* 02 disc_enable */
+       0,                      /* 03 wdtr_able */
+       0,                      /* 04 sdtr_speed1 */
+       0,                      /* 05 start_motor */
+       0,                      /* 06 tagqng_able */
+       0,                      /* 07 bios_scan */
+       0,                      /* 08 scam_tolerant */
+       1,                      /* 09 adapter_scsi_id */
+       1,                      /*    bios_boot_delay */
+       1,                      /* 10 scsi_reset_delay */
+       1,                      /*    bios_id_lun */
+       1,                      /* 11 termination_se */
+       1,                      /*    termination_lvd */
+       0,                      /* 12 bios_ctrl */
+       0,                      /* 13 sdtr_speed2 */
+       0,                      /* 14 sdtr_speed3 */
+       1,                      /* 15 max_host_qng */
+       1,                      /*    max_dvc_qng */
+       0,                      /* 16 dvc_cntl */
+       0,                      /* 17 sdtr_speed4 */
+       0,                      /* 18 serial_number_word1 */
+       0,                      /* 19 serial_number_word2 */
+       0,                      /* 20 serial_number_word3 */
+       0,                      /* 21 check_sum */
+       {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+       ,                       /* 22-29 oem_name[16] */
+       0,                      /* 30 dvc_err_code */
+       0,                      /* 31 adv_err_code */
+       0,                      /* 32 adv_err_addr */
+       0,                      /* 33 saved_dvc_err_code */
+       0,                      /* 34 saved_adv_err_code */
+       0,                      /* 35 saved_adv_err_addr */
+       0,                      /* 36 reserved */
+       0,                      /* 37 reserved */
+       0,                      /* 38 reserved */
+       0,                      /* 39 reserved */
+       0,                      /* 40 reserved */
+       0,                      /* 41 reserved */
+       0,                      /* 42 reserved */
+       0,                      /* 43 reserved */
+       0,                      /* 44 reserved */
+       0,                      /* 45 reserved */
+       0,                      /* 46 reserved */
+       0,                      /* 47 reserved */
+       0,                      /* 48 reserved */
+       0,                      /* 49 reserved */
+       0,                      /* 50 reserved */
+       0,                      /* 51 reserved */
+       0,                      /* 52 reserved */
+       0,                      /* 53 reserved */
+       0,                      /* 54 reserved */
+       0,                      /* 55 reserved */
+       0,                      /* 56 cisptr_lsw */
+       0,                      /* 57 cisprt_msw */
+       0,                      /* 58 subsysvid */
+       0,                      /* 59 subsysid */
+       0,                      /* 60 reserved */
+       0,                      /* 61 reserved */
+       0,                      /* 62 reserved */
+       0                       /* 63 reserved */
+};
 
+#ifdef CONFIG_PCI
 /*
- * Read EEPROM configuration into the specified buffer.
- *
- * Return a checksum based on the EEPROM configuration read.
+ * Wait for EEPROM command to complete
  */
-static ushort __init
-AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
+static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
 {
-       ushort wval, chksum;
-       ushort *wbuf;
-       int eep_addr;
-       ushort *charfields;
-
-       charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
-       wbuf = (ushort *)cfg_buf;
-       chksum = 0;
-
-       for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
-            eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
-               wval = AdvReadEEPWord(iop_base, eep_addr);
-               chksum += wval; /* Checksum is calculated from word values. */
-               if (*charfields++) {
-                       *wbuf = le16_to_cpu(wval);
-               } else {
-                       *wbuf = wval;
-               }
-       }
-       /* Read checksum word. */
-       *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-       wbuf++;
-       charfields++;
+       int eep_delay_ms;
 
-       /* Read rest of EEPROM not covered by the checksum. */
-       for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
-            eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
-               *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-               if (*charfields++) {
-                       *wbuf = le16_to_cpu(*wbuf);
+       for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
+               if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
+                   ASC_EEP_CMD_DONE) {
+                       break;
                }
+               mdelay(1);
        }
-       return chksum;
+       if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
+           0)
+               BUG();
 }
 
 /*
  * Read the EEPROM from specified location
  */
-static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
 {
        AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
                             ASC_EEP_CMD_READ | eep_word_addr);
@@ -16868,31 +12258,10 @@ static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
        return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
 }
 
-/*
- * Wait for EEPROM command to complete
- */
-static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
-{
-       int eep_delay_ms;
-
-       for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
-               if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
-                   ASC_EEP_CMD_DONE) {
-                       break;
-               }
-               DvcSleepMilliSecond(1);
-       }
-       if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
-           0) {
-               ASC_ASSERT(0);
-       }
-       return;
-}
-
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void __init
+void __devinit
 AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 {
        ushort *wbuf;
@@ -16923,7 +12292,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
                AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
                                     ASC_EEP_CMD_WRITE | addr);
                AdvWaitEEPCmd(iop_base);
-               DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+               mdelay(ADV_EEP_DELAY_MS);
        }
 
        /*
@@ -16954,13 +12323,12 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
        }
        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
        AdvWaitEEPCmd(iop_base);
-       return;
 }
 
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void __init
+void __devinit
 AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
 {
        ushort *wbuf;
@@ -16991,7 +12359,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
                AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
                                     ASC_EEP_CMD_WRITE | addr);
                AdvWaitEEPCmd(iop_base);
-               DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+               mdelay(ADV_EEP_DELAY_MS);
        }
 
        /*
@@ -17022,13 +12390,12 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
        }
        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
        AdvWaitEEPCmd(iop_base);
-       return;
 }
 
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void __init
+void __devinit
 AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
 {
        ushort *wbuf;
@@ -17059,7 +12426,7 @@ AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
                AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
                                     ASC_EEP_CMD_WRITE | addr);
                AdvWaitEEPCmd(iop_base);
-               DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+               mdelay(ADV_EEP_DELAY_MS);
        }
 
        /*
@@ -17071,834 +12438,1005 @@ AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
        wbuf++;
        charfields++;
 
-       /*
-        * Write EEPROM OEM name at words 22 to 29.
-        */
-       for (addr = ADV_EEP_DVC_CTL_BEGIN;
-            addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
-               ushort word;
-
+       /*
+        * Write EEPROM OEM name at words 22 to 29.
+        */
+       for (addr = ADV_EEP_DVC_CTL_BEGIN;
+            addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+               ushort word;
+
+               if (*charfields++) {
+                       word = cpu_to_le16(*wbuf);
+               } else {
+                       word = *wbuf;
+               }
+               AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+               AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+                                    ASC_EEP_CMD_WRITE | addr);
+               AdvWaitEEPCmd(iop_base);
+       }
+       AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+       AdvWaitEEPCmd(iop_base);
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static ushort __devinit
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+       ushort wval, chksum;
+       ushort *wbuf;
+       int eep_addr;
+       ushort *charfields;
+
+       charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+       wbuf = (ushort *)cfg_buf;
+       chksum = 0;
+
+       for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+            eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+               wval = AdvReadEEPWord(iop_base, eep_addr);
+               chksum += wval; /* Checksum is calculated from word values. */
+               if (*charfields++) {
+                       *wbuf = le16_to_cpu(wval);
+               } else {
+                       *wbuf = wval;
+               }
+       }
+       /* Read checksum word. */
+       *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+       wbuf++;
+       charfields++;
+
+       /* Read rest of EEPROM not covered by the checksum. */
+       for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+            eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+               *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+               if (*charfields++) {
+                       *wbuf = le16_to_cpu(*wbuf);
+               }
+       }
+       return chksum;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static ushort __devinit
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
+{
+       ushort wval, chksum;
+       ushort *wbuf;
+       int eep_addr;
+       ushort *charfields;
+
+       charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+       wbuf = (ushort *)cfg_buf;
+       chksum = 0;
+
+       for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+            eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+               wval = AdvReadEEPWord(iop_base, eep_addr);
+               chksum += wval; /* Checksum is calculated from word values. */
+               if (*charfields++) {
+                       *wbuf = le16_to_cpu(wval);
+               } else {
+                       *wbuf = wval;
+               }
+       }
+       /* Read checksum word. */
+       *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+       wbuf++;
+       charfields++;
+
+       /* Read rest of EEPROM not covered by the checksum. */
+       for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+            eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+               *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+               if (*charfields++) {
+                       *wbuf = le16_to_cpu(*wbuf);
+               }
+       }
+       return chksum;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static ushort __devinit
+AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
+{
+       ushort wval, chksum;
+       ushort *wbuf;
+       int eep_addr;
+       ushort *charfields;
+
+       charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+       wbuf = (ushort *)cfg_buf;
+       chksum = 0;
+
+       for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+            eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+               wval = AdvReadEEPWord(iop_base, eep_addr);
+               chksum += wval; /* Checksum is calculated from word values. */
+               if (*charfields++) {
+                       *wbuf = le16_to_cpu(wval);
+               } else {
+                       *wbuf = wval;
+               }
+       }
+       /* Read checksum word. */
+       *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+       wbuf++;
+       charfields++;
+
+       /* Read rest of EEPROM not covered by the checksum. */
+       for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+            eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+               *wbuf = AdvReadEEPWord(iop_base, eep_addr);
                if (*charfields++) {
-                       word = cpu_to_le16(*wbuf);
-               } else {
-                       word = *wbuf;
+                       *wbuf = le16_to_cpu(*wbuf);
                }
-               AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
-               AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
-                                    ASC_EEP_CMD_WRITE | addr);
-               AdvWaitEEPCmd(iop_base);
        }
-       AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
-       AdvWaitEEPCmd(iop_base);
-       return;
+       return chksum;
 }
 
-/* a_advlib.c */
 /*
- * AdvExeScsiQueue() - Send a request to the RISC microcode program.
- *
- *   Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
- *   add the carrier to the ICQ (Initiator Command Queue), and tickle the
- *   RISC to notify it a new command is ready to be executed.
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
  *
- * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
- * set to SCSI_MAX_RETRY.
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
- * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
- * for DMA addresses or math operations are byte swapped to little-endian
- * order.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
  *
- * Return:
- *      ADV_SUCCESS(1) - The request was successfully queued.
- *      ADV_BUSY(0) -    Resource unavailable; Retry again after pending
- *                       request completes.
- *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
- *                       host IC error.
+ * Note: Chip is stopped on entry.
  */
-static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
+static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
 {
-       ulong last_int_level;
        AdvPortAddr iop_base;
-       ADV_DCNT req_size;
-       ADV_PADDR req_paddr;
-       ADV_CARR_T *new_carrp;
-
-       ASC_ASSERT(scsiq != NULL);      /* 'scsiq' should never be NULL. */
-
-       /*
-        * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
-        */
-       if (scsiq->target_id > ADV_MAX_TID) {
-               scsiq->host_status = QHSTA_M_INVALID_DEVICE;
-               scsiq->done_status = QD_WITH_ERROR;
-               return ADV_ERROR;
-       }
+       ushort warn_code;
+       ADVEEP_3550_CONFIG eep_config;
 
        iop_base = asc_dvc->iop_base;
 
-       last_int_level = DvcEnterCritical();
-
-       /*
-        * Allocate a carrier ensuring at least one carrier always
-        * remains on the freelist and initialize fields.
-        */
-       if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
-               DvcLeaveCritical(last_int_level);
-               return ADV_BUSY;
-       }
-       asc_dvc->carr_freelist = (ADV_CARR_T *)
-           ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
-       asc_dvc->carr_pending_cnt++;
-
-       /*
-        * Set the carrier to be a stopper by setting 'next_vpa'
-        * to the stopper value. The current stopper will be changed
-        * below to point to the new stopper.
-        */
-       new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+       warn_code = 0;
 
        /*
-        * Clear the ADV_SCSI_REQ_Q done flag.
+        * Read the board's EEPROM configuration.
+        *
+        * Set default values if a bad checksum is found.
         */
-       scsiq->a_flag &= ~ADV_SCSIQ_DONE;
-
-       req_size = sizeof(ADV_SCSI_REQ_Q);
-       req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
-                                 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
-
-       ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
-       ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+       if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
+               warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
-       /* Wait for assertion before making little-endian */
-       req_paddr = cpu_to_le32(req_paddr);
+               /*
+                * Set EEPROM default values.
+                */
+               memcpy(&eep_config, &Default_3550_EEPROM_Config,
+                       sizeof(ADVEEP_3550_CONFIG));
 
-       /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
-       scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
-       scsiq->scsiq_rptr = req_paddr;
+               /*
+                * Assume the 6 byte board serial number that was read from
+                * EEPROM is correct even if the EEPROM checksum failed.
+                */
+               eep_config.serial_number_word3 =
+                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
 
-       scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
-       /*
-        * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
-        * order during initialization.
-        */
-       scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
+               eep_config.serial_number_word2 =
+                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
 
-       /*
-        * Use the current stopper to send the ADV_SCSI_REQ_Q command to
-        * the microcode. The newly allocated stopper will become the new
-        * stopper.
-        */
-       asc_dvc->icq_sp->areq_vpa = req_paddr;
+               eep_config.serial_number_word1 =
+                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
 
+               AdvSet3550EEPConfig(iop_base, &eep_config);
+       }
        /*
-        * Set the 'next_vpa' pointer for the old stopper to be the
-        * physical address of the new stopper. The RISC can only
-        * follow physical addresses.
+        * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+        * EEPROM configuration that was read.
+        *
+        * This is the mapping of EEPROM fields to Adv Library fields.
         */
-       asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
+       asc_dvc->wdtr_able = eep_config.wdtr_able;
+       asc_dvc->sdtr_able = eep_config.sdtr_able;
+       asc_dvc->ultra_able = eep_config.ultra_able;
+       asc_dvc->tagqng_able = eep_config.tagqng_able;
+       asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+       asc_dvc->max_host_qng = eep_config.max_host_qng;
+       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+       asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+       asc_dvc->start_motor = eep_config.start_motor;
+       asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+       asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+       asc_dvc->no_scam = eep_config.scam_tolerant;
+       asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+       asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+       asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
 
        /*
-        * Set the host adapter stopper pointer to point to the new carrier.
+        * Set the host maximum queuing (max. 253, min. 16) and the per device
+        * maximum queuing (max. 63, min. 4).
         */
-       asc_dvc->icq_sp = new_carrp;
-
-       if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
-           asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
-               /*
-                * Tickle the RISC to tell it to read its Command Queue Head pointer.
-                */
-               AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
-               if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
-                       /*
-                        * Clear the tickle value. In the ASC-3550 the RISC flag
-                        * command 'clr_tickle_a' does not work unless the host
-                        * value is cleared.
-                        */
-                       AdvWriteByteRegister(iop_base, IOPB_TICKLE,
-                                            ADV_TICKLE_NOP);
+       if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+               eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+       } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+               /* If the value is zero, assume it is uninitialized. */
+               if (eep_config.max_host_qng == 0) {
+                       eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+               } else {
+                       eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
                }
-       } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
-               /*
-                * Notify the RISC a carrier is ready by writing the physical
-                * address of the new carrier stopper to the COMMA register.
-                */
-               AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
-                                     le32_to_cpu(new_carrp->carr_pa));
        }
 
-       DvcLeaveCritical(last_int_level);
-
-       return ADV_SUCCESS;
-}
-
-/*
- * Reset SCSI Bus and purge all outstanding requests.
- *
- * Return Value:
- *      ADV_TRUE(1) -   All requests are purged and SCSI Bus is reset.
- *      ADV_FALSE(0) -  Microcode command failed.
- *      ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
- *                      may be hung which requires driver recovery.
- */
-static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
-{
-       int status;
+       if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+               eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+       } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+               /* If the value is zero, assume it is uninitialized. */
+               if (eep_config.max_dvc_qng == 0) {
+                       eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+               } else {
+                       eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+               }
+       }
 
        /*
-        * Send the SCSI Bus Reset idle start idle command which asserts
-        * the SCSI Bus Reset signal.
+        * If 'max_dvc_qng' is greater than 'max_host_qng', then
+        * set 'max_dvc_qng' to 'max_host_qng'.
         */
-       status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
-       if (status != ADV_TRUE) {
-               return status;
+       if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+               eep_config.max_dvc_qng = eep_config.max_host_qng;
        }
 
        /*
-        * Delay for the specified SCSI Bus Reset hold time.
-        *
-        * The hold time delay is done on the host because the RISC has no
-        * microsecond accurate timer.
+        * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+        * values based on possibly adjusted EEPROM values.
         */
-       DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
+       asc_dvc->max_host_qng = eep_config.max_host_qng;
+       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
        /*
-        * Send the SCSI Bus Reset end idle command which de-asserts
-        * the SCSI Bus Reset signal and purges any pending requests.
+        * If the EEPROM 'termination' field is set to automatic (0), then set
+        * the ADV_DVC_CFG 'termination' field to automatic also.
+        *
+        * If the termination is specified with a non-zero 'termination'
+        * value check that a legal value is set and set the ADV_DVC_CFG
+        * 'termination' field appropriately.
         */
-       status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
-       if (status != ADV_TRUE) {
-               return status;
+       if (eep_config.termination == 0) {
+               asc_dvc->cfg->termination = 0;  /* auto termination */
+       } else {
+               /* Enable manual control with low off / high off. */
+               if (eep_config.termination == 1) {
+                       asc_dvc->cfg->termination = TERM_CTL_SEL;
+
+                       /* Enable manual control with low off / high on. */
+               } else if (eep_config.termination == 2) {
+                       asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+
+                       /* Enable manual control with low on / high on. */
+               } else if (eep_config.termination == 3) {
+                       asc_dvc->cfg->termination =
+                           TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+               } else {
+                       /*
+                        * The EEPROM 'termination' field contains a bad value. Use
+                        * automatic termination instead.
+                        */
+                       asc_dvc->cfg->termination = 0;
+                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
+               }
        }
 
-       DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
-
-       return status;
+       return warn_code;
 }
 
 /*
- * Reset chip and SCSI Bus.
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
  *
- * Return Value:
- *      ADV_TRUE(1) -   Chip re-initialization and SCSI Bus Reset successful.
- *      ADV_FALSE(0) -  Chip re-initialization and SCSI Bus Reset failure.
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
  */
-static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
 {
-       int status;
-       ushort wdtr_able, sdtr_able, tagqng_able;
-       ushort ppr_able = 0;
-       uchar tid, max_cmd[ADV_MAX_TID + 1];
        AdvPortAddr iop_base;
-       ushort bios_sig;
+       ushort warn_code;
+       ADVEEP_38C0800_CONFIG eep_config;
+       uchar tid, termination;
+       ushort sdtr_speed = 0;
 
        iop_base = asc_dvc->iop_base;
 
+       warn_code = 0;
+
        /*
-        * Save current per TID negotiated values.
+        * Read the board's EEPROM configuration.
+        *
+        * Set default values if a bad checksum is found.
         */
-       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-       if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
-               AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
-       }
-       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-               AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                               max_cmd[tid]);
-       }
+       if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
+           eep_config.check_sum) {
+               warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
+               /*
+                * Set EEPROM default values.
+                */
+               memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
+                       sizeof(ADVEEP_38C0800_CONFIG));
+
+               /*
+                * Assume the 6 byte board serial number that was read from
+                * EEPROM is correct even if the EEPROM checksum failed.
+                */
+               eep_config.serial_number_word3 =
+                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+
+               eep_config.serial_number_word2 =
+                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+
+               eep_config.serial_number_word1 =
+                   AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+
+               AdvSet38C0800EEPConfig(iop_base, &eep_config);
+       }
        /*
-        * Force the AdvInitAsc3550/38C0800Driver() function to
-        * perform a SCSI Bus Reset by clearing the BIOS signature word.
-        * The initialization functions assumes a SCSI Bus Reset is not
-        * needed if the BIOS signature word is present.
+        * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+        * EEPROM configuration that was read.
+        *
+        * This is the mapping of EEPROM fields to Adv Library fields.
         */
-       AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
-       AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
+       asc_dvc->wdtr_able = eep_config.wdtr_able;
+       asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+       asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+       asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+       asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+       asc_dvc->tagqng_able = eep_config.tagqng_able;
+       asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+       asc_dvc->max_host_qng = eep_config.max_host_qng;
+       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+       asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+       asc_dvc->start_motor = eep_config.start_motor;
+       asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+       asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+       asc_dvc->no_scam = eep_config.scam_tolerant;
+       asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+       asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+       asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
 
        /*
-        * Stop chip and reset it.
+        * For every Target ID if any of its 'sdtr_speed[1234]' bits
+        * are set, then set an 'sdtr_able' bit for it.
         */
-       AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
-       AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
-       DvcSleepMilliSecond(100);
-       AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
-                            ADV_CTRL_REG_CMD_WR_IO_REG);
+       asc_dvc->sdtr_able = 0;
+       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+               if (tid == 0) {
+                       sdtr_speed = asc_dvc->sdtr_speed1;
+               } else if (tid == 4) {
+                       sdtr_speed = asc_dvc->sdtr_speed2;
+               } else if (tid == 8) {
+                       sdtr_speed = asc_dvc->sdtr_speed3;
+               } else if (tid == 12) {
+                       sdtr_speed = asc_dvc->sdtr_speed4;
+               }
+               if (sdtr_speed & ADV_MAX_TID) {
+                       asc_dvc->sdtr_able |= (1 << tid);
+               }
+               sdtr_speed >>= 4;
+       }
 
        /*
-        * Reset Adv Library error code, if any, and try
-        * re-initializing the chip.
+        * Set the host maximum queuing (max. 253, min. 16) and the per device
+        * maximum queuing (max. 63, min. 4).
         */
-       asc_dvc->err_code = 0;
-       if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
-               status = AdvInitAsc38C1600Driver(asc_dvc);
-       } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
-               status = AdvInitAsc38C0800Driver(asc_dvc);
-       } else {
-               status = AdvInitAsc3550Driver(asc_dvc);
+       if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+               eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+       } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+               /* If the value is zero, assume it is uninitialized. */
+               if (eep_config.max_host_qng == 0) {
+                       eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+               } else {
+                       eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+               }
        }
 
-       /* Translate initialization return value to status value. */
-       if (status == 0) {
-               status = ADV_TRUE;
-       } else {
-               status = ADV_FALSE;
+       if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+               eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+       } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+               /* If the value is zero, assume it is uninitialized. */
+               if (eep_config.max_dvc_qng == 0) {
+                       eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+               } else {
+                       eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+               }
        }
 
        /*
-        * Restore the BIOS signature word.
+        * If 'max_dvc_qng' is greater than 'max_host_qng', then
+        * set 'max_dvc_qng' to 'max_host_qng'.
         */
-       AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+       if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+               eep_config.max_dvc_qng = eep_config.max_host_qng;
+       }
 
        /*
-        * Restore per TID negotiated values.
+        * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+        * values based on possibly adjusted EEPROM values.
         */
-       AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-       AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-       if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
-               AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+       asc_dvc->max_host_qng = eep_config.max_host_qng;
+       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+       /*
+        * If the EEPROM 'termination' field is set to automatic (0), then set
+        * the ADV_DVC_CFG 'termination' field to automatic also.
+        *
+        * If the termination is specified with a non-zero 'termination'
+        * value check that a legal value is set and set the ADV_DVC_CFG
+        * 'termination' field appropriately.
+        */
+       if (eep_config.termination_se == 0) {
+               termination = 0;        /* auto termination for SE */
+       } else {
+               /* Enable manual control with low off / high off. */
+               if (eep_config.termination_se == 1) {
+                       termination = 0;
+
+                       /* Enable manual control with low off / high on. */
+               } else if (eep_config.termination_se == 2) {
+                       termination = TERM_SE_HI;
+
+                       /* Enable manual control with low on / high on. */
+               } else if (eep_config.termination_se == 3) {
+                       termination = TERM_SE;
+               } else {
+                       /*
+                        * The EEPROM 'termination_se' field contains a bad value.
+                        * Use automatic termination instead.
+                        */
+                       termination = 0;
+                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
+               }
        }
-       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-       for (tid = 0; tid <= ADV_MAX_TID; tid++) {
-               AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                                max_cmd[tid]);
+
+       if (eep_config.termination_lvd == 0) {
+               asc_dvc->cfg->termination = termination;        /* auto termination for LVD */
+       } else {
+               /* Enable manual control with low off / high off. */
+               if (eep_config.termination_lvd == 1) {
+                       asc_dvc->cfg->termination = termination;
+
+                       /* Enable manual control with low off / high on. */
+               } else if (eep_config.termination_lvd == 2) {
+                       asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+                       /* Enable manual control with low on / high on. */
+               } else if (eep_config.termination_lvd == 3) {
+                       asc_dvc->cfg->termination = termination | TERM_LVD;
+               } else {
+                       /*
+                        * The EEPROM 'termination_lvd' field contains a bad value.
+                        * Use automatic termination instead.
+                        */
+                       asc_dvc->cfg->termination = termination;
+                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
+               }
        }
 
-       return status;
+       return warn_code;
 }
 
 /*
- * Adv Library Interrupt Service Routine
- *
- *  This function is called by a driver's interrupt service routine.
- *  The function disables and re-enables interrupts.
+ * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
+ * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
  *
- *  When a microcode idle command is completed, the ADV_DVC_VAR
- *  'idle_cmd_done' field is set to ADV_TRUE.
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
- *  Note: AdvISR() can be called when interrupts are disabled or even
- *  when there is no hardware interrupt condition present. It will
- *  always check for completed idle commands and microcode requests.
- *  This is an important feature that shouldn't be changed because it
- *  allows commands to be completed from polling mode loops.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
  *
- * Return:
- *   ADV_TRUE(1) - interrupt was pending
- *   ADV_FALSE(0) - no interrupt was pending
+ * Note: Chip is stopped on entry.
  */
-static int AdvISR(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
 {
        AdvPortAddr iop_base;
-       uchar int_stat;
-       ushort target_bit;
-       ADV_CARR_T *free_carrp;
-       ADV_VADDR irq_next_vpa;
-       int flags;
-       ADV_SCSI_REQ_Q *scsiq;
-
-       flags = DvcEnterCritical();
+       ushort warn_code;
+       ADVEEP_38C1600_CONFIG eep_config;
+       uchar tid, termination;
+       ushort sdtr_speed = 0;
 
        iop_base = asc_dvc->iop_base;
 
-       /* Reading the register clears the interrupt. */
-       int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
-
-       if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
-                        ADV_INTR_STATUS_INTRC)) == 0) {
-               DvcLeaveCritical(flags);
-               return ADV_FALSE;
-       }
+       warn_code = 0;
 
        /*
-        * Notify the driver of an asynchronous microcode condition by
-        * calling the ADV_DVC_VAR.async_callback function. The function
-        * is passed the microcode ASC_MC_INTRB_CODE byte value.
+        * Read the board's EEPROM configuration.
+        *
+        * Set default values if a bad checksum is found.
         */
-       if (int_stat & ADV_INTR_STATUS_INTRB) {
-               uchar intrb_code;
-
-               AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
-
-               if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
-                   asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
-                       if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
-                           asc_dvc->carr_pending_cnt != 0) {
-                               AdvWriteByteRegister(iop_base, IOPB_TICKLE,
-                                                    ADV_TICKLE_A);
-                               if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
-                                       AdvWriteByteRegister(iop_base,
-                                                            IOPB_TICKLE,
-                                                            ADV_TICKLE_NOP);
-                               }
-                       }
-               }
-
-               if (asc_dvc->async_callback != 0) {
-                       (*asc_dvc->async_callback) (asc_dvc, intrb_code);
-               }
-       }
+       if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
+           eep_config.check_sum) {
+               struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
+               warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
-       /*
-        * Check if the IRQ stopper carrier contains a completed request.
-        */
-       while (((irq_next_vpa =
-                le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
                /*
-                * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
-                * The RISC will have set 'areq_vpa' to a virtual address.
-                *
-                * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
-                * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
-                * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
-                * in AdvExeScsiQueue().
+                * Set EEPROM default values.
                 */
-               scsiq = (ADV_SCSI_REQ_Q *)
-                   ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+               memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
+                       sizeof(ADVEEP_38C1600_CONFIG));
 
-               /*
-                * Request finished with good status and the queue was not
-                * DMAed to host memory by the firmware. Set all status fields
-                * to indicate good status.
-                */
-               if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
-                       scsiq->done_status = QD_NO_ERROR;
-                       scsiq->host_status = scsiq->scsi_status = 0;
-                       scsiq->data_cnt = 0L;
+               if (PCI_FUNC(pdev->devfn) != 0) {
+                       u8 ints;
+                       /*
+                        * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
+                        * and old Mac system booting problem. The Expansion
+                        * ROM must be disabled in Function 1 for these systems
+                        */
+                       eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
+                       /*
+                        * Clear the INTAB (bit 11) if the GPIO 0 input
+                        * indicates the Function 1 interrupt line is wired
+                        * to INTB.
+                        *
+                        * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
+                        *   1 - Function 1 interrupt line wired to INT A.
+                        *   0 - Function 1 interrupt line wired to INT B.
+                        *
+                        * Note: Function 0 is always wired to INTA.
+                        * Put all 5 GPIO bits in input mode and then read
+                        * their input values.
+                        */
+                       AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
+                       ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
+                       if ((ints & 0x01) == 0)
+                               eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
                }
 
                /*
-                * Advance the stopper pointer to the next carrier
-                * ignoring the lower four bits. Free the previous
-                * stopper carrier.
+                * Assume the 6 byte board serial number that was read from
+                * EEPROM is correct even if the EEPROM checksum failed.
                 */
-               free_carrp = asc_dvc->irq_sp;
-               asc_dvc->irq_sp = (ADV_CARR_T *)
-                   ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
-
-               free_carrp->next_vpa =
-                   cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-               asc_dvc->carr_freelist = free_carrp;
-               asc_dvc->carr_pending_cnt--;
+               eep_config.serial_number_word3 =
+                       AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+               eep_config.serial_number_word2 =
+                       AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+               eep_config.serial_number_word1 =
+                       AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
 
-               ASC_ASSERT(scsiq != NULL);
-               target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+               AdvSet38C1600EEPConfig(iop_base, &eep_config);
+       }
 
-               /*
-                * Clear request microcode control flag.
-                */
-               scsiq->cntl = 0;
+       /*
+        * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+        * EEPROM configuration that was read.
+        *
+        * This is the mapping of EEPROM fields to Adv Library fields.
+        */
+       asc_dvc->wdtr_able = eep_config.wdtr_able;
+       asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+       asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+       asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+       asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+       asc_dvc->ppr_able = 0;
+       asc_dvc->tagqng_able = eep_config.tagqng_able;
+       asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+       asc_dvc->max_host_qng = eep_config.max_host_qng;
+       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+       asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
+       asc_dvc->start_motor = eep_config.start_motor;
+       asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+       asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+       asc_dvc->no_scam = eep_config.scam_tolerant;
 
-               /*
-                * If the command that completed was a SCSI INQUIRY and
-                * LUN 0 was sent the command, then process the INQUIRY
-                * command information for the device.
-                *
-                * Note: If data returned were either VPD or CmdDt data,
-                * don't process the INQUIRY command information for
-                * the device, otherwise may erroneously set *_able bits.
-                */
-               if (scsiq->done_status == QD_NO_ERROR &&
-                   scsiq->cdb[0] == INQUIRY &&
-                   scsiq->target_lun == 0 &&
-                   (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
-                   == ADV_INQ_RTN_STD_INQUIRY_DATA) {
-                       AdvInquiryHandling(asc_dvc, scsiq);
+       /*
+        * For every Target ID if any of its 'sdtr_speed[1234]' bits
+        * are set, then set an 'sdtr_able' bit for it.
+        */
+       asc_dvc->sdtr_able = 0;
+       for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+               if (tid == 0) {
+                       sdtr_speed = asc_dvc->sdtr_speed1;
+               } else if (tid == 4) {
+                       sdtr_speed = asc_dvc->sdtr_speed2;
+               } else if (tid == 8) {
+                       sdtr_speed = asc_dvc->sdtr_speed3;
+               } else if (tid == 12) {
+                       sdtr_speed = asc_dvc->sdtr_speed4;
                }
-
-               /*
-                * Notify the driver of the completed request by passing
-                * the ADV_SCSI_REQ_Q pointer to its callback function.
-                */
-               scsiq->a_flag |= ADV_SCSIQ_DONE;
-               (*asc_dvc->isr_callback) (asc_dvc, scsiq);
-               /*
-                * Note: After the driver callback function is called, 'scsiq'
-                * can no longer be referenced.
-                *
-                * Fall through and continue processing other completed
-                * requests...
-                */
-
-               /*
-                * Disable interrupts again in case the driver inadvertently
-                * enabled interrupts in its callback function.
-                *
-                * The DvcEnterCritical() return value is ignored, because
-                * the 'flags' saved when AdvISR() was first entered will be
-                * used to restore the interrupt flag on exit.
-                */
-               (void)DvcEnterCritical();
+               if (sdtr_speed & ASC_MAX_TID) {
+                       asc_dvc->sdtr_able |= (1 << tid);
+               }
+               sdtr_speed >>= 4;
        }
-       DvcLeaveCritical(flags);
-       return ADV_TRUE;
-}
-
-/*
- * Send an idle command to the chip and wait for completion.
- *
- * Command completion is polled for once per microsecond.
- *
- * The function can be called from anywhere including an interrupt handler.
- * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
- * functions to prevent reentrancy.
- *
- * Return Values:
- *   ADV_TRUE - command completed successfully
- *   ADV_FALSE - command failed
- *   ADV_ERROR - command timed out
- */
-static int
-AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
-              ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
-{
-       ulong last_int_level;
-       int result;
-       ADV_DCNT i, j;
-       AdvPortAddr iop_base;
 
-       last_int_level = DvcEnterCritical();
+       /*
+        * Set the host maximum queuing (max. 253, min. 16) and the per device
+        * maximum queuing (max. 63, min. 4).
+        */
+       if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+               eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+       } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+               /* If the value is zero, assume it is uninitialized. */
+               if (eep_config.max_host_qng == 0) {
+                       eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+               } else {
+                       eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+               }
+       }
 
-       iop_base = asc_dvc->iop_base;
+       if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+               eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+       } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+               /* If the value is zero, assume it is uninitialized. */
+               if (eep_config.max_dvc_qng == 0) {
+                       eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+               } else {
+                       eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+               }
+       }
 
        /*
-        * Clear the idle command status which is set by the microcode
-        * to a non-zero value to indicate when the command is completed.
-        * The non-zero result is one of the IDLE_CMD_STATUS_* values
-        * defined in a_advlib.h.
+        * If 'max_dvc_qng' is greater than 'max_host_qng', then
+        * set 'max_dvc_qng' to 'max_host_qng'.
         */
-       AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
+       if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+               eep_config.max_dvc_qng = eep_config.max_host_qng;
+       }
 
        /*
-        * Write the idle command value after the idle command parameter
-        * has been written to avoid a race condition. If the order is not
-        * followed, the microcode may process the idle command before the
-        * parameters have been written to LRAM.
+        * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
+        * values based on possibly adjusted EEPROM values.
         */
-       AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
-                               cpu_to_le32(idle_cmd_parameter));
-       AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+       asc_dvc->max_host_qng = eep_config.max_host_qng;
+       asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
        /*
-        * Tickle the RISC to tell it to process the idle command.
+        * If the EEPROM 'termination' field is set to automatic (0), then set
+        * the ASC_DVC_CFG 'termination' field to automatic also.
+        *
+        * If the termination is specified with a non-zero 'termination'
+        * value check that a legal value is set and set the ASC_DVC_CFG
+        * 'termination' field appropriately.
         */
-       AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
-       if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
-               /*
-                * Clear the tickle value. In the ASC-3550 the RISC flag
-                * command 'clr_tickle_b' does not work unless the host
-                * value is cleared.
-                */
-               AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+       if (eep_config.termination_se == 0) {
+               termination = 0;        /* auto termination for SE */
+       } else {
+               /* Enable manual control with low off / high off. */
+               if (eep_config.termination_se == 1) {
+                       termination = 0;
+
+                       /* Enable manual control with low off / high on. */
+               } else if (eep_config.termination_se == 2) {
+                       termination = TERM_SE_HI;
+
+                       /* Enable manual control with low on / high on. */
+               } else if (eep_config.termination_se == 3) {
+                       termination = TERM_SE;
+               } else {
+                       /*
+                        * The EEPROM 'termination_se' field contains a bad value.
+                        * Use automatic termination instead.
+                        */
+                       termination = 0;
+                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
+               }
        }
 
-       /* Wait for up to 100 millisecond for the idle command to timeout. */
-       for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
-               /* Poll once each microsecond for command completion. */
-               for (j = 0; j < SCSI_US_PER_MSEC; j++) {
-                       AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
-                                       result);
-                       if (result != 0) {
-                               DvcLeaveCritical(last_int_level);
-                               return result;
-                       }
-                       DvcDelayMicroSecond(asc_dvc, (ushort)1);
+       if (eep_config.termination_lvd == 0) {
+               asc_dvc->cfg->termination = termination;        /* auto termination for LVD */
+       } else {
+               /* Enable manual control with low off / high off. */
+               if (eep_config.termination_lvd == 1) {
+                       asc_dvc->cfg->termination = termination;
+
+                       /* Enable manual control with low off / high on. */
+               } else if (eep_config.termination_lvd == 2) {
+                       asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+                       /* Enable manual control with low on / high on. */
+               } else if (eep_config.termination_lvd == 3) {
+                       asc_dvc->cfg->termination = termination | TERM_LVD;
+               } else {
+                       /*
+                        * The EEPROM 'termination_lvd' field contains a bad value.
+                        * Use automatic termination instead.
+                        */
+                       asc_dvc->cfg->termination = termination;
+                       warn_code |= ASC_WARN_EEPROM_TERMINATION;
                }
        }
 
-       ASC_ASSERT(0);          /* The idle command should never timeout. */
-       DvcLeaveCritical(last_int_level);
-       return ADV_ERROR;
+       return warn_code;
 }
 
 /*
- * Inquiry Information Byte 7 Handling
+ * Initialize the ADV_DVC_VAR structure.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
- * Handle SCSI Inquiry Command information for a device by setting
- * microcode operating variables that affect WDTR, SDTR, and Tag
- * Queuing.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
  */
-static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
+static int __devinit
+AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
 {
-       AdvPortAddr iop_base;
-       uchar tid;
-       ADV_SCSI_INQUIRY *inq;
-       ushort tidmask;
-       ushort cfg_word;
+       struct asc_board *board = shost_priv(shost);
+       ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var;
+       unsigned short warn_code = 0;
+       AdvPortAddr iop_base = asc_dvc->iop_base;
+       u16 cmd;
+       int status;
+
+       asc_dvc->err_code = 0;
 
        /*
-        * AdvInquiryHandling() requires up to INQUIRY information Byte 7
-        * to be available.
-        *
-        * If less than 8 bytes of INQUIRY information were requested or less
-        * than 8 bytes were transferred, then return. cdb[4] is the request
-        * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
-        * microcode to the transfer residual count.
+        * Save the state of the PCI Configuration Command Register
+        * "Parity Error Response Control" Bit. If the bit is clear (0),
+        * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+        * DMA parity errors.
         */
+       asc_dvc->cfg->control_flag = 0;
+       pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+       if ((cmd & PCI_COMMAND_PARITY) == 0)
+               asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
 
-       if (scsiq->cdb[4] < 8 ||
-           (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
-               return;
-       }
+       asc_dvc->cfg->chip_version =
+           AdvGetChipVersion(iop_base, asc_dvc->bus_type);
 
-       iop_base = asc_dvc->iop_base;
-       tid = scsiq->target_id;
+       ASC_DBG(1, "iopb_chip_id_1: 0x%x 0x%x\n",
+                (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+                (ushort)ADV_CHIP_ID_BYTE);
 
-       inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
+       ASC_DBG(1, "iopw_chip_id_0: 0x%x 0x%x\n",
+                (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+                (ushort)ADV_CHIP_ID_WORD);
 
        /*
-        * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
+        * Reset the chip to start and allow register writes.
         */
-       if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
-               return;
+       if (AdvFindSignature(iop_base) == 0) {
+               asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+               return ADV_ERROR;
        } else {
                /*
-                * INQUIRY Byte 7 Handling
-                *
-                * Use a device's INQUIRY byte 7 to determine whether it
-                * supports WDTR, SDTR, and Tag Queuing. If the feature
-                * is enabled in the EEPROM and the device supports the
-                * feature, then enable it in the microcode.
-                */
-
-               tidmask = ADV_TID_TO_TIDMASK(tid);
-
-               /*
-                * Wide Transfers
-                *
-                * If the EEPROM enabled WDTR for the device and the device
-                * supports wide bus (16 bit) transfers, then turn on the
-                * device's 'wdtr_able' bit and write the new value to the
-                * microcode.
+                * The caller must set 'chip_type' to a valid setting.
                 */
-               if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
-                       AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
-                       if ((cfg_word & tidmask) == 0) {
-                               cfg_word |= tidmask;
-                               AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
-                                                cfg_word);
-
-                               /*
-                                * Clear the microcode "SDTR negotiation" and "WDTR
-                                * negotiation" done indicators for the target to cause
-                                * it to negotiate with the new setting set above.
-                                * WDTR when accepted causes the target to enter
-                                * asynchronous mode, so SDTR must be negotiated.
-                                */
-                               AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
-                                               cfg_word);
-                               cfg_word &= ~tidmask;
-                               AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
-                                                cfg_word);
-                               AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
-                                               cfg_word);
-                               cfg_word &= ~tidmask;
-                               AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
-                                                cfg_word);
-                       }
+               if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+                   asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+                   asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+                       asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+                       return ADV_ERROR;
                }
 
                /*
-                * Synchronous Transfers
-                *
-                * If the EEPROM enabled SDTR for the device and the device
-                * supports synchronous transfers, then turn on the device's
-                * 'sdtr_able' bit. Write the new value to the microcode.
+                * Reset Chip.
                 */
-               if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
-                       AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
-                       if ((cfg_word & tidmask) == 0) {
-                               cfg_word |= tidmask;
-                               AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
-                                                cfg_word);
+               AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+                                    ADV_CTRL_REG_CMD_RESET);
+               mdelay(100);
+               AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+                                    ADV_CTRL_REG_CMD_WR_IO_REG);
 
-                               /*
-                                * Clear the microcode "SDTR negotiation" done indicator
-                                * for the target to cause it to negotiate with the new
-                                * setting set above.
-                                */
-                               AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
-                                               cfg_word);
-                               cfg_word &= ~tidmask;
-                               AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
-                                                cfg_word);
-                       }
-               }
-               /*
-                * If the Inquiry data included enough space for the SPI-3
-                * Clocking field, then check if DT mode is supported.
-                */
-               if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
-                   (scsiq->cdb[4] >= 57 ||
-                    (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
-                       /*
-                        * PPR (Parallel Protocol Request) Capable
-                        *
-                        * If the device supports DT mode, then it must be PPR capable.
-                        * The PPR message will be used in place of the SDTR and WDTR
-                        * messages to negotiate synchronous speed and offset, transfer
-                        * width, and protocol options.
-                        */
-                       if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
-                               AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
-                                               asc_dvc->ppr_able);
-                               asc_dvc->ppr_able |= tidmask;
-                               AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
-                                                asc_dvc->ppr_able);
-                       }
+               if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+                       status = AdvInitFrom38C1600EEP(asc_dvc);
+               } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+                       status = AdvInitFrom38C0800EEP(asc_dvc);
+               } else {
+                       status = AdvInitFrom3550EEP(asc_dvc);
                }
+               warn_code |= status;
+       }
 
-               /*
-                * If the EEPROM enabled Tag Queuing for the device and the
-                * device supports Tag Queueing, then turn on the device's
-                * 'tagqng_enable' bit in the microcode and set the microcode
-                * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
-                * value.
-                *
-                * Tag Queuing is disabled for the BIOS which runs in polled
-                * mode and would see no benefit from Tag Queuing. Also by
-                * disabling Tag Queuing in the BIOS devices with Tag Queuing
-                * bugs will at least work with the BIOS.
-                */
-               if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
-                       AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
-                       cfg_word |= tidmask;
-                       AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
-                                        cfg_word);
+       if (warn_code != 0)
+               shost_printk(KERN_WARNING, shost, "warning: 0x%x\n", warn_code);
 
-                       AdvWriteByteLram(iop_base,
-                                        ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                                        asc_dvc->max_dvc_qng);
-               }
-       }
+       if (asc_dvc->err_code)
+               shost_printk(KERN_ERR, shost, "error code 0x%x\n",
+                               asc_dvc->err_code);
+
+       return asc_dvc->err_code;
 }
+#endif
 
-MODULE_LICENSE("Dual BSD/GPL");
+static struct scsi_host_template advansys_template = {
+       .proc_name = DRV_NAME,
+#ifdef CONFIG_PROC_FS
+       .proc_info = advansys_proc_info,
+#endif
+       .name = DRV_NAME,
+       .info = advansys_info,
+       .queuecommand = advansys_queuecommand,
+       .eh_bus_reset_handler = advansys_reset,
+       .bios_param = advansys_biosparam,
+       .slave_configure = advansys_slave_configure,
+       /*
+        * Because the driver may control an ISA adapter 'unchecked_isa_dma'
+        * must be set. The flag will be cleared in advansys_board_found
+        * for non-ISA adapters.
+        */
+       .unchecked_isa_dma = 1,
+       /*
+        * All adapters controlled by this driver are capable of large
+        * scatter-gather lists. According to the mid-level SCSI documentation
+        * this obviates any performance gain provided by setting
+        * 'use_clustering'. But empirically while CPU utilization is increased
+        * by enabling clustering, I/O throughput increases as well.
+        */
+       .use_clustering = ENABLE_CLUSTERING,
+};
 
-static struct Scsi_Host *__devinit
-advansys_board_found(int iop, struct device *dev, int bus_type)
+static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost)
 {
-       struct Scsi_Host *shost;
-       struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
-       asc_board_t *boardp;
-       ASC_DVC_VAR *asc_dvc_varp = NULL;
-       ADV_DVC_VAR *adv_dvc_varp = NULL;
-       adv_sgblk_t *sgp = NULL;
-       int share_irq = FALSE;
-       int iolen = 0;
-       ADV_PADDR pci_memory_address;
+       struct asc_board *board = shost_priv(shost);
+       struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
+       int req_cnt = 0;
+       adv_req_t *reqp = NULL;
+       int sg_cnt = 0;
+       adv_sgblk_t *sgp;
        int warn_code, err_code;
-       int ret;
 
        /*
-        * Adapter found.
-        *
-        * Register the adapter, get its configuration, and
-        * initialize it.
+        * Allocate buffer carrier structures. The total size
+        * is about 4 KB, so allocate all at once.
         */
-       ASC_DBG(2, "advansys_board_found: scsi_register()\n");
-       shost = scsi_register(&driver_template, sizeof(asc_board_t));
+       adv_dvc->carrier_buf = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
+       ASC_DBG(1, "carrier_buf 0x%p\n", adv_dvc->carrier_buf);
 
-       if (!shost)
-               return NULL;
+       if (!adv_dvc->carrier_buf)
+               goto kmalloc_failed;
+
+       /*
+        * Allocate up to 'max_host_qng' request structures for the Wide
+        * board. The total size is about 16 KB, so allocate all at once.
+        * If the allocation fails decrement and try again.
+        */
+       for (req_cnt = adv_dvc->max_host_qng; req_cnt > 0; req_cnt--) {
+               reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
 
-       /* Save a pointer to the Scsi_Host of each board found. */
-       asc_host[asc_board_count++] = shost;
+               ASC_DBG(1, "reqp 0x%p, req_cnt %d, bytes %lu\n", reqp, req_cnt,
+                        (ulong)sizeof(adv_req_t) * req_cnt);
+
+               if (reqp)
+                       break;
+       }
 
-       /* Initialize private per board data */
-       boardp = ASC_BOARDP(shost);
-       memset(boardp, 0, sizeof(asc_board_t));
-       boardp->id = asc_board_count - 1;
+       if (!reqp)
+               goto kmalloc_failed;
 
-       /* Initialize spinlock. */
-       spin_lock_init(&boardp->lock);
+       adv_dvc->orig_reqp = reqp;
 
        /*
-        * Handle both narrow and wide boards.
-        *
-        * If a Wide board was detected, set the board structure
-        * wide board flag. Set-up the board structure based on
-        * the board type.
+        * Allocate up to ADV_TOT_SG_BLOCK request structures for
+        * the Wide board. Each structure is about 136 bytes.
         */
-#ifdef CONFIG_PCI
-       if (bus_type == ASC_IS_PCI &&
-           (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
-            pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
-            pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
-               boardp->flags |= ASC_IS_WIDE_BOARD;
+       board->adv_sgblkp = NULL;
+       for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+               sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
+
+               if (!sgp)
+                       break;
+
+               sgp->next_sgblkp = board->adv_sgblkp;
+               board->adv_sgblkp = sgp;
+
        }
-#endif /* CONFIG_PCI */
+
+       ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t),
+                sizeof(adv_sgblk_t) * sg_cnt);
+
+       if (!board->adv_sgblkp)
+               goto kmalloc_failed;
+
+       /*
+        * Point 'adv_reqp' to the request structures and
+        * link them together.
+        */
+       req_cnt--;
+       reqp[req_cnt].next_reqp = NULL;
+       for (; req_cnt > 0; req_cnt--) {
+               reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
+       }
+       board->adv_reqp = &reqp[0];
+
+       if (adv_dvc->chip_type == ADV_CHIP_ASC3550) {
+               ASC_DBG(2, "AdvInitAsc3550Driver()\n");
+               warn_code = AdvInitAsc3550Driver(adv_dvc);
+       } else if (adv_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+               ASC_DBG(2, "AdvInitAsc38C0800Driver()\n");
+               warn_code = AdvInitAsc38C0800Driver(adv_dvc);
+       } else {
+               ASC_DBG(2, "AdvInitAsc38C1600Driver()\n");
+               warn_code = AdvInitAsc38C1600Driver(adv_dvc);
+       }
+       err_code = adv_dvc->err_code;
+
+       if (warn_code || err_code) {
+               shost_printk(KERN_WARNING, shost, "error: warn 0x%x, error "
+                       "0x%x\n", warn_code, err_code);
+       }
+
+       goto exit;
+
+ kmalloc_failed:
+       shost_printk(KERN_ERR, shost, "error: kmalloc() failed\n");
+       err_code = ADV_ERROR;
+ exit:
+       return err_code;
+}
+
+static void advansys_wide_free_mem(struct asc_board *board)
+{
+       struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
+       kfree(adv_dvc->carrier_buf);
+       adv_dvc->carrier_buf = NULL;
+       kfree(adv_dvc->orig_reqp);
+       adv_dvc->orig_reqp = board->adv_reqp = NULL;
+       while (board->adv_sgblkp) {
+               adv_sgblk_t *sgp = board->adv_sgblkp;
+               board->adv_sgblkp = sgp->next_sgblkp;
+               kfree(sgp);
+       }
+}
+
+static int __devinit advansys_board_found(struct Scsi_Host *shost,
+                                         unsigned int iop, int bus_type)
+{
+       struct pci_dev *pdev;
+       struct asc_board *boardp = shost_priv(shost);
+       ASC_DVC_VAR *asc_dvc_varp = NULL;
+       ADV_DVC_VAR *adv_dvc_varp = NULL;
+       int share_irq, warn_code, ret;
+
+       pdev = (bus_type == ASC_IS_PCI) ? to_pci_dev(boardp->dev) : NULL;
 
        if (ASC_NARROW_BOARD(boardp)) {
-               ASC_DBG(1, "advansys_board_found: narrow board\n");
+               ASC_DBG(1, "narrow board\n");
                asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
                asc_dvc_varp->bus_type = bus_type;
                asc_dvc_varp->drv_ptr = boardp;
                asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
-               asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
                asc_dvc_varp->iop_base = iop;
-               asc_dvc_varp->isr_callback = asc_isr_callback;
        } else {
-               ASC_DBG(1, "advansys_board_found: wide board\n");
+#ifdef CONFIG_PCI
                adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
                adv_dvc_varp->drv_ptr = boardp;
                adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
-               adv_dvc_varp->isr_callback = adv_isr_callback;
-               adv_dvc_varp->async_callback = adv_async_callback;
-#ifdef CONFIG_PCI
                if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
-                       ASC_DBG(1, "advansys_board_found: ASC-3550\n");
+                       ASC_DBG(1, "wide board ASC-3550\n");
                        adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
                } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
-                       ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
+                       ASC_DBG(1, "wide board ASC-38C0800\n");
                        adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
                } else {
-                       ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
+                       ASC_DBG(1, "wide board ASC-38C1600\n");
                        adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
                }
-#endif /* CONFIG_PCI */
 
-               /*
-                * Map the board's registers into virtual memory for
-                * PCI slave access. Only memory accesses are used to
-                * access the board's registers.
-                *
-                * Note: The PCI register base address is not always
-                * page aligned, but the address passed to ioremap()
-                * must be page aligned. It is guaranteed that the
-                * PCI register base address will not cross a page
-                * boundary.
-                */
-               if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-                       iolen = ADV_3550_IOLEN;
-               } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-                       iolen = ADV_38C0800_IOLEN;
-               } else {
-                       iolen = ADV_38C1600_IOLEN;
-               }
-#ifdef CONFIG_PCI
-               pci_memory_address = pci_resource_start(pdev, 1);
-               ASC_DBG1(1,
-                        "advansys_board_found: pci_memory_address: 0x%lx\n",
-                        (ulong)pci_memory_address);
-               if ((boardp->ioremap_addr =
-                    ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
-                       ASC_PRINT3
-                           ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
-                            boardp->id, pci_memory_address, iolen);
-                       scsi_unregister(shost);
-                       asc_board_count--;
-                       return NULL;
+               boardp->asc_n_io_port = pci_resource_len(pdev, 1);
+               boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
+                                              boardp->asc_n_io_port);
+               if (!boardp->ioremap_addr) {
+                       shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) "
+                                       "returned NULL\n",
+                                       (long)pci_resource_start(pdev, 1),
+                                       boardp->asc_n_io_port);
+                       ret = -ENODEV;
+                       goto err_shost;
                }
-               ASC_DBG1(1,
-                        "advansys_board_found: ioremap_addr: 0x%lx\n",
-                        (ulong)boardp->ioremap_addr);
-               adv_dvc_varp->iop_base = (AdvPortAddr)
-                   (boardp->ioremap_addr +
-                    (pci_memory_address - (pci_memory_address & PAGE_MASK)));
-               ASC_DBG1(1,
-                        "advansys_board_found: iop_base: 0x%lx\n",
-                        adv_dvc_varp->iop_base);
-#endif /* CONFIG_PCI */
+               adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr;
+               ASC_DBG(1, "iop_base: 0x%p\n", adv_dvc_varp->iop_base);
 
                /*
                 * Even though it isn't used to access wide boards, other
@@ -17907,9 +13445,9 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                 */
                boardp->ioport = iop;
 
-               ASC_DBG2(1,
-                        "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
-                        (ushort)inp(iop + 1), (ushort)inpw(iop));
+               ASC_DBG(1, "iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
+                               (ushort)inp(iop + 1), (ushort)inpw(iop));
+#endif /* CONFIG_PCI */
        }
 
 #ifdef CONFIG_PROC_FS
@@ -17917,18 +13455,16 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
         * Allocate buffer for printing information from
         * /proc/scsi/advansys/[0...].
         */
-       if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
-               ASC_PRINT3
-                   ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n",
-                    boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
-               scsi_unregister(shost);
-               asc_board_count--;
-               return NULL;
+       boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
+       if (!boardp->prtbuf) {
+               shost_printk(KERN_ERR, shost, "kmalloc(%d) returned NULL\n",
+                               ASC_PRTBUF_SIZE);
+               ret = -ENOMEM;
+               goto err_unmap;
        }
 #endif /* CONFIG_PROC_FS */
 
        if (ASC_NARROW_BOARD(boardp)) {
-               asc_dvc_varp->cfg->dev = dev;
                /*
                 * Set the board bus type and PCI IRQ before
                 * calling AscInitGetConfig().
@@ -17937,127 +13473,56 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 #ifdef CONFIG_ISA
                case ASC_IS_ISA:
                        shost->unchecked_isa_dma = TRUE;
-                       share_irq = FALSE;
+                       share_irq = 0;
                        break;
                case ASC_IS_VL:
                        shost->unchecked_isa_dma = FALSE;
-                       share_irq = FALSE;
+                       share_irq = 0;
                        break;
                case ASC_IS_EISA:
                        shost->unchecked_isa_dma = FALSE;
-                       share_irq = TRUE;
+                       share_irq = IRQF_SHARED;
                        break;
 #endif /* CONFIG_ISA */
 #ifdef CONFIG_PCI
                case ASC_IS_PCI:
-                       shost->irq = asc_dvc_varp->irq_no = pdev->irq;
-                       asc_dvc_varp->cfg->pci_slot_info =
-                           ASC_PCI_MKID(pdev->bus->number,
-                                        PCI_SLOT(pdev->devfn),
-                                        PCI_FUNC(pdev->devfn));
                        shost->unchecked_isa_dma = FALSE;
-                       share_irq = TRUE;
+                       share_irq = IRQF_SHARED;
                        break;
 #endif /* CONFIG_PCI */
                default:
-                       ASC_PRINT2
-                           ("advansys_board_found: board %d: unknown adapter type: %d\n",
-                            boardp->id, asc_dvc_varp->bus_type);
+                       shost_printk(KERN_ERR, shost, "unknown adapter type: "
+                                       "%d\n", asc_dvc_varp->bus_type);
                        shost->unchecked_isa_dma = TRUE;
-                       share_irq = FALSE;
+                       share_irq = 0;
                        break;
                }
-       } else {
-               adv_dvc_varp->cfg->dev = dev;
-               /*
-                * For Wide boards set PCI information before calling
-                * AdvInitGetConfig().
-                */
-#ifdef CONFIG_PCI
-               shost->irq = adv_dvc_varp->irq_no = pdev->irq;
-               adv_dvc_varp->cfg->pci_slot_info =
-                   ASC_PCI_MKID(pdev->bus->number,
-                                PCI_SLOT(pdev->devfn),
-                                PCI_FUNC(pdev->devfn));
-               shost->unchecked_isa_dma = FALSE;
-               share_irq = TRUE;
-#endif /* CONFIG_PCI */
-       }
 
-       /*
-        * Read the board configuration.
-        */
-       if (ASC_NARROW_BOARD(boardp)) {
                /*
                 * NOTE: AscInitGetConfig() may change the board's
                 * bus_type value. The bus_type value should no
                 * longer be used. If the bus_type field must be
                 * referenced only use the bit-wise AND operator "&".
                 */
-               ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
-               switch (ret = AscInitGetConfig(asc_dvc_varp)) {
-               case 0: /* No error */
-                       break;
-               case ASC_WARN_IO_PORT_ROTATE:
-                       ASC_PRINT1
-                           ("AscInitGetConfig: board %d: I/O port address modified\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_AUTO_CONFIG:
-                       ASC_PRINT1
-                           ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_EEPROM_CHKSUM:
-                       ASC_PRINT1
-                           ("AscInitGetConfig: board %d: EEPROM checksum error\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_IRQ_MODIFIED:
-                       ASC_PRINT1
-                           ("AscInitGetConfig: board %d: IRQ modified\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_CMD_QNG_CONFLICT:
-                       ASC_PRINT1
-                           ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
-                            boardp->id);
-                       break;
-               default:
-                       ASC_PRINT2
-                           ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
-                            boardp->id, ret);
-                       break;
-               }
-               if ((err_code = asc_dvc_varp->err_code) != 0) {
-                       ASC_PRINT3
-                           ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
-                            boardp->id,
-                            asc_dvc_varp->init_state, asc_dvc_varp->err_code);
-               }
+               ASC_DBG(2, "AscInitGetConfig()\n");
+               ret = AscInitGetConfig(shost) ? -ENODEV : 0;
        } else {
-               ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
-               if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
-                       ASC_PRINT2
-                           ("AdvInitGetConfig: board %d: warning: 0x%x\n",
-                            boardp->id, ret);
-               }
-               if ((err_code = adv_dvc_varp->err_code) != 0) {
-                       ASC_PRINT2
-                           ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
-                            boardp->id, adv_dvc_varp->err_code);
-               }
-       }
+#ifdef CONFIG_PCI
+               /*
+                * For Wide boards set PCI information before calling
+                * AdvInitGetConfig().
+                */
+               shost->unchecked_isa_dma = FALSE;
+               share_irq = IRQF_SHARED;
+               ASC_DBG(2, "AdvInitGetConfig()\n");
 
-       if (err_code != 0) {
-#ifdef CONFIG_PROC_FS
-               kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-               scsi_unregister(shost);
-               asc_board_count--;
-               return NULL;
+               ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0;
+#endif /* CONFIG_PCI */
        }
 
+       if (ret)
+               goto err_free_proc;
+
        /*
         * Save the EEPROM configuration so that it can be displayed
         * from /proc/scsi/advansys/[0...].
@@ -18098,61 +13563,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                /*
                 * Modify board configuration.
                 */
-               ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
-               switch (ret = AscInitSetConfig(asc_dvc_varp)) {
-               case 0: /* No error. */
-                       break;
-               case ASC_WARN_IO_PORT_ROTATE:
-                       ASC_PRINT1
-                           ("AscInitSetConfig: board %d: I/O port address modified\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_AUTO_CONFIG:
-                       ASC_PRINT1
-                           ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_EEPROM_CHKSUM:
-                       ASC_PRINT1
-                           ("AscInitSetConfig: board %d: EEPROM checksum error\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_IRQ_MODIFIED:
-                       ASC_PRINT1
-                           ("AscInitSetConfig: board %d: IRQ modified\n",
-                            boardp->id);
-                       break;
-               case ASC_WARN_CMD_QNG_CONFLICT:
-                       ASC_PRINT1
-                           ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
-                            boardp->id);
-                       break;
-               default:
-                       ASC_PRINT2
-                           ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
-                            boardp->id, ret);
-                       break;
-               }
-               if (asc_dvc_varp->err_code != 0) {
-                       ASC_PRINT3
-                           ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
-                            boardp->id,
-                            asc_dvc_varp->init_state, asc_dvc_varp->err_code);
-#ifdef CONFIG_PROC_FS
-                       kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                       scsi_unregister(shost);
-                       asc_board_count--;
-                       return NULL;
-               }
-
-               /*
-                * Finish initializing the 'Scsi_Host' structure.
-                */
-               /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
-               if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
-                       shost->irq = asc_dvc_varp->irq_no;
-               }
+               ASC_DBG(2, "AscInitSetConfig()\n");
+               ret = AscInitSetConfig(pdev, shost) ? -ENODEV : 0;
+               if (ret)
+                       goto err_free_proc;
        } else {
                ADVEEP_3550_CONFIG *ep_3550;
                ADVEEP_38C0800_CONFIG *ep_38C0800;
@@ -18246,11 +13660,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                 */
                boardp->init_tidmask |=
                    ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
-
-               /*
-                * Finish initializing the 'Scsi_Host' structure.
-                */
-               shost->irq = adv_dvc_varp->irq_no;
        }
 
        /*
@@ -18262,6 +13671,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
        if (ASC_NARROW_BOARD(boardp)) {
                shost->max_id = ASC_MAX_TID + 1;
                shost->max_lun = ASC_MAX_LUN + 1;
+               shost->max_cmd_len = ASC_MAX_CDB_LEN;
 
                shost->io_port = asc_dvc_varp->iop_base;
                boardp->asc_n_io_port = ASC_IOADR_GAP;
@@ -18272,6 +13682,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
        } else {
                shost->max_id = ADV_MAX_TID + 1;
                shost->max_lun = ADV_MAX_LUN + 1;
+               shost->max_cmd_len = ADV_MAX_CDB_LEN;
 
                /*
                 * Save the I/O Port address and length even though
@@ -18280,7 +13691,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                 * PCI Memory Mapped I/O.
                 */
                shost->io_port = iop;
-               boardp->asc_n_io_port = iolen;
 
                shost->this_id = adv_dvc_varp->chip_scsi_id;
 
@@ -18288,15 +13698,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                shost->can_queue = adv_dvc_varp->max_host_qng;
        }
 
-       /*
-        * 'n_io_port' currently is one byte.
-        *
-        * Set a value to 'n_io_port', but never referenced it because
-        * it may be truncated.
-        */
-       shost->n_io_port = boardp->asc_n_io_port <= 255 ?
-           boardp->asc_n_io_port : 255;
-
        /*
         * Following v1.3.89, 'cmd_per_lun' is no longer needed
         * and should be set to zero.
@@ -18343,14 +13744,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                shost->sg_tablesize = SG_ALL;
        }
 
-       ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
+       ASC_DBG(1, "sg_tablesize: %d\n", shost->sg_tablesize);
 
        /* BIOS start address. */
        if (ASC_NARROW_BOARD(boardp)) {
-               shost->base = ((ulong)
-                            AscGetChipBiosAddress(asc_dvc_varp->
-                                                  iop_base,
-                                                  asc_dvc_varp->bus_type));
+               shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
+                                                   asc_dvc_varp->bus_type);
        } else {
                /*
                 * Fill-in BIOS board variables. The Wide BIOS saves
@@ -18365,12 +13764,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                AdvReadWordLram(adv_dvc_varp->iop_base,
                                BIOS_CODELEN, boardp->bios_codelen);
 
-               ASC_DBG2(1,
-                        "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
+               ASC_DBG(1, "bios_signature 0x%x, bios_version 0x%x\n",
                         boardp->bios_signature, boardp->bios_version);
 
-               ASC_DBG2(1,
-                        "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
+               ASC_DBG(1, "bios_codeseg 0x%x, bios_codelen 0x%x\n",
                         boardp->bios_codeseg, boardp->bios_codelen);
 
                /*
@@ -18392,30 +13789,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
         * Register Board Resources - I/O Port, DMA, IRQ
         */
 
-       /*
-        * Register I/O port range.
-        *
-        * For Wide boards the I/O ports are not used to access
-        * the board, but request the region anyway.
-        *
-        * 'shost->n_io_port' is not referenced, because it may be truncated.
-        */
-       ASC_DBG2(2,
-                "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
-                (ulong)shost->io_port, boardp->asc_n_io_port);
-       if (request_region(shost->io_port, boardp->asc_n_io_port,
-                          "advansys") == NULL) {
-               ASC_PRINT3
-                   ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
-                    boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
-               kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-               scsi_unregister(shost);
-               asc_board_count--;
-               return NULL;
-       }
-
        /* Register DMA Channel for Narrow boards. */
        shost->dma_channel = NO_ISA_DMA;        /* Default to no ISA DMA. */
 #ifdef CONFIG_ISA
@@ -18423,19 +13796,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
                /* Register DMA channel for ISA bus. */
                if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
                        shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
-                       if ((ret =
-                            request_dma(shost->dma_channel, "advansys")) != 0) {
-                               ASC_PRINT3
-                                   ("advansys_board_found: board %d: request_dma() %d failed %d\n",
-                                    boardp->id, shost->dma_channel, ret);
-                               release_region(shost->io_port,
-                                              boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
-                               kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                               scsi_unregister(shost);
-                               asc_board_count--;
-                               return NULL;
+                       ret = request_dma(shost->dma_channel, DRV_NAME);
+                       if (ret) {
+                               shost_printk(KERN_ERR, shost, "request_dma() "
+                                               "%d failed %d\n",
+                                               shost->dma_channel, ret);
+                               goto err_free_proc;
                        }
                        AscEnableIsaDma(shost->dma_channel);
                }
@@ -18443,573 +13809,392 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 #endif /* CONFIG_ISA */
 
        /* Register IRQ Number. */
-       ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
-       /*
-        * If request_irq() fails with the IRQF_DISABLED flag set,
-        * then try again without the IRQF_DISABLED flag set. This
-        * allows IRQ sharing to work even with other drivers that
-        * do not set the IRQF_DISABLED flag.
-        *
-        * If IRQF_DISABLED is not set, then interrupts are enabled
-        * before the driver interrupt function is called.
-        */
-       if (((ret = request_irq(shost->irq, advansys_interrupt,
-                               IRQF_DISABLED | (share_irq ==
-                                                TRUE ?
-                                                IRQF_SHARED :
-                                                0), "advansys", boardp)) != 0)
-           &&
-           ((ret =
-             request_irq(shost->irq, advansys_interrupt,
-                         (share_irq == TRUE ? IRQF_SHARED : 0),
-                         "advansys", boardp)) != 0)) {
+       ASC_DBG(2, "request_irq(%d, %p)\n", boardp->irq, shost);
+
+       ret = request_irq(boardp->irq, advansys_interrupt, share_irq,
+                         DRV_NAME, shost);
+
+       if (ret) {
                if (ret == -EBUSY) {
-                       ASC_PRINT2
-                           ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
-                            boardp->id, shost->irq);
+                       shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+                                       "already in use\n", boardp->irq);
                } else if (ret == -EINVAL) {
-                       ASC_PRINT2
-                           ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
-                            boardp->id, shost->irq);
+                       shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+                                       "not valid\n", boardp->irq);
                } else {
-                       ASC_PRINT3
-                           ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
-                            boardp->id, shost->irq, ret);
+                       shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+                                       "failed with %d\n", boardp->irq, ret);
                }
-               release_region(shost->io_port, boardp->asc_n_io_port);
-               iounmap(boardp->ioremap_addr);
-               if (shost->dma_channel != NO_ISA_DMA) {
-                       free_dma(shost->dma_channel);
-               }
-#ifdef CONFIG_PROC_FS
-               kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-               scsi_unregister(shost);
-               asc_board_count--;
-               return NULL;
+               goto err_free_dma;
        }
 
        /*
         * Initialize board RISC chip and enable interrupts.
         */
        if (ASC_NARROW_BOARD(boardp)) {
-               ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
+               ASC_DBG(2, "AscInitAsc1000Driver()\n");
                warn_code = AscInitAsc1000Driver(asc_dvc_varp);
-               err_code = asc_dvc_varp->err_code;
 
-               if (warn_code || err_code) {
-                       ASC_PRINT4
-                           ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
-                            boardp->id,
-                            asc_dvc_varp->init_state, warn_code, err_code);
+               if (warn_code || asc_dvc_varp->err_code) {
+                       shost_printk(KERN_ERR, shost, "error: init_state 0x%x, "
+                                       "warn 0x%x, error 0x%x\n",
+                                       asc_dvc_varp->init_state, warn_code,
+                                       asc_dvc_varp->err_code);
+                       if (asc_dvc_varp->err_code)
+                               ret = -ENODEV;
                }
        } else {
-               ADV_CARR_T *carrp;
-               int req_cnt = 0;
-               adv_req_t *reqp = NULL;
-               int sg_cnt = 0;
-
-               /*
-                * Allocate buffer carrier structures. The total size
-                * is about 4 KB, so allocate all at once.
-                */
-               carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
-               ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp);
-
-               if (carrp == NULL) {
-                       goto kmalloc_error;
-               }
+               if (advansys_wide_init_chip(shost))
+                       ret = -ENODEV;
+       }
 
-               /*
-                * Allocate up to 'max_host_qng' request structures for
-                * the Wide board. The total size is about 16 KB, so
-                * allocate all at once. If the allocation fails decrement
-                * and try again.
-                */
-               for (req_cnt = adv_dvc_varp->max_host_qng;
-                    req_cnt > 0; req_cnt--) {
+       if (ret)
+               goto err_free_wide_mem;
 
-                       reqp = (adv_req_t *)
-                           kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+       ASC_DBG_PRT_SCSI_HOST(2, shost);
 
-                       ASC_DBG3(1,
-                                "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n",
-                                (ulong)reqp, req_cnt,
-                                (ulong)sizeof(adv_req_t) * req_cnt);
+       ret = scsi_add_host(shost, boardp->dev);
+       if (ret)
+               goto err_free_wide_mem;
 
-                       if (reqp != NULL) {
-                               break;
-                       }
-               }
-               if (reqp == NULL) {
-                       goto kmalloc_error;
-               }
+       scsi_scan_host(shost);
+       return 0;
 
-               /*
-                * Allocate up to ADV_TOT_SG_BLOCK request structures for
-                * the Wide board. Each structure is about 136 bytes.
-                */
-               boardp->adv_sgblkp = NULL;
-               for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+ err_free_wide_mem:
+       advansys_wide_free_mem(boardp);
+       free_irq(boardp->irq, shost);
+ err_free_dma:
+       if (shost->dma_channel != NO_ISA_DMA)
+               free_dma(shost->dma_channel);
+ err_free_proc:
+       kfree(boardp->prtbuf);
+ err_unmap:
+       if (boardp->ioremap_addr)
+               iounmap(boardp->ioremap_addr);
+ err_shost:
+       return ret;
+}
 
-                       sgp = (adv_sgblk_t *)
-                           kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
+/*
+ * advansys_release()
+ *
+ * Release resources allocated for a single AdvanSys adapter.
+ */
+static int advansys_release(struct Scsi_Host *shost)
+{
+       struct asc_board *board = shost_priv(shost);
+       ASC_DBG(1, "begin\n");
+       scsi_remove_host(shost);
+       free_irq(board->irq, shost);
+       if (shost->dma_channel != NO_ISA_DMA) {
+               ASC_DBG(1, "free_dma()\n");
+               free_dma(shost->dma_channel);
+       }
+       if (ASC_NARROW_BOARD(board)) {
+               dma_unmap_single(board->dev,
+                                       board->dvc_var.asc_dvc_var.overrun_dma,
+                                       ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+       } else {
+               iounmap(board->ioremap_addr);
+               advansys_wide_free_mem(board);
+       }
+       kfree(board->prtbuf);
+       scsi_host_put(shost);
+       ASC_DBG(1, "end\n");
+       return 0;
+}
 
-                       if (sgp == NULL) {
-                               break;
-                       }
+#define ASC_IOADR_TABLE_MAX_IX  11
 
-                       sgp->next_sgblkp = boardp->adv_sgblkp;
-                       boardp->adv_sgblkp = sgp;
+static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
+       0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
+       0x0210, 0x0230, 0x0250, 0x0330
+};
 
-               }
-               ASC_DBG3(1,
-                        "advansys_board_found: sg_cnt %d * %u = %u bytes\n",
-                        sg_cnt, sizeof(adv_sgblk_t),
-                        (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
+/*
+ * The ISA IRQ number is found in bits 2 and 3 of the CfgLsw.  It decodes as:
+ * 00: 10
+ * 01: 11
+ * 10: 12
+ * 11: 15
+ */
+static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base)
+{
+       unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+       unsigned int chip_irq = ((cfg_lsw >> 2) & 0x03) + 10;
+       if (chip_irq == 13)
+               chip_irq = 15;
+       return chip_irq;
+}
 
-               /*
-                * If no request structures or scatter-gather structures could
-                * be allocated, then return an error. Otherwise continue with
-                * initialization.
-                */
- kmalloc_error:
-               if (carrp == NULL) {
-                       ASC_PRINT1
-                           ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n",
-                            boardp->id);
-                       err_code = ADV_ERROR;
-               } else if (reqp == NULL) {
-                       kfree(carrp);
-                       ASC_PRINT1
-                           ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n",
-                            boardp->id);
-                       err_code = ADV_ERROR;
-               } else if (boardp->adv_sgblkp == NULL) {
-                       kfree(carrp);
-                       kfree(reqp);
-                       ASC_PRINT1
-                           ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
-                            boardp->id);
-                       err_code = ADV_ERROR;
-               } else {
+static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
+{
+       int err = -ENODEV;
+       PortAddr iop_base = _asc_def_iop_base[id];
+       struct Scsi_Host *shost;
+       struct asc_board *board;
 
-                       /* Save carrier buffer pointer. */
-                       boardp->orig_carrp = carrp;
+       if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
+               ASC_DBG(1, "I/O port 0x%x busy\n", iop_base);
+               return -ENODEV;
+       }
+       ASC_DBG(1, "probing I/O port 0x%x\n", iop_base);
+       if (!AscFindSignature(iop_base))
+               goto release_region;
+       if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
+               goto release_region;
 
-                       /*
-                        * Save original pointer for kfree() in case the
-                        * driver is built as a module and can be unloaded.
-                        */
-                       boardp->orig_reqp = reqp;
+       err = -ENOMEM;
+       shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+       if (!shost)
+               goto release_region;
 
-                       adv_dvc_varp->carrier_buf = carrp;
+       board = shost_priv(shost);
+       board->irq = advansys_isa_irq_no(iop_base);
+       board->dev = dev;
 
-                       /*
-                        * Point 'adv_reqp' to the request structures and
-                        * link them together.
-                        */
-                       req_cnt--;
-                       reqp[req_cnt].next_reqp = NULL;
-                       for (; req_cnt > 0; req_cnt--) {
-                               reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
-                       }
-                       boardp->adv_reqp = &reqp[0];
-
-                       if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
-                               ASC_DBG(2,
-                                       "advansys_board_found: AdvInitAsc3550Driver()\n");
-                               warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
-                       } else if (adv_dvc_varp->chip_type ==
-                                  ADV_CHIP_ASC38C0800) {
-                               ASC_DBG(2,
-                                       "advansys_board_found: AdvInitAsc38C0800Driver()\n");
-                               warn_code =
-                                   AdvInitAsc38C0800Driver(adv_dvc_varp);
-                       } else {
-                               ASC_DBG(2,
-                                       "advansys_board_found: AdvInitAsc38C1600Driver()\n");
-                               warn_code =
-                                   AdvInitAsc38C1600Driver(adv_dvc_varp);
-                       }
-                       err_code = adv_dvc_varp->err_code;
+       err = advansys_board_found(shost, iop_base, ASC_IS_ISA);
+       if (err)
+               goto free_host;
 
-                       if (warn_code || err_code) {
-                               ASC_PRINT3
-                                   ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n",
-                                    boardp->id, warn_code, err_code);
-                       }
-               }
-       }
+       dev_set_drvdata(dev, shost);
+       return 0;
 
-       if (err_code != 0) {
-               release_region(shost->io_port, boardp->asc_n_io_port);
-               if (ASC_WIDE_BOARD(boardp)) {
-                       iounmap(boardp->ioremap_addr);
-                       kfree(boardp->orig_carrp);
-                       boardp->orig_carrp = NULL;
-                       if (boardp->orig_reqp) {
-                               kfree(boardp->orig_reqp);
-                               boardp->orig_reqp = boardp->adv_reqp = NULL;
-                       }
-                       while ((sgp = boardp->adv_sgblkp) != NULL) {
-                               boardp->adv_sgblkp = sgp->next_sgblkp;
-                               kfree(sgp);
-                       }
-               }
-               if (shost->dma_channel != NO_ISA_DMA) {
-                       free_dma(shost->dma_channel);
-               }
-#ifdef CONFIG_PROC_FS
-               kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-               free_irq(shost->irq, boardp);
-               scsi_unregister(shost);
-               asc_board_count--;
-               return NULL;
-       }
-       ASC_DBG_PRT_SCSI_HOST(2, shost);
+ free_host:
+       scsi_host_put(shost);
+ release_region:
+       release_region(iop_base, ASC_IOADR_GAP);
+       return err;
+}
 
-       return shost;
+static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
+{
+       int ioport = _asc_def_iop_base[id];
+       advansys_release(dev_get_drvdata(dev));
+       release_region(ioport, ASC_IOADR_GAP);
+       return 0;
 }
 
+static struct isa_driver advansys_isa_driver = {
+       .probe          = advansys_isa_probe,
+       .remove         = __devexit_p(advansys_isa_remove),
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = DRV_NAME,
+       },
+};
+
 /*
- * advansys_detect()
- *
- * Detect function for AdvanSys adapters.
- *
- * Argument is a pointer to the host driver's scsi_hosts entry.
- *
- * Return number of adapters found.
- *
- * Note: Because this function is called during system initialization
- * it must not call SCSI mid-level functions including scsi_malloc()
- * and scsi_free().
+ * The VLB IRQ number is found in bits 2 to 4 of the CfgLsw.  It decodes as:
+ * 000: invalid
+ * 001: 10
+ * 010: 11
+ * 011: 12
+ * 100: invalid
+ * 101: 14
+ * 110: 15
+ * 111: invalid
  */
-static int __init advansys_detect(struct scsi_host_template *tpnt)
+static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base)
 {
-       static int detect_called = ASC_FALSE;
-       int iop;
-       int bus;
-       int ioport = 0;
-       struct device *dev = NULL;
-#ifdef CONFIG_PCI
-       int pci_init_search = 0;
-       struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
-       int pci_card_cnt_max = 0;
-       int pci_card_cnt = 0;
-       struct pci_dev *pdev = NULL;
-       int pci_device_id_cnt = 0;
-       unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
-               PCI_DEVICE_ID_ASP_1200A,
-               PCI_DEVICE_ID_ASP_ABP940,
-               PCI_DEVICE_ID_ASP_ABP940U,
-               PCI_DEVICE_ID_ASP_ABP940UW,
-               PCI_DEVICE_ID_38C0800_REV1,
-               PCI_DEVICE_ID_38C1600_REV1
-       };
-#endif /* CONFIG_PCI */
-
-       if (detect_called == ASC_FALSE) {
-               detect_called = ASC_TRUE;
-       } else {
-               printk
-                   ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
+       unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+       unsigned int chip_irq = ((cfg_lsw >> 2) & 0x07) + 9;
+       if ((chip_irq < 10) || (chip_irq == 13) || (chip_irq > 15))
                return 0;
-       }
-
-       ASC_DBG(1, "advansys_detect: begin\n");
+       return chip_irq;
+}
 
-       asc_board_count = 0;
+static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
+{
+       int err = -ENODEV;
+       PortAddr iop_base = _asc_def_iop_base[id];
+       struct Scsi_Host *shost;
+       struct asc_board *board;
 
+       if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
+               ASC_DBG(1, "I/O port 0x%x busy\n", iop_base);
+               return -ENODEV;
+       }
+       ASC_DBG(1, "probing I/O port 0x%x\n", iop_base);
+       if (!AscFindSignature(iop_base))
+               goto release_region;
        /*
-        * If I/O port probing has been modified, then verify and
-        * clean-up the 'asc_ioport' list.
+        * I don't think this condition can actually happen, but the old
+        * driver did it, and the chances of finding a VLB setup in 2007
+        * to do testing with is slight to none.
         */
-       if (asc_iopflag == ASC_TRUE) {
-               for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
-                       ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
-                                ioport, asc_ioport[ioport]);
-                       if (asc_ioport[ioport] != 0) {
-                               for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
-                                    iop++) {
-                                       if (_asc_def_iop_base[iop] ==
-                                           asc_ioport[ioport]) {
-                                               break;
-                                       }
-                               }
-                               if (iop == ASC_IOADR_TABLE_MAX_IX) {
-                                       printk
-                                           ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
-                                            asc_ioport[ioport]);
-                                       asc_ioport[ioport] = 0;
-                               }
-                       }
-               }
-               ioport = 0;
-       }
+       if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
+               goto release_region;
 
-       for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+       err = -ENOMEM;
+       shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+       if (!shost)
+               goto release_region;
 
-               ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
-                        bus, asc_bus_name[bus]);
-               iop = 0;
+       board = shost_priv(shost);
+       board->irq = advansys_vlb_irq_no(iop_base);
+       board->dev = dev;
 
-               while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+       err = advansys_board_found(shost, iop_base, ASC_IS_VL);
+       if (err)
+               goto free_host;
 
-                       ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
-                                asc_board_count);
+       dev_set_drvdata(dev, shost);
+       return 0;
 
-                       switch (asc_bus[bus]) {
-                       case ASC_IS_ISA:
-                       case ASC_IS_VL:
-#ifdef CONFIG_ISA
-                               if (asc_iopflag == ASC_FALSE) {
-                                       iop =
-                                           AscSearchIOPortAddr(iop,
-                                                               asc_bus[bus]);
-                               } else {
-                                       /*
-                                        * ISA and VL I/O port scanning has either been
-                                        * eliminated or limited to selected ports on
-                                        * the LILO command line, /etc/lilo.conf, or
-                                        * by setting variables when the module was loaded.
-                                        */
-                                       ASC_DBG(1,
-                                               "advansys_detect: I/O port scanning modified\n");
- ioport_try_again:
-                                       iop = 0;
-                                       for (; ioport < ASC_NUM_IOPORT_PROBE;
-                                            ioport++) {
-                                               if ((iop =
-                                                    asc_ioport[ioport]) != 0) {
-                                                       break;
-                                               }
-                                       }
-                                       if (iop) {
-                                               ASC_DBG1(1,
-                                                        "advansys_detect: probing I/O port 0x%x...\n",
-                                                        iop);
-                                               if (!request_region
-                                                   (iop, ASC_IOADR_GAP,
-                                                    "advansys")) {
-                                                       printk
-                                                           ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
-                                                            iop);
-                                                       /* Don't try this I/O port twice. */
-                                                       asc_ioport[ioport] = 0;
-                                                       goto ioport_try_again;
-                                               } else if (AscFindSignature(iop)
-                                                          == ASC_FALSE) {
-                                                       printk
-                                                           ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
-                                                            iop);
-                                                       /* Don't try this I/O port twice. */
-                                                       release_region(iop,
-                                                                      ASC_IOADR_GAP);
-                                                       asc_ioport[ioport] = 0;
-                                                       goto ioport_try_again;
-                                               } else {
-                                                       /*
-                                                        * If this isn't an ISA board, then it must be
-                                                        * a VL board. If currently looking an ISA
-                                                        * board is being looked for then try for
-                                                        * another ISA board in 'asc_ioport'.
-                                                        */
-                                                       if (asc_bus[bus] ==
-                                                           ASC_IS_ISA
-                                                           &&
-                                                           (AscGetChipVersion
-                                                            (iop,
-                                                             ASC_IS_ISA) &
-                                                            ASC_CHIP_VER_ISA_BIT)
-                                                           == 0) {
-                                                               /*
-                                                                * Don't clear 'asc_ioport[ioport]'. Try
-                                                                * this board again for VL. Increment
-                                                                * 'ioport' past this board.
-                                                                */
-                                                               ioport++;
-                                                               release_region
-                                                                   (iop,
-                                                                    ASC_IOADR_GAP);
-                                                               goto ioport_try_again;
-                                                       }
-                                               }
-                                               /*
-                                                * This board appears good, don't try the I/O port
-                                                * again by clearing its value. Increment 'ioport'
-                                                * for the next iteration.
-                                                */
-                                               asc_ioport[ioport++] = 0;
-                                       }
-                               }
-#endif /* CONFIG_ISA */
-                               break;
+ free_host:
+       scsi_host_put(shost);
+ release_region:
+       release_region(iop_base, ASC_IOADR_GAP);
+       return -ENODEV;
+}
 
-                       case ASC_IS_EISA:
-#ifdef CONFIG_ISA
-                               iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-#endif /* CONFIG_ISA */
-                               break;
+static struct isa_driver advansys_vlb_driver = {
+       .probe          = advansys_vlb_probe,
+       .remove         = __devexit_p(advansys_isa_remove),
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "advansys_vlb",
+       },
+};
 
-                       case ASC_IS_PCI:
-#ifdef CONFIG_PCI
-                               if (pci_init_search == 0) {
-                                       int i, j;
-
-                                       pci_init_search = 1;
-
-                                       /* Find all PCI cards. */
-                                       while (pci_device_id_cnt <
-                                              ASC_PCI_DEVICE_ID_CNT) {
-                                               if ((pdev =
-                                                    pci_find_device
-                                                    (PCI_VENDOR_ID_ASP,
-                                                     pci_device_id
-                                                     [pci_device_id_cnt],
-                                                     pdev)) == NULL) {
-                                                       pci_device_id_cnt++;
-                                               } else {
-                                                       if (pci_enable_device
-                                                           (pdev) == 0) {
-                                                               pci_devicep
-                                                                   [pci_card_cnt_max++]
-                                                                   = pdev;
-                                                       }
-                                               }
-                                       }
+static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
+       { "ABP7401" },
+       { "ABP7501" },
+       { "" }
+};
 
-                                       /*
-                                        * Sort PCI cards in ascending order by PCI Bus, Slot,
-                                        * and Device Number.
-                                        */
-                                       for (i = 0; i < pci_card_cnt_max - 1;
-                                            i++) {
-                                               for (j = i + 1;
-                                                    j < pci_card_cnt_max;
-                                                    j++) {
-                                                       if ((pci_devicep[j]->
-                                                            bus->number <
-                                                            pci_devicep[i]->
-                                                            bus->number)
-                                                           ||
-                                                           ((pci_devicep[j]->
-                                                             bus->number ==
-                                                             pci_devicep[i]->
-                                                             bus->number)
-                                                            &&
-                                                            (pci_devicep[j]->
-                                                             devfn <
-                                                             pci_devicep[i]->
-                                                             devfn))) {
-                                                               pdev =
-                                                                   pci_devicep
-                                                                   [i];
-                                                               pci_devicep[i] =
-                                                                   pci_devicep
-                                                                   [j];
-                                                               pci_devicep[j] =
-                                                                   pdev;
-                                                       }
-                                               }
-                                       }
+MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
 
-                                       pci_card_cnt = 0;
-                               } else {
-                                       pci_card_cnt++;
-                               }
+/*
+ * EISA is a little more tricky than PCI; each EISA device may have two
+ * channels, and this driver is written to make each channel its own Scsi_Host
+ */
+struct eisa_scsi_data {
+       struct Scsi_Host *host[2];
+};
 
-                               if (pci_card_cnt == pci_card_cnt_max) {
-                                       iop = 0;
-                               } else {
-                                       pdev = pci_devicep[pci_card_cnt];
-
-                                       ASC_DBG2(2,
-                                                "advansys_detect: devfn %d, bus number %d\n",
-                                                pdev->devfn,
-                                                pdev->bus->number);
-                                       iop = pci_resource_start(pdev, 0);
-                                       ASC_DBG2(1,
-                                                "advansys_detect: vendorID %X, deviceID %X\n",
-                                                pdev->vendor,
-                                                pdev->device);
-                                       ASC_DBG2(2,
-                                                "advansys_detect: iop %X, irqLine %d\n",
-                                                iop, pdev->irq);
-                               }
-                               if (pdev)
-                                       dev = &pdev->dev;
+/*
+ * The EISA IRQ number is found in bits 8 to 10 of the CfgLsw.  It decodes as:
+ * 000: 10
+ * 001: 11
+ * 010: 12
+ * 011: invalid
+ * 100: 14
+ * 101: 15
+ * 110: invalid
+ * 111: invalid
+ */
+static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev)
+{
+       unsigned short cfg_lsw = inw(edev->base_addr + 0xc86);
+       unsigned int chip_irq = ((cfg_lsw >> 8) & 0x07) + 10;
+       if ((chip_irq == 13) || (chip_irq > 15))
+               return 0;
+       return chip_irq;
+}
 
-#endif /* CONFIG_PCI */
-                               break;
+static int __devinit advansys_eisa_probe(struct device *dev)
+{
+       int i, ioport, irq = 0;
+       int err;
+       struct eisa_device *edev = to_eisa_device(dev);
+       struct eisa_scsi_data *data;
 
-                       default:
-                               ASC_PRINT1
-                                   ("advansys_detect: unknown bus type: %d\n",
-                                    asc_bus[bus]);
-                               break;
-                       }
-                       ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
+       err = -ENOMEM;
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               goto fail;
+       ioport = edev->base_addr + 0xc30;
 
-                       /*
-                        * Adapter not found, try next bus type.
-                        */
-                       if (iop == 0) {
-                               break;
-                       }
+       err = -ENODEV;
+       for (i = 0; i < 2; i++, ioport += 0x20) {
+               struct asc_board *board;
+               struct Scsi_Host *shost;
+               if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) {
+                       printk(KERN_WARNING "Region %x-%x busy\n", ioport,
+                              ioport + ASC_IOADR_GAP - 1);
+                       continue;
+               }
+               if (!AscFindSignature(ioport)) {
+                       release_region(ioport, ASC_IOADR_GAP);
+                       continue;
+               }
+
+               /*
+                * I don't know why we need to do this for EISA chips, but
+                * not for any others.  It looks to be equivalent to
+                * AscGetChipCfgMsw, but I may have overlooked something,
+                * so I'm not converting it until I get an EISA board to
+                * test with.
+                */
+               inw(ioport + 4);
 
-                       advansys_board_found(iop, dev, asc_bus[bus]);
+               if (!irq)
+                       irq = advansys_eisa_irq_no(edev);
+
+               err = -ENOMEM;
+               shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+               if (!shost)
+                       goto release_region;
+
+               board = shost_priv(shost);
+               board->irq = irq;
+               board->dev = dev;
+
+               err = advansys_board_found(shost, ioport, ASC_IS_EISA);
+               if (!err) {
+                       data->host[i] = shost;
+                       continue;
                }
+
+               scsi_host_put(shost);
+ release_region:
+               release_region(ioport, ASC_IOADR_GAP);
+               break;
        }
 
-       ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
-                asc_board_count);
-       return asc_board_count;
+       if (err)
+               goto free_data;
+       dev_set_drvdata(dev, data);
+       return 0;
+
+ free_data:
+       kfree(data->host[0]);
+       kfree(data->host[1]);
+       kfree(data);
+ fail:
+       return err;
 }
 
-/*
- * advansys_release()
- *
- * Release resources allocated for a single AdvanSys adapter.
- */
-static int advansys_release(struct Scsi_Host *shost)
+static __devexit int advansys_eisa_remove(struct device *dev)
 {
-       asc_board_t *boardp;
+       int i;
+       struct eisa_scsi_data *data = dev_get_drvdata(dev);
 
-       ASC_DBG(1, "advansys_release: begin\n");
-       boardp = ASC_BOARDP(shost);
-       free_irq(shost->irq, boardp);
-       if (shost->dma_channel != NO_ISA_DMA) {
-               ASC_DBG(1, "advansys_release: free_dma()\n");
-               free_dma(shost->dma_channel);
+       for (i = 0; i < 2; i++) {
+               int ioport;
+               struct Scsi_Host *shost = data->host[i];
+               if (!shost)
+                       continue;
+               ioport = shost->io_port;
+               advansys_release(shost);
+               release_region(ioport, ASC_IOADR_GAP);
        }
-       release_region(shost->io_port, boardp->asc_n_io_port);
-       if (ASC_WIDE_BOARD(boardp)) {
-               adv_sgblk_t *sgp = NULL;
 
-               iounmap(boardp->ioremap_addr);
-               kfree(boardp->orig_carrp);
-               boardp->orig_carrp = NULL;
-               if (boardp->orig_reqp) {
-                       kfree(boardp->orig_reqp);
-                       boardp->orig_reqp = boardp->adv_reqp = NULL;
-               }
-               while ((sgp = boardp->adv_sgblkp) != NULL) {
-                       boardp->adv_sgblkp = sgp->next_sgblkp;
-                       kfree(sgp);
-               }
-       }
-#ifdef CONFIG_PROC_FS
-       ASC_ASSERT(boardp->prtbuf != NULL);
-       kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-       scsi_unregister(shost);
-       ASC_DBG(1, "advansys_release: end\n");
+       kfree(data);
        return 0;
 }
 
-#ifdef CONFIG_PCI
+static struct eisa_driver advansys_eisa_driver = {
+       .id_table =             advansys_eisa_table,
+       .driver = {
+               .name =         DRV_NAME,
+               .probe =        advansys_eisa_probe,
+               .remove =       __devexit_p(advansys_eisa_remove),
+       }
+};
+
 /* PCI Devices supported by this driver */
 static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
        {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
@@ -19028,4 +14213,131 @@ static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
 };
 
 MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
-#endif /* CONFIG_PCI */
+
+static void __devinit advansys_set_latency(struct pci_dev *pdev)
+{
+       if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
+           (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
+               pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
+       } else {
+               u8 latency;
+               pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+               if (latency < 0x20)
+                       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
+       }
+}
+
+static int __devinit
+advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       int err, ioport;
+       struct Scsi_Host *shost;
+       struct asc_board *board;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               goto fail;
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err)
+               goto disable_device;
+       pci_set_master(pdev);
+       advansys_set_latency(pdev);
+
+       err = -ENODEV;
+       if (pci_resource_len(pdev, 0) == 0)
+               goto release_region;
+
+       ioport = pci_resource_start(pdev, 0);
+
+       err = -ENOMEM;
+       shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+       if (!shost)
+               goto release_region;
+
+       board = shost_priv(shost);
+       board->irq = pdev->irq;
+       board->dev = &pdev->dev;
+
+       if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+           pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
+           pdev->device == PCI_DEVICE_ID_38C1600_REV1) {
+               board->flags |= ASC_IS_WIDE_BOARD;
+       }
+
+       err = advansys_board_found(shost, ioport, ASC_IS_PCI);
+       if (err)
+               goto free_host;
+
+       pci_set_drvdata(pdev, shost);
+       return 0;
+
+ free_host:
+       scsi_host_put(shost);
+ release_region:
+       pci_release_regions(pdev);
+ disable_device:
+       pci_disable_device(pdev);
+ fail:
+       return err;
+}
+
+static void __devexit advansys_pci_remove(struct pci_dev *pdev)
+{
+       advansys_release(pci_get_drvdata(pdev));
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_driver advansys_pci_driver = {
+       .name =         DRV_NAME,
+       .id_table =     advansys_pci_tbl,
+       .probe =        advansys_pci_probe,
+       .remove =       __devexit_p(advansys_pci_remove),
+};
+
+static int __init advansys_init(void)
+{
+       int error;
+
+       error = isa_register_driver(&advansys_isa_driver,
+                                   ASC_IOADR_TABLE_MAX_IX);
+       if (error)
+               goto fail;
+
+       error = isa_register_driver(&advansys_vlb_driver,
+                                   ASC_IOADR_TABLE_MAX_IX);
+       if (error)
+               goto unregister_isa;
+
+       error = eisa_driver_register(&advansys_eisa_driver);
+       if (error)
+               goto unregister_vlb;
+
+       error = pci_register_driver(&advansys_pci_driver);
+       if (error)
+               goto unregister_eisa;
+
+       return 0;
+
+ unregister_eisa:
+       eisa_driver_unregister(&advansys_eisa_driver);
+ unregister_vlb:
+       isa_unregister_driver(&advansys_vlb_driver);
+ unregister_isa:
+       isa_unregister_driver(&advansys_isa_driver);
+ fail:
+       return error;
+}
+
+static void __exit advansys_exit(void)
+{
+       pci_unregister_driver(&advansys_pci_driver);
+       eisa_driver_unregister(&advansys_eisa_driver);
+       isa_unregister_driver(&advansys_vlb_driver);
+       isa_unregister_driver(&advansys_isa_driver);
+}
+
+module_init(advansys_init);
+module_exit(advansys_exit);
+
+MODULE_LICENSE("GPL");
index d30a30786ddaaa976e3517472918f410707796ba..f08e71e0205a5f5a3e538701d44e80bd9a4822ca 100644 (file)
@@ -907,9 +907,10 @@ out_host_put:
 
 void aha152x_release(struct Scsi_Host *shpnt)
 {
-       if(!shpnt)
+       if (!shpnt)
                return;
 
+       scsi_remove_host(shpnt);
        if (shpnt->irq)
                free_irq(shpnt->irq, shpnt);
 
@@ -923,7 +924,6 @@ void aha152x_release(struct Scsi_Host *shpnt)
                pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
 #endif
 
-       scsi_remove_host(shpnt);
        list_del(&HOSTDATA(shpnt)->host_list);
        scsi_host_put(shpnt);
 }
index 4998bb850c49be1c8669067b93b4db829b4603ee..1a71b0236c974ef8ed3006f9a82756c163d0d3c6 100644 (file)
@@ -8416,10 +8416,9 @@ aic7xxx_alloc(struct scsi_host_template *sht, struct aic7xxx_host *temp)
     *p = *temp;
     p->host = host;
 
-    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
-    if (p->scb_data != NULL)
+    p->scb_data = kzalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (!p->scb_data)
     {
-      memset(p->scb_data, 0, sizeof(scb_data_type));
       scbq_init (&p->scb_data->free_scbs);
     }
     else
@@ -9196,10 +9195,9 @@ aic7xxx_detect(struct scsi_host_template *template)
             printk(KERN_INFO "         this driver, we are ignoring it.\n");
           }
         }
-        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+        else if ( (temp_p = kzalloc(sizeof(struct aic7xxx_host),
                                     GFP_ATOMIC)) != NULL )
         {
-          memset(temp_p, 0, sizeof(struct aic7xxx_host));
           temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
           temp_p->flags = aic_pdevs[i].flags;
           temp_p->features = aic_pdevs[i].features;
index c6c3d18222fabea78ad3f6cfb3627ea97897bf20..491e5d8a98bcffe819a11998f5110ef265f4ca0a 100644 (file)
 #define ASD_MAX_PHYS       8
 #define ASD_PCBA_SN_SIZE   12
 
-/* Those are to be further named properly, the "RAZORx" part, and
- * subsequently included in include/linux/pci_ids.h.
- */
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1F 0x41F
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
-
 struct asd_ha_addrspace {
        void __iomem  *addr;
        unsigned long  start;       /* pci resource start */
index 63bcde24644740baeadb8b956c6c0ab68f88b16e..b70d6e7f96e951e55829cc118337946e80dc7101 100644 (file)
@@ -583,7 +583,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
        asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
        if (!asd_ha) {
                asd_printk("out of memory\n");
-               goto Err;
+               goto Err_put;
        }
        asd_ha->pcidev = dev;
        asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
@@ -600,14 +600,12 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
        shost->max_cmd_len = 16;
 
        err = scsi_add_host(shost, &dev->dev);
-       if (err) {
-               scsi_host_put(shost);
+       if (err)
                goto Err_free;
-       }
 
        err = asd_dev->setup(asd_ha);
        if (err)
-               goto Err_free;
+               goto Err_remove;
 
        err = -ENODEV;
        if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
@@ -618,14 +616,14 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
                ;
        else {
                asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
-               goto Err_free;
+               goto Err_remove;
        }
 
        pci_set_drvdata(dev, asd_ha);
 
        err = asd_map_ha(asd_ha);
        if (err)
-               goto Err_free;
+               goto Err_remove;
 
        err = asd_create_ha_caches(asd_ha);
         if (err)
@@ -692,9 +690,12 @@ Err_free_cache:
        asd_destroy_ha_caches(asd_ha);
 Err_unmap:
        asd_unmap_ha(asd_ha);
+Err_remove:
+       scsi_remove_host(shost);
 Err_free:
        kfree(asd_ha);
-       scsi_remove_host(shost);
+Err_put:
+       scsi_host_put(shost);
 Err:
        pci_disable_device(dev);
        return err;
@@ -829,22 +830,15 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
 };
 
 static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
-        0, 0, 2},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
-        0, 0, 2},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
-        0, 0, 2},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
-        0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2},
        {}
 };
 
index ab13824df856594ec140ce9c23bb9888b71b4523..f2b23e01401ad95b825b73c8c0648edc2c09b874 100644 (file)
@@ -207,7 +207,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
                                            "stat(0x%x) is not CHECK_CONDITION"
                                            "\n",
                                            SAS_ADDR(task->dev->sas_addr),
-                                           ts->stat);
+                                           iu->status);
                        }
                }
        }  else {
index f0b8bf4534f0186c800667f3f511b29472452286..ace7a15b413e42ba499847b2e5912f0f2cc7b56f 100644 (file)
@@ -9,7 +9,7 @@
 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
 **
 **     Web site: www.areca.com.tw
-**       E-mail: erich@areca.com.tw
+**       E-mail: support@areca.com.tw
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License version 2 as
 #include <linux/interrupt.h>
 
 struct class_device_attribute;
-
-#define ARCMSR_MAX_OUTSTANDING_CMD                                             256
-#define ARCMSR_MAX_FREECCB_NUM                                                 288
-#define ARCMSR_DRIVER_VERSION                          "Driver Version 1.20.00.14"
+/*The limit of outstanding scsi command that firmware can handle*/
+#define ARCMSR_MAX_OUTSTANDING_CMD                                             256
+#define ARCMSR_MAX_FREECCB_NUM                                                 320
+#define ARCMSR_DRIVER_VERSION               "Driver Version 1.20.00.15 2007/08/30"
 #define ARCMSR_SCSI_INITIATOR_ID                                               255
 #define ARCMSR_MAX_XFER_SECTORS                                                        512
-#define ARCMSR_MAX_XFER_SECTORS_B                                              4096
-#define ARCMSR_MAX_TARGETID                                                     17
-#define ARCMSR_MAX_TARGETLUN                                                     8
-#define ARCMSR_MAX_CMD_PERLUN                           ARCMSR_MAX_OUTSTANDING_CMD
-#define ARCMSR_MAX_QBUFFER                                                    4096
-#define ARCMSR_MAX_SG_ENTRIES                                                   38
-
+#define ARCMSR_MAX_XFER_SECTORS_B                                              4096
+#define ARCMSR_MAX_TARGETID                                                    17
+#define ARCMSR_MAX_TARGETLUN                                                   8
+#define ARCMSR_MAX_CMD_PERLUN                           ARCMSR_MAX_OUTSTANDING_CMD
+#define ARCMSR_MAX_QBUFFER                                                     4096
+#define ARCMSR_MAX_SG_ENTRIES                                                  38
+#define ARCMSR_MAX_HBB_POSTQUEUE                                               264
+/*
+**********************************************************************************
+**
+**********************************************************************************
+*/
+#define ARC_SUCCESS                                                       0
+#define ARC_FAILURE                                                       1
 /*
 *******************************************************************************
 **        split 64bits dma addressing
@@ -90,7 +97,7 @@ struct CMD_MESSAGE_FIELD
     uint8_t                            messagedatabuffer[1032];
 };
 /* IOP message transfer */
-#define ARCMSR_MESSAGE_FAIL             0x0001
+#define ARCMSR_MESSAGE_FAIL                    0x0001
 /* DeviceType */
 #define ARECA_SATA_RAID                                0x90000000
 /* FunctionCode */
@@ -163,27 +170,27 @@ struct QBUFFER
 };
 /*
 *******************************************************************************
-**      FIRMWARE INFO
+**      FIRMWARE INFO for Intel IOP R 80331 processor (Type A)
 *******************************************************************************
 */
 struct FIRMWARE_INFO
 {
-       uint32_t      signature;                /*0, 00-03*/
-       uint32_t      request_len;              /*1, 04-07*/
-       uint32_t      numbers_queue;            /*2, 08-11*/
+       uint32_t      signature;                /*0, 00-03*/
+       uint32_t      request_len;              /*1, 04-07*/
+       uint32_t      numbers_queue;            /*2, 08-11*/
        uint32_t      sdram_size;               /*3, 12-15*/
-       uint32_t      ide_channels;             /*4, 16-19*/
-       char          vendor[40];               /*5, 20-59*/
-       char          model[8];                 /*15, 60-67*/
-       char          firmware_ver[16];         /*17, 68-83*/
-       char          device_map[16];           /*21, 84-99*/
+       uint32_t      ide_channels;             /*4, 16-19*/
+       char          vendor[40];               /*5, 20-59*/
+       char          model[8];                 /*15, 60-67*/
+       char          firmware_ver[16];         /*17, 68-83*/
+       char          device_map[16];           /*21, 84-99*/
 };
 /* signature of set and get firmware config */
-#define ARCMSR_SIGNATURE_GET_CONFIG                   0x87974060
-#define ARCMSR_SIGNATURE_SET_CONFIG                   0x87974063
+#define ARCMSR_SIGNATURE_GET_CONFIG                  0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG                  0x87974063
 /* message code of inbound message register */
-#define ARCMSR_INBOUND_MESG0_NOP                      0x00000000
-#define ARCMSR_INBOUND_MESG0_GET_CONFIG               0x00000001
+#define ARCMSR_INBOUND_MESG0_NOP                     0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG                      0x00000001
 #define ARCMSR_INBOUND_MESG0_SET_CONFIG               0x00000002
 #define ARCMSR_INBOUND_MESG0_ABORT_CMD                0x00000003
 #define ARCMSR_INBOUND_MESG0_STOP_BGRB                0x00000004
@@ -203,6 +210,60 @@ struct FIRMWARE_INFO
 #define ARCMSR_CCBREPLY_FLAG_ERROR                    0x10000000
 /* outbound firmware ok */
 #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK             0x80000000
+
+/*
+************************************************************************
+**                SPEC. for Areca Type B adapter
+************************************************************************
+*/
+/* ARECA HBB COMMAND for its FIRMWARE */
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL                       0x00020400
+#define ARCMSR_DRV2IOP_DOORBELL_MASK                  0x00020404
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL                       0x00020408
+#define ARCMSR_IOP2DRV_DOORBELL_MASK                  0x0002040C
+/* ARECA FLAG LANGUAGE */
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_WRITE_OK                  0x00000001
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_READ_OK                   0x00000002
+#define ARCMSR_IOP2DRV_CDB_DONE                       0x00000004
+#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE               0x00000008
+
+#define ARCMSR_DOORBELL_HANDLE_INT                   0x0000000F
+#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN            0xFF00FFF0
+#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN             0xFF00FFF7
+/* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_GET_CONFIG                    0x00010008
+/* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_SET_CONFIG                    0x00020008
+/* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_ABORT_CMD                     0x00030008
+/* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_STOP_BGRB                     0x00040008
+/* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_FLUSH_CACHE                    0x00050008
+/* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_START_BGRB                    0x00060008
+#define ARCMSR_MESSAGE_START_DRIVER_MODE             0x000E0008
+#define ARCMSR_MESSAGE_SET_POST_WINDOW               0x000F0008
+/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */
+#define ARCMSR_MESSAGE_FIRMWARE_OK                   0x80000000
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_WRITE_OK                  0x00000001
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_READ_OK                   0x00000002
+#define ARCMSR_DRV2IOP_CDB_POSTED                     0x00000004
+#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED             0x00000008
+
+/* data tunnel buffer between user space program and its firmware */
+/* user space data to iop 128bytes */
+#define ARCMSR_IOCTL_WBUFFER                         0x0000fe00
+/* iop data to user space 128bytes */
+#define ARCMSR_IOCTL_RBUFFER                         0x0000ff00
+/* iop message_rwbuffer for message command */
+#define ARCMSR_MSGCODE_RWBUFFER                              0x0000fa00
 /*
 *******************************************************************************
 **    ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
@@ -214,7 +275,6 @@ struct ARCMSR_CDB
        uint8_t                                                 TargetID;
        uint8_t                                                 LUN;
        uint8_t                                                 Function;
-
        uint8_t                                                 CdbLength;
        uint8_t                                                 sgcount;
        uint8_t                                                 Flags;
@@ -224,20 +284,18 @@ struct ARCMSR_CDB
 #define ARCMSR_CDB_FLAG_SIMPLEQ            0x00
 #define ARCMSR_CDB_FLAG_HEADQ              0x08
 #define ARCMSR_CDB_FLAG_ORDEREDQ           0x10
-       uint8_t                                                 Reserved1;
 
+       uint8_t                                                 Reserved1;
        uint32_t                                                Context;
        uint32_t                                                DataLength;
-
        uint8_t                                                 Cdb[16];
-
        uint8_t                                                 DeviceStatus;
-#define ARCMSR_DEV_CHECK_CONDITION          0x02
-#define ARCMSR_DEV_SELECT_TIMEOUT                      0xF0
-#define ARCMSR_DEV_ABORTED                             0xF1
-#define ARCMSR_DEV_INIT_FAIL                           0xF2
-       uint8_t                                                 SenseData[15];
+#define ARCMSR_DEV_CHECK_CONDITION         0x02
+#define ARCMSR_DEV_SELECT_TIMEOUT          0xF0
+#define ARCMSR_DEV_ABORTED                 0xF1
+#define ARCMSR_DEV_INIT_FAIL               0xF2
 
+       uint8_t                                                 SenseData[15];
        union
        {
                struct SG32ENTRY                sg32entry[ARCMSR_MAX_SG_ENTRIES];
@@ -246,10 +304,10 @@ struct ARCMSR_CDB
 };
 /*
 *******************************************************************************
-**     Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+**     Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor
 *******************************************************************************
 */
-struct MessageUnit
+struct MessageUnit_A
 {
        uint32_t        resrved0[4];                    /*0000 000F*/
        uint32_t        inbound_msgaddr0;               /*0010 0013*/
@@ -274,6 +332,30 @@ struct MessageUnit
        uint32_t        message_rbuffer[32];            /*0F00 0F7F  32*/
        uint32_t        reserved6[32];                  /*0F80 0FFF  32*/
 };
+
+struct MessageUnit_B
+{
+       uint32_t        post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+       uint32_t        done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+       uint32_t        postq_index;
+       uint32_t        doneq_index;
+       uint32_t        *drv2iop_doorbell_reg;
+       uint32_t        *drv2iop_doorbell_mask_reg;
+       uint32_t        *iop2drv_doorbell_reg;
+       uint32_t        *iop2drv_doorbell_mask_reg;
+       uint32_t        *msgcode_rwbuffer_reg;
+       uint32_t        *ioctl_wbuffer_reg;
+       uint32_t        *ioctl_rbuffer_reg;
+};
+
+struct MessageUnit
+{
+       union
+       {
+               struct MessageUnit_A    pmu_A;
+               struct MessageUnit_B    pmu_B;
+       } u;
+};
 /*
 *******************************************************************************
 **                 Adapter Control Block
@@ -281,37 +363,45 @@ struct MessageUnit
 */
 struct AdapterControlBlock
 {
+       uint32_t  adapter_type;                /* adapter A,B..... */
+       #define ACB_ADAPTER_TYPE_A            0x00000001        /* hba I IOP */
+       #define ACB_ADAPTER_TYPE_B            0x00000002        /* hbb M IOP */
+       #define ACB_ADAPTER_TYPE_C            0x00000004        /* hbc P IOP */
+       #define ACB_ADAPTER_TYPE_D            0x00000008        /* hbd A IOP */
        struct pci_dev *                pdev;
        struct Scsi_Host *              host;
        unsigned long                   vir2phy_offset;
        /* Offset is used in making arc cdb physical to virtual calculations */
        uint32_t                        outbound_int_enable;
 
-       struct MessageUnit __iomem *            pmu;
+       struct MessageUnit *                    pmu;
        /* message unit ATU inbound base address0 */
 
        uint32_t                        acb_flags;
-#define ACB_F_SCSISTOPADAPTER         0x0001
-#define ACB_F_MSG_STOP_BGRB           0x0002
+       #define ACB_F_SCSISTOPADAPTER           0x0001
+       #define ACB_F_MSG_STOP_BGRB             0x0002
        /* stop RAID background rebuild */
-#define ACB_F_MSG_START_BGRB          0x0004
+       #define ACB_F_MSG_START_BGRB            0x0004
        /* stop RAID background rebuild */
-#define ACB_F_IOPDATA_OVERFLOW        0x0008
+       #define ACB_F_IOPDATA_OVERFLOW          0x0008
        /* iop message data rqbuffer overflow */
-#define ACB_F_MESSAGE_WQBUFFER_CLEARED  0x0010
+       #define ACB_F_MESSAGE_WQBUFFER_CLEARED  0x0010
        /* message clear wqbuffer */
-#define ACB_F_MESSAGE_RQBUFFER_CLEARED  0x0020
+       #define ACB_F_MESSAGE_RQBUFFER_CLEARED  0x0020
        /* message clear rqbuffer */
-#define ACB_F_MESSAGE_WQBUFFER_READED   0x0040
-#define ACB_F_BUS_RESET               0x0080
-#define ACB_F_IOP_INITED              0x0100
+       #define ACB_F_MESSAGE_WQBUFFER_READED   0x0040
+       #define ACB_F_BUS_RESET                 0x0080
+       #define ACB_F_IOP_INITED                0x0100
        /* iop init */
 
        struct CommandControlBlock *                    pccb_pool[ARCMSR_MAX_FREECCB_NUM];
        /* used for memory free */
        struct list_head                ccb_free_list;
        /* head of free ccb list */
+
        atomic_t                        ccboutstandingcount;
+       /*The present outstanding command number that in the IOP that
+                                       waiting for being handled by FW*/
 
        void *                          dma_coherent;
        /* dma_coherent used for memory free */
@@ -353,7 +443,7 @@ struct CommandControlBlock
 {
        struct ARCMSR_CDB               arcmsr_cdb;
        /*
-       ** 0-503 (size of CDB=504):
+       ** 0-503 (size of CDB = 504):
        ** arcmsr messenger scsi command descriptor size 504 bytes
        */
        uint32_t                        cdb_shifted_phyaddr;
@@ -466,7 +556,9 @@ struct SENSE_DATA
 #define     ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE               0x01
 #define     ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE                    0x1F
 
-extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
+extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *);
+extern void arcmsr_iop_message_read(struct AdapterControlBlock *);
+extern struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *);
 extern struct class_device_attribute *arcmsr_host_attrs[];
-extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
+extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *);
 void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
index 06c0dce3b83916095064eab9af2c440098a9bea3..d04d1aa28fa4512c1196768ac3511be520584e71 100644 (file)
@@ -8,7 +8,7 @@
 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
 **
 **     Web site: www.areca.com.tw
-**       E-mail: erich@areca.com.tw
+**       E-mail: support@areca.com.tw
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License version 2 as
@@ -49,6 +49,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/pci.h>
 
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 
 struct class_device_attribute *arcmsr_host_attrs[];
 
-static ssize_t
-arcmsr_sysfs_iop_message_read(struct kobject *kobj,
-                             struct bin_attribute *bin_attr,
-                             char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj,
+                                            struct bin_attribute *bin,
+                                            char *buf, loff_t off,
+                                            size_t count)
 {
        struct class_device *cdev = container_of(kobj,struct class_device,kobj);
        struct Scsi_Host *host = class_to_shost(cdev);
        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
-       struct MessageUnit __iomem *reg = acb->pmu;
        uint8_t *pQbuffer,*ptmpQbuffer;
        int32_t allxfer_len = 0;
 
@@ -85,12 +85,13 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
                allxfer_len++;
        }
        if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-               struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
-                                       &reg->message_rbuffer;
-               uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+               struct QBUFFER *prbuffer;
+               uint8_t *iop_data;
                int32_t iop_len;
 
                acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+               prbuffer = arcmsr_get_iop_rqbuffer(acb);
+               iop_data = (uint8_t *)prbuffer->data;
                iop_len = readl(&prbuffer->data_len);
                while (iop_len > 0) {
                        acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
@@ -99,16 +100,15 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
                        iop_data++;
                        iop_len--;
                }
-               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
-                               &reg->inbound_doorbell);
+               arcmsr_iop_message_read(acb);
        }
        return (allxfer_len);
 }
 
-static ssize_t
-arcmsr_sysfs_iop_message_write(struct kobject *kobj,
-                              struct bin_attribute *bin_attr,
-                              char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj,
+                                             struct bin_attribute *bin,
+                                             char *buf, loff_t off,
+                                             size_t count)
 {
        struct class_device *cdev = container_of(kobj,struct class_device,kobj);
        struct Scsi_Host *host = class_to_shost(cdev);
@@ -126,7 +126,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
        wqbuf_lastindex = acb->wqbuf_lastindex;
        wqbuf_firstindex = acb->wqbuf_firstindex;
        if (wqbuf_lastindex != wqbuf_firstindex) {
-               arcmsr_post_Qbuffer(acb);
+               arcmsr_post_ioctldata2iop(acb);
                return 0;       /*need retry*/
        } else {
                my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
@@ -144,7 +144,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
                        if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
                                acb->acb_flags &=
                                        ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
-                               arcmsr_post_Qbuffer(acb);
+                               arcmsr_post_ioctldata2iop(acb);
                        }
                        return count;
                } else {
@@ -153,15 +153,14 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
        }
 }
 
-static ssize_t
-arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
-                              struct bin_attribute *bin_attr,
-                              char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
+                                             struct bin_attribute *bin,
+                                             char *buf, loff_t off,
+                                             size_t count)
 {
        struct class_device *cdev = container_of(kobj,struct class_device,kobj);
        struct Scsi_Host *host = class_to_shost(cdev);
        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
-       struct MessageUnit __iomem *reg = acb->pmu;
        uint8_t *pQbuffer;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -169,8 +168,7 @@ arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
 
        if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
                acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
-               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
-                               , &reg->inbound_doorbell);
+               arcmsr_iop_message_read(acb);
        }
        acb->acb_flags |=
                (ACB_F_MESSAGE_WQBUFFER_CLEARED
@@ -191,6 +189,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
        .attr = {
                .name = "mu_read",
                .mode = S_IRUSR ,
+               .owner = THIS_MODULE,
        },
        .size = 1032,
        .read = arcmsr_sysfs_iop_message_read,
@@ -200,6 +199,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
        .attr = {
                .name = "mu_write",
                .mode = S_IWUSR,
+               .owner = THIS_MODULE,
        },
        .size = 1032,
        .write = arcmsr_sysfs_iop_message_write,
@@ -209,6 +209,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
        .attr = {
                .name = "mu_clear",
                .mode = S_IWUSR,
+               .owner = THIS_MODULE,
        },
        .size = 1,
        .write = arcmsr_sysfs_iop_message_clear,
@@ -219,31 +220,26 @@ int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
        struct Scsi_Host *host = acb->host;
        int error;
 
-       error = sysfs_create_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_read_attr);
+       error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
        if (error) {
                printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
                goto error_bin_file_message_read;
        }
-       error = sysfs_create_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_write_attr);
+       error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
        if (error) {
                printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
                goto error_bin_file_message_write;
        }
-       error = sysfs_create_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_clear_attr);
+       error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
        if (error) {
                printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
                goto error_bin_file_message_clear;
        }
        return 0;
 error_bin_file_message_clear:
-       sysfs_remove_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_write_attr);
+       sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
 error_bin_file_message_write:
-       sysfs_remove_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_read_attr);
+       sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
 error_bin_file_message_read:
        return error;
 }
@@ -252,12 +248,9 @@ void
 arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
        struct Scsi_Host *host = acb->host;
 
-       sysfs_remove_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_clear_attr);
-       sysfs_remove_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_write_attr);
-       sysfs_remove_bin_file(&host->shost_classdev.kobj,
-                               &arcmsr_sysfs_message_read_attr);
+       sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
+       sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
+       sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
 }
 
 
index 0ddfc21e9f7df3d6c54fc5a91737f31f75867db7..cfcf40159eab96e0d512dabec9b39c4c3c19296a 100644 (file)
@@ -9,7 +9,7 @@
 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
 **
 **     Web site: www.areca.com.tw
-**       E-mail: erich@areca.com.tw
+**       E-mail: support@areca.com.tw
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License version 2 as
 #include <scsi/scsicam.h>
 #include "arcmsr.h"
 
-MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
+MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
 MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
 
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
+                                       struct scsi_cmnd *cmd);
+static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
 static int arcmsr_abort(struct scsi_cmnd *);
 static int arcmsr_bus_reset(struct scsi_cmnd *);
 static int arcmsr_bios_param(struct scsi_device *sdev,
-                               struct block_device *bdev, sector_t capacity, int *info);
-static int arcmsr_queue_command(struct scsi_cmnd * cmd,
-                               void (*done) (struct scsi_cmnd *));
+               struct block_device *bdev, sector_t capacity, int *info);
+static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+                                       void (*done) (struct scsi_cmnd *));
 static int arcmsr_probe(struct pci_dev *pdev,
                                const struct pci_device_id *id);
 static void arcmsr_remove(struct pci_dev *pdev);
 static void arcmsr_shutdown(struct pci_dev *pdev);
 static void arcmsr_iop_init(struct AdapterControlBlock *acb);
 static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
 static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
-static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
-static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
-                                               pci_channel_state_t state);
-static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
-static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
+                                                               int queue_depth)
 {
        if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
                queue_depth = ARCMSR_MAX_CMD_PERLUN;
@@ -123,17 +124,25 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
        .use_clustering         = ENABLE_CLUSTERING,
        .shost_attrs            = arcmsr_host_attrs,
 };
+#ifdef CONFIG_SCSI_ARCMSR_AER
+static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
+static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
+                                               pci_channel_state_t state);
+
 static struct pci_error_handlers arcmsr_pci_error_handlers = {
        .error_detected         = arcmsr_pci_error_detected,
        .slot_reset             = arcmsr_pci_slot_reset,
 };
-
+#endif
 static struct pci_device_id arcmsr_device_id_table[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
@@ -153,20 +162,20 @@ static struct pci_driver arcmsr_pci_driver = {
        .probe                  = arcmsr_probe,
        .remove                 = arcmsr_remove,
        .shutdown               = arcmsr_shutdown,
+       #ifdef CONFIG_SCSI_ARCMSR_AER
        .err_handler            = &arcmsr_pci_error_handlers,
+       #endif
 };
 
 static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
 {
        irqreturn_t handle_state;
-       struct AdapterControlBlock *acb;
-       unsigned long flags;
+       struct AdapterControlBlock *acb = dev_id;
 
-       acb = (struct AdapterControlBlock *)dev_id;
-
-       spin_lock_irqsave(acb->host->host_lock, flags);
+       spin_lock(acb->host->host_lock);
        handle_state = arcmsr_interrupt(acb);
-       spin_unlock_irqrestore(acb->host->host_lock, flags);
+       spin_unlock(acb->host->host_lock);
+
        return handle_state;
 }
 
@@ -198,68 +207,159 @@ static int arcmsr_bios_param(struct scsi_device *sdev,
        return 0;
 }
 
-static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
 {
        struct pci_dev *pdev = acb->pdev;
-       struct MessageUnit __iomem *reg = acb->pmu;
-       u32 ccb_phyaddr_hi32;
-       void *dma_coherent;
-       dma_addr_t dma_coherent_handle, dma_addr;
-       struct CommandControlBlock *ccb_tmp;
-       int i, j;
+       u16 dev_id;
+       pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+       switch (dev_id) {
+       case 0x1201 : {
+               acb->adapter_type = ACB_ADAPTER_TYPE_B;
+               }
+               break;
 
-       dma_coherent = dma_alloc_coherent(&pdev->dev,
+       default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
+       }
+}
+
+static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+{
+
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               struct pci_dev *pdev = acb->pdev;
+               void *dma_coherent;
+               dma_addr_t dma_coherent_handle, dma_addr;
+               struct CommandControlBlock *ccb_tmp;
+               uint32_t intmask_org;
+               int i, j;
+
+               acb->pmu = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+               if (!acb->pmu) {
+                       printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
+                                                       acb->host->host_no);
+               }
+
+               dma_coherent = dma_alloc_coherent(&pdev->dev,
                        ARCMSR_MAX_FREECCB_NUM *
                        sizeof (struct CommandControlBlock) + 0x20,
                        &dma_coherent_handle, GFP_KERNEL);
-       if (!dma_coherent)
-               return -ENOMEM;
+               if (!dma_coherent)
+                       return -ENOMEM;
 
-       acb->dma_coherent = dma_coherent;
-       acb->dma_coherent_handle = dma_coherent_handle;
+               acb->dma_coherent = dma_coherent;
+               acb->dma_coherent_handle = dma_coherent_handle;
 
-       if (((unsigned long)dma_coherent & 0x1F)) {
-               dma_coherent = dma_coherent +
-                       (0x20 - ((unsigned long)dma_coherent & 0x1F));
-               dma_coherent_handle = dma_coherent_handle +
-                       (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
-       }
+               if (((unsigned long)dma_coherent & 0x1F)) {
+                       dma_coherent = dma_coherent +
+                               (0x20 - ((unsigned long)dma_coherent & 0x1F));
+                       dma_coherent_handle = dma_coherent_handle +
+                               (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+               }
 
-       dma_addr = dma_coherent_handle;
-       ccb_tmp = (struct CommandControlBlock *)dma_coherent;
-       for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
-               ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
-               ccb_tmp->acb = acb;
-               acb->pccb_pool[i] = ccb_tmp;
-               list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
-               dma_addr = dma_addr + sizeof (struct CommandControlBlock);
-               ccb_tmp++;
-       }
+               dma_addr = dma_coherent_handle;
+               ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+               for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+                       ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+                       ccb_tmp->acb = acb;
+                       acb->pccb_pool[i] = ccb_tmp;
+                       list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+                       dma_addr = dma_addr + sizeof(struct CommandControlBlock);
+                       ccb_tmp++;
+               }
 
-       acb->vir2phy_offset = (unsigned long)ccb_tmp -
-                             (unsigned long)dma_addr;
-       for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
-               for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
-                       acb->devstate[i][j] = ARECA_RAID_GOOD;
+               acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
+               for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+                       for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+                               acb->devstate[i][j] = ARECA_RAID_GONE;
 
-       /*
-       ** here we need to tell iop 331 our ccb_tmp.HighPart
-       ** if ccb_tmp.HighPart is not zero
-       */
-       ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
-       if (ccb_phyaddr_hi32 != 0) {
-               writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->message_rwbuffer[0]);
-               writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
-               writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
-               if (arcmsr_wait_msgint_ready(acb))
-                       printk(KERN_NOTICE "arcmsr%d: "
-                              "'set ccb high part physical address' timeout\n",
-                               acb->host->host_no);
-       }
+               /*
+               ** here we need to tell iop 331 our ccb_tmp.HighPart
+               ** if ccb_tmp.HighPart is not zero
+               */
+               intmask_org = arcmsr_disable_outbound_ints(acb);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+
+               struct pci_dev *pdev = acb->pdev;
+               struct MessageUnit_B *reg;
+               void *mem_base0, *mem_base1;
+               void *dma_coherent;
+               dma_addr_t dma_coherent_handle, dma_addr;
+               uint32_t intmask_org;
+               struct CommandControlBlock *ccb_tmp;
+               int i, j;
+
+               dma_coherent = dma_alloc_coherent(&pdev->dev,
+                       ((ARCMSR_MAX_FREECCB_NUM *
+                       sizeof(struct CommandControlBlock) + 0x20) +
+                       sizeof(struct MessageUnit_B)),
+                       &dma_coherent_handle, GFP_KERNEL);
+               if (!dma_coherent)
+                       return -ENOMEM;
+
+               acb->dma_coherent = dma_coherent;
+               acb->dma_coherent_handle = dma_coherent_handle;
+
+               if (((unsigned long)dma_coherent & 0x1F)) {
+                       dma_coherent = dma_coherent +
+                               (0x20 - ((unsigned long)dma_coherent & 0x1F));
+                       dma_coherent_handle = dma_coherent_handle +
+                               (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+               }
 
-       writel(readl(&reg->outbound_intmask) |
-                       ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
-              &reg->outbound_intmask);
+               reg = (struct MessageUnit_B *)(dma_coherent +
+               ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+
+               dma_addr = dma_coherent_handle;
+               ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+               for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+                       ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+                       ccb_tmp->acb = acb;
+                       acb->pccb_pool[i] = ccb_tmp;
+                       list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+                       dma_addr = dma_addr + sizeof(struct CommandControlBlock);
+                       ccb_tmp++;
+               }
+
+               reg = (struct MessageUnit_B *)(dma_coherent +
+               ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+               acb->pmu = (struct MessageUnit *)reg;
+               mem_base0 = ioremap(pci_resource_start(pdev, 0),
+                                       pci_resource_len(pdev, 0));
+               mem_base1 = ioremap(pci_resource_start(pdev, 2),
+                                       pci_resource_len(pdev, 2));
+               reg->drv2iop_doorbell_reg = (uint32_t *)((char *)mem_base0 +
+                                               ARCMSR_DRV2IOP_DOORBELL);
+               reg->drv2iop_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 +
+                                               ARCMSR_DRV2IOP_DOORBELL_MASK);
+               reg->iop2drv_doorbell_reg = (uint32_t *)((char *)mem_base0 +
+                                                       ARCMSR_IOP2DRV_DOORBELL);
+               reg->iop2drv_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 +
+                                               ARCMSR_IOP2DRV_DOORBELL_MASK);
+               reg->ioctl_wbuffer_reg = (uint32_t *)((char *)mem_base1 +
+                                                       ARCMSR_IOCTL_WBUFFER);
+               reg->ioctl_rbuffer_reg = (uint32_t *)((char *)mem_base1 +
+                                                       ARCMSR_IOCTL_RBUFFER);
+               reg->msgcode_rwbuffer_reg = (uint32_t *)((char *)mem_base1 +
+                                                       ARCMSR_MSGCODE_RWBUFFER);
+
+               acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
+               for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+                       for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+                               acb->devstate[i][j] = ARECA_RAID_GOOD;
+
+               /*
+               ** here we need to tell iop 331 our ccb_tmp.HighPart
+               ** if ccb_tmp.HighPart is not zero
+               */
+               intmask_org = arcmsr_disable_outbound_ints(acb);
+               }
+               break;
+       }
        return 0;
 }
 
@@ -310,16 +410,11 @@ static int arcmsr_probe(struct pci_dev *pdev,
        host->unique_id = (bus << 8) | dev_fun;
        host->irq = pdev->irq;
        error = pci_request_regions(pdev, "arcmsr");
-       if (error)
+       if (error) {
                goto out_host_put;
-
-       acb->pmu = ioremap(pci_resource_start(pdev, 0),
-                          pci_resource_len(pdev, 0));
-       if (!acb->pmu) {
-               printk(KERN_NOTICE "arcmsr%d: memory"
-                       " mapping region fail \n", acb->host->host_no);
-               goto out_release_regions;
        }
+       arcmsr_define_adapter_type(acb);
+
        acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
                           ACB_F_MESSAGE_RQBUFFER_CLEARED |
                           ACB_F_MESSAGE_WQBUFFER_READED);
@@ -328,10 +423,10 @@ static int arcmsr_probe(struct pci_dev *pdev,
 
        error = arcmsr_alloc_ccb_pool(acb);
        if (error)
-               goto out_iounmap;
+               goto out_release_regions;
 
        error = request_irq(pdev->irq, arcmsr_do_interrupt,
-                       IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
+                           IRQF_SHARED, "arcmsr", acb);
        if (error)
                goto out_free_ccb_pool;
 
@@ -349,14 +444,15 @@ static int arcmsr_probe(struct pci_dev *pdev,
                goto out_free_sysfs;
 
        scsi_scan_host(host);
+       #ifdef CONFIG_SCSI_ARCMSR_AER
        pci_enable_pcie_error_reporting(pdev);
+       #endif
        return 0;
  out_free_sysfs:
  out_free_irq:
        free_irq(pdev->irq, acb);
  out_free_ccb_pool:
        arcmsr_free_ccb_pool(acb);
- out_iounmap:
        iounmap(acb->pmu);
  out_release_regions:
        pci_release_regions(pdev);
@@ -368,17 +464,84 @@ static int arcmsr_probe(struct pci_dev *pdev,
        return error;
 }
 
-static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+       uint32_t Index;
+       uint8_t Retries = 0x00;
+
+       do {
+               for (Index = 0; Index < 100; Index++) {
+                       if (readl(&reg->outbound_intstatus) &
+                                       ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+                               writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+                                       &reg->outbound_intstatus);
+                               return 0x00;
+                       }
+                       msleep(10);
+               }/*max 1 seconds*/
+
+       } while (Retries++ < 20);/*max 20 sec*/
+       return 0xff;
+}
+
+static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+       uint32_t Index;
+       uint8_t Retries = 0x00;
+
+       do {
+               for (Index = 0; Index < 100; Index++) {
+                       if (readl(reg->iop2drv_doorbell_reg)
+                               & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+                               writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
+                                       , reg->iop2drv_doorbell_reg);
+                               return 0x00;
+                       }
+                       msleep(10);
+               }/*max 1 seconds*/
+
+       } while (Retries++ < 20);/*max 20 sec*/
+       return 0xff;
+}
+
+static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
 
        writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
-       if (arcmsr_wait_msgint_ready(acb))
+       if (arcmsr_hba_wait_msgint_ready(acb))
+               printk(KERN_NOTICE
+                       "arcmsr%d: wait 'abort all outstanding command' timeout \n"
+                       , acb->host->host_no);
+}
+
+static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+
+       writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
+       if (arcmsr_hbb_wait_msgint_ready(acb))
                printk(KERN_NOTICE
                        "arcmsr%d: wait 'abort all outstanding command' timeout \n"
                        , acb->host->host_no);
 }
 
+static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+{
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               arcmsr_abort_hba_allcmd(acb);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               arcmsr_abort_hbb_allcmd(acb);
+               }
+       }
+}
+
 static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
 {
        struct scsi_cmnd *pcmd = ccb->pcmd;
@@ -400,28 +563,239 @@ static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
        pcmd->scsi_done(pcmd);
 }
 
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+       int retry_count = 30;
+
+       writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+       do {
+               if (!arcmsr_hba_wait_msgint_ready(acb))
+                       break;
+               else {
+                       retry_count--;
+                       printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+                       timeout, retry count down = %d \n", acb->host->host_no, retry_count);
+               }
+       } while (retry_count != 0);
+}
+
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+       int retry_count = 30;
+
+       writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg);
+       do {
+               if (!arcmsr_hbb_wait_msgint_ready(acb))
+                       break;
+               else {
+                       retry_count--;
+                       printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+                       timeout,retry count down = %d \n", acb->host->host_no, retry_count);
+               }
+       } while (retry_count != 0);
+}
+
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               arcmsr_flush_hba_cache(acb);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               arcmsr_flush_hbb_cache(acb);
+               }
+       }
+}
+
+static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
+{
+
+       struct scsi_cmnd *pcmd = ccb->pcmd;
+       struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+
+       pcmd->result = DID_OK << 16;
+       if (sensebuffer) {
+               int sense_data_length =
+                       sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer)
+                       ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer);
+               memset(sensebuffer, 0, sizeof(pcmd->sense_buffer));
+               memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+               sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
+               sensebuffer->Valid = 1;
+       }
+}
+
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
+{
+       u32 orig_mask = 0;
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A : {
+               struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+               orig_mask = readl(&reg->outbound_intmask)|\
+                               ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+               writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
+                                               &reg->outbound_intmask);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B : {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \
+                                       (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
+               writel(0, reg->iop2drv_doorbell_mask_reg);
+               }
+               break;
+       }
+       return orig_mask;
+}
+
+static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
+                       struct CommandControlBlock *ccb, uint32_t flag_ccb)
+{
+
+       uint8_t id, lun;
+       id = ccb->pcmd->device->id;
+       lun = ccb->pcmd->device->lun;
+       if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+               if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+                       acb->devstate[id][lun] = ARECA_RAID_GOOD;
+                       ccb->pcmd->result = DID_OK << 16;
+                       arcmsr_ccb_complete(ccb, 1);
+       } else {
+               switch (ccb->arcmsr_cdb.DeviceStatus) {
+               case ARCMSR_DEV_SELECT_TIMEOUT: {
+                       acb->devstate[id][lun] = ARECA_RAID_GONE;
+                       ccb->pcmd->result = DID_NO_CONNECT << 16;
+                       arcmsr_ccb_complete(ccb, 1);
+                       }
+                       break;
+
+               case ARCMSR_DEV_ABORTED:
+
+               case ARCMSR_DEV_INIT_FAIL: {
+                       acb->devstate[id][lun] = ARECA_RAID_GONE;
+                       ccb->pcmd->result = DID_BAD_TARGET << 16;
+                       arcmsr_ccb_complete(ccb, 1);
+                       }
+                       break;
+
+               case ARCMSR_DEV_CHECK_CONDITION: {
+                       acb->devstate[id][lun] = ARECA_RAID_GOOD;
+                       arcmsr_report_sense_info(ccb);
+                       arcmsr_ccb_complete(ccb, 1);
+                       }
+                       break;
+
+               default:
+                               printk(KERN_NOTICE
+                                       "arcmsr%d: scsi id = %d lun = %d"
+                                       " isr get command error done, "
+                                       "but got unknown DeviceStatus = 0x%x \n"
+                                       , acb->host->host_no
+                                       , id
+                                       , lun
+                                       , ccb->arcmsr_cdb.DeviceStatus);
+                                       acb->devstate[id][lun] = ARECA_RAID_GONE;
+                                       ccb->pcmd->result = DID_NO_CONNECT << 16;
+                                       arcmsr_ccb_complete(ccb, 1);
+                       break;
+               }
+       }
+}
+
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+
+{
+       struct CommandControlBlock *ccb;
+
+       ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+       if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+               if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+                       struct scsi_cmnd *abortcmd = ccb->pcmd;
+                       if (abortcmd) {
+                               abortcmd->result |= DID_ABORT << 16;
+                               arcmsr_ccb_complete(ccb, 1);
+                               printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
+                               isr got aborted command \n", acb->host->host_no, ccb);
+                       }
+               }
+               printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
+                               done acb = '0x%p'"
+                               "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
+                               " ccboutstandingcount = %d \n"
+                               , acb->host->host_no
+                               , acb
+                               , ccb
+                               , ccb->acb
+                               , ccb->startdone
+                               , atomic_read(&acb->ccboutstandingcount));
+               }
+       arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+}
+
+static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
+{
+       int i = 0;
+       uint32_t flag_ccb;
+
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A __iomem *reg = \
+                       (struct MessageUnit_A *)acb->pmu;
+               uint32_t outbound_intstatus;
+               outbound_intstatus = readl(&reg->outbound_intstatus) & \
+                                       acb->outbound_int_enable;
+               /*clear and abort all outbound posted Q*/
+               writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
+               while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) \
+                               && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+                       arcmsr_drain_donequeue(acb, flag_ccb);
+               }
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               /*clear all outbound posted Q*/
+               for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
+                       if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
+                               writel(0, &reg->done_qbuffer[i]);
+                               arcmsr_drain_donequeue(acb, flag_ccb);
+                       }
+                       writel(0, &reg->post_qbuffer[i]);
+               }
+               reg->doneq_index = 0;
+               reg->postq_index = 0;
+               }
+               break;
+       }
+}
 static void arcmsr_remove(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
        struct AdapterControlBlock *acb =
                (struct AdapterControlBlock *) host->hostdata;
-       struct MessageUnit __iomem *reg = acb->pmu;
        int poll_count = 0;
 
        arcmsr_free_sysfs_attr(acb);
        scsi_remove_host(host);
        arcmsr_stop_adapter_bgrb(acb);
        arcmsr_flush_adapter_cache(acb);
-       writel(readl(&reg->outbound_intmask) |
-               ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
-               &reg->outbound_intmask);
+       arcmsr_disable_outbound_ints(acb);
        acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
        acb->acb_flags &= ~ACB_F_IOP_INITED;
 
-       for (poll_count = 0; poll_count < 256; poll_count++) {
+       for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) {
                if (!atomic_read(&acb->ccboutstandingcount))
                        break;
-               arcmsr_interrupt(acb);
+               arcmsr_interrupt(acb);/* FIXME: need spinlock */
                msleep(25);
        }
 
@@ -429,8 +803,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
                int i;
 
                arcmsr_abort_allcmd(acb);
-               for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
-                       readl(&reg->outbound_queueport);
+               arcmsr_done4abort_postqueue(acb);
                for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
                        struct CommandControlBlock *ccb = acb->pccb_pool[i];
                        if (ccb->startdone == ARCMSR_CCB_START) {
@@ -477,77 +850,34 @@ static void arcmsr_module_exit(void)
 module_init(arcmsr_module_init);
 module_exit(arcmsr_module_exit);
 
-static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
-{
-       struct MessageUnit __iomem *reg = acb->pmu;
-       u32 orig_mask = readl(&reg->outbound_intmask);
-
-       writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
-                       &reg->outbound_intmask);
-       return orig_mask;
-}
-
-static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
-               u32 orig_mask)
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
+                                               u32 intmask_org)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
        u32 mask;
 
-       mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
-                            ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
-       writel(mask, &reg->outbound_intmask);
-}
-
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
-{
-       struct MessageUnit __iomem *reg = acb->pmu;
-
-       writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
-       if (arcmsr_wait_msgint_ready(acb))
-               printk(KERN_NOTICE
-                       "arcmsr%d: wait 'flush adapter cache' timeout \n"
-                       , acb->host->host_no);
-}
+       switch (acb->adapter_type) {
 
-static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
-{
-       struct scsi_cmnd *pcmd = ccb->pcmd;
-       struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+       case ACB_ADAPTER_TYPE_A : {
+               struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+               mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
+                            ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+               writel(mask, &reg->outbound_intmask);
+               acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+               }
+               break;
 
-       pcmd->result = DID_OK << 16;
-       if (sensebuffer) {
-               int sense_data_length =
-                       sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer)
-                       ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer);
-               memset(sensebuffer, 0, sizeof (pcmd->sense_buffer));
-               memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
-               sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
-               sensebuffer->Valid = 1;
+       case ACB_ADAPTER_TYPE_B : {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \
+                       ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE);
+               writel(mask, reg->iop2drv_doorbell_mask_reg);
+               acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
+               }
        }
 }
 
-static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
-       struct MessageUnit __iomem *reg = acb->pmu;
-       uint32_t Index;
-       uint8_t Retries = 0x00;
-
-       do {
-               for (Index = 0; Index < 100; Index++) {
-                       if (readl(&reg->outbound_intstatus)
-                               & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
-                               writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT
-                                       , &reg->outbound_intstatus);
-                               return 0x00;
-                       }
-                       msleep_interruptible(10);
-               }/*max 1 seconds*/
-       } while (Retries++ < 20);/*max 20 sec*/
-       return 0xff;
-}
-
-static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
-       struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
+static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
+       struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
 {
        struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
        int8_t *psge = (int8_t *)&arcmsr_cdb->u;
@@ -556,7 +886,7 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
        int nseg;
 
        ccb->pcmd = pcmd;
-       memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
+       memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
        arcmsr_cdb->Bus = 0;
        arcmsr_cdb->TargetID = pcmd->device->id;
        arcmsr_cdb->LUN = pcmd->device->lun;
@@ -609,52 +939,85 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
 
 static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
        uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
        struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
-
        atomic_inc(&acb->ccboutstandingcount);
        ccb->startdone = ARCMSR_CCB_START;
-       if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
-               writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu;
+
+               if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
+                       writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
                        &reg->inbound_queueport);
-       else
-               writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
-}
+               else {
+                               writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+               }
+               }
+               break;
 
-void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb)
-{
-       struct MessageUnit __iomem *reg = acb->pmu;
-       struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
-       uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
-       int32_t allxfer_len = 0;
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               uint32_t ending_index, index = reg->postq_index;
 
-       if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
-               acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
-               while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
-                       && (allxfer_len < 124)) {
-                       writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
-                       acb->wqbuf_firstindex++;
-                       acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-                       iop_data++;
-                       allxfer_len++;
+               ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
+               writel(0, &reg->post_qbuffer[ending_index]);
+               if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
+                       writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
+                                                &reg->post_qbuffer[index]);
+               }
+               else {
+                       writel(cdb_shifted_phyaddr, &reg->post_qbuffer[index]);
                }
-               writel(allxfer_len, &pwbuffer->data_len);
-               writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK
-                       , &reg->inbound_doorbell);
+               index++;
+               index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
+               reg->postq_index = index;
+               writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg);
+               }
+               break;
        }
 }
 
-static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
-
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
        acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
        writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
-       if (arcmsr_wait_msgint_ready(acb))
+
+       if (arcmsr_hba_wait_msgint_ready(acb)) {
+               printk(KERN_NOTICE
+                       "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+                       , acb->host->host_no);
+       }
+}
+
+static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+       acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+       writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg);
+
+       if (arcmsr_hbb_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE
                        "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
                        , acb->host->host_no);
+       }
+}
+
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+{
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               arcmsr_stop_hba_bgrb(acb);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               arcmsr_stop_hbb_bgrb(acb);
+               }
+               break;
+       }
 }
 
 static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
@@ -665,151 +1028,260 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
                acb->dma_coherent_handle);
 }
 
-static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
-       struct CommandControlBlock *ccb;
-       uint32_t flag_ccb, outbound_intstatus, outbound_doorbell;
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+               }
+               break;
 
-       outbound_intstatus = readl(&reg->outbound_intstatus)
-               & acb->outbound_int_enable;
-       writel(outbound_intstatus, &reg->outbound_intstatus);
-       if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
-               outbound_doorbell = readl(&reg->outbound_doorbell);
-               writel(outbound_doorbell, &reg->outbound_doorbell);
-               if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
-                       struct QBUFFER __iomem * prbuffer =
-                               (struct QBUFFER __iomem *) &reg->message_rbuffer;
-                       uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
-                       int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
-
-                       rqbuf_lastindex = acb->rqbuf_lastindex;
-                       rqbuf_firstindex = acb->rqbuf_firstindex;
-                       iop_len = readl(&prbuffer->data_len);
-                       my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1)
-                                       &(ARCMSR_MAX_QBUFFER - 1);
-                       if (my_empty_len >= iop_len) {
-                               while (iop_len > 0) {
-                                       acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
-                                       acb->rqbuf_lastindex++;
-                                       acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-                                       iop_data++;
-                                       iop_len--;
-                               }
-                               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
-                                       &reg->inbound_doorbell);
-                       } else
-                               acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
-               }
-               if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
-                       acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
-                       if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
-                               struct QBUFFER __iomem * pwbuffer =
-                                               (struct QBUFFER __iomem *) &reg->message_wbuffer;
-                               uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
-                               int32_t allxfer_len = 0;
-
-                               acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
-                               while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
-                                       && (allxfer_len < 124)) {
-                                       writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
-                                       acb->wqbuf_firstindex++;
-                                       acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-                                       iop_data++;
-                                       allxfer_len++;
-                               }
-                               writel(allxfer_len, &pwbuffer->data_len);
-                               writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
-                                       &reg->inbound_doorbell);
-                       }
-                       if (acb->wqbuf_firstindex == acb->wqbuf_lastindex)
-                               acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
                }
+               break;
        }
-       if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
-               int id, lun;
+}
+
+static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
+{
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
                /*
-               ****************************************************************
-               **            areca cdb command done
-               ****************************************************************
+               ** push inbound doorbell tell iop, driver data write ok
+               ** and wait reply on next hwinterrupt for next Qbuffer post
                */
-               while (1) {
-                       if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF)
-                               break;/*chip FIFO no ccb for completion already*/
-                       /* check if command done with no error*/
-                       ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
-                               (flag_ccb << 5));
-                       if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
-                               if (ccb->startdone == ARCMSR_CCB_ABORTED) {
-                                       struct scsi_cmnd *abortcmd = ccb->pcmd;
-                                       if (abortcmd) {
-                                       abortcmd->result |= DID_ABORT >> 16;
-                                       arcmsr_ccb_complete(ccb, 1);
-                                       printk(KERN_NOTICE
-                                               "arcmsr%d: ccb ='0x%p' isr got aborted command \n"
-                                               , acb->host->host_no, ccb);
-                                       }
-                                       continue;
-                               }
-                               printk(KERN_NOTICE
-                                       "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'"
-                                       "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
-                                       " ccboutstandingcount = %d \n"
-                                       , acb->host->host_no
-                                       , acb
-                                       , ccb
-                                       , ccb->acb
-                                       , ccb->startdone
-                                       , atomic_read(&acb->ccboutstandingcount));
-                               continue;
-                       }
-                       id = ccb->pcmd->device->id;
-                       lun = ccb->pcmd->device->lun;
-                       if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
-                               if (acb->devstate[id][lun] == ARECA_RAID_GONE)
-                                       acb->devstate[id][lun] = ARECA_RAID_GOOD;
-                               ccb->pcmd->result = DID_OK << 16;
-                               arcmsr_ccb_complete(ccb, 1);
-                       } else {
-                               switch(ccb->arcmsr_cdb.DeviceStatus) {
-                               case ARCMSR_DEV_SELECT_TIMEOUT: {
-                                               acb->devstate[id][lun] = ARECA_RAID_GONE;
-                                               ccb->pcmd->result = DID_NO_CONNECT << 16;
-                                               arcmsr_ccb_complete(ccb, 1);
-                                       }
-                                       break;
-                               case ARCMSR_DEV_ABORTED:
-                               case ARCMSR_DEV_INIT_FAIL: {
-                                               acb->devstate[id][lun] = ARECA_RAID_GONE;
-                                               ccb->pcmd->result = DID_BAD_TARGET << 16;
-                                               arcmsr_ccb_complete(ccb, 1);
-                                       }
-                                       break;
-                               case ARCMSR_DEV_CHECK_CONDITION: {
-                                               acb->devstate[id][lun] = ARECA_RAID_GOOD;
-                                               arcmsr_report_sense_info(ccb);
-                                               arcmsr_ccb_complete(ccb, 1);
-                                       }
-                                       break;
-                               default:
-                                       printk(KERN_NOTICE
-                                               "arcmsr%d: scsi id = %d lun = %d"
-                                               " isr get command error done, "
-                                               "but got unknown DeviceStatus = 0x%x \n"
-                                               , acb->host->host_no
-                                               , id
-                                               , lun
-                                               , ccb->arcmsr_cdb.DeviceStatus);
-                                               acb->devstate[id][lun] = ARECA_RAID_GONE;
-                                               ccb->pcmd->result = DID_NO_CONNECT << 16;
-                                               arcmsr_ccb_complete(ccb, 1);
-                                       break;
-                               }
-                       }
-               }/*drain reply FIFO*/
+               writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, &reg->inbound_doorbell);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               /*
+               ** push inbound doorbell tell iop, driver data write ok
+               ** and wait reply on next hwinterrupt for next Qbuffer post
+               */
+               writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg);
+               }
+               break;
+       }
+}
+
+struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
+{
+       static struct QBUFFER *qbuffer;
+
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+               qbuffer = (struct QBUFFER __iomem *) &reg->message_rbuffer;
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               qbuffer = (struct QBUFFER __iomem *) reg->ioctl_rbuffer_reg;
+               }
+               break;
+       }
+       return qbuffer;
+}
+
+static struct QBUFFER *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
+{
+       static struct QBUFFER *pqbuffer;
+
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+               pqbuffer = (struct QBUFFER *) &reg->message_wbuffer;
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B  *reg = (struct MessageUnit_B *)acb->pmu;
+               pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg;
+               }
+               break;
+       }
+       return pqbuffer;
+}
+
+static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
+{
+       struct QBUFFER *prbuffer;
+       struct QBUFFER *pQbuffer;
+       uint8_t *iop_data;
+       int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+
+       rqbuf_lastindex = acb->rqbuf_lastindex;
+       rqbuf_firstindex = acb->rqbuf_firstindex;
+       prbuffer = arcmsr_get_iop_rqbuffer(acb);
+       iop_data = (uint8_t *)prbuffer->data;
+       iop_len = prbuffer->data_len;
+       my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1);
+
+       if (my_empty_len >= iop_len)
+       {
+               while (iop_len > 0) {
+                       pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
+                       memcpy(pQbuffer, iop_data,1);
+                       rqbuf_lastindex++;
+                       rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+                       iop_data++;
+                       iop_len--;
+               }
+               acb->rqbuf_lastindex = rqbuf_lastindex;
+               arcmsr_iop_message_read(acb);
+       }
+
+       else {
+               acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
+       }
+}
+
+static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
+{
+       acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
+       if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
+               uint8_t *pQbuffer;
+               struct QBUFFER *pwbuffer;
+               uint8_t *iop_data;
+               int32_t allxfer_len = 0;
+
+               acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+               pwbuffer = arcmsr_get_iop_wqbuffer(acb);
+               iop_data = (uint8_t __iomem *)pwbuffer->data;
+
+               while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \
+                                                       (allxfer_len < 124)) {
+                       pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
+                       memcpy(iop_data, pQbuffer, 1);
+                       acb->wqbuf_firstindex++;
+                       acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+                       iop_data++;
+                       allxfer_len++;
+               }
+               pwbuffer->data_len = allxfer_len;
+
+               arcmsr_iop_message_wrote(acb);
+       }
+
+       if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) {
+               acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+       }
+}
+
+static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
+{
+       uint32_t outbound_doorbell;
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+
+       outbound_doorbell = readl(&reg->outbound_doorbell);
+       writel(outbound_doorbell, &reg->outbound_doorbell);
+       if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
+               arcmsr_iop2drv_data_wrote_handle(acb);
+       }
+
+       if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)    {
+               arcmsr_iop2drv_data_read_handle(acb);
+       }
+}
+
+static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
+{
+       uint32_t flag_ccb;
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+
+       while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
+               arcmsr_drain_donequeue(acb, flag_ccb);
+       }
+}
+
+static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
+{
+       uint32_t index;
+       uint32_t flag_ccb;
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+
+       index = reg->doneq_index;
+
+       while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
+               writel(0, &reg->done_qbuffer[index]);
+               arcmsr_drain_donequeue(acb, flag_ccb);
+               index++;
+               index %= ARCMSR_MAX_HBB_POSTQUEUE;
+               reg->doneq_index = index;
+       }
+}
+
+static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
+{
+       uint32_t outbound_intstatus;
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+
+       outbound_intstatus = readl(&reg->outbound_intstatus) & \
+                                                       acb->outbound_int_enable;
+       if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))      {
+               return 1;
+       }
+       writel(outbound_intstatus, &reg->outbound_intstatus);
+       if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)       {
+               arcmsr_hba_doorbell_isr(acb);
+       }
+       if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
+               arcmsr_hba_postqueue_isr(acb);
+       }
+       return 0;
+}
+
+static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
+{
+       uint32_t outbound_doorbell;
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+
+       outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & \
+                                                       acb->outbound_int_enable;
+       if (!outbound_doorbell)
+               return 1;
+
+       writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
+
+       if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)   {
+               arcmsr_iop2drv_data_wrote_handle(acb);
+       }
+       if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
+               arcmsr_iop2drv_data_read_handle(acb);
+       }
+       if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
+               arcmsr_hbb_postqueue_isr(acb);
+       }
+
+       return 0;
+}
+
+static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+{
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               if (arcmsr_handle_hba_isr(acb)) {
+                       return IRQ_NONE;
+               }
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               if (arcmsr_handle_hbb_isr(acb)) {
+                       return IRQ_NONE;
+               }
+               }
+               break;
        }
-       if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
-               return IRQ_NONE;
        return IRQ_HANDLED;
 }
 
@@ -818,16 +1290,47 @@ static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
        if (acb) {
                /* stop adapter background rebuild */
                if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
+                       uint32_t intmask_org;
                        acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+                       intmask_org = arcmsr_disable_outbound_ints(acb);
                        arcmsr_stop_adapter_bgrb(acb);
                        arcmsr_flush_adapter_cache(acb);
+                       arcmsr_enable_outbound_ints(acb, intmask_org);
+               }
+       }
+}
+
+void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
+{
+       int32_t wqbuf_firstindex, wqbuf_lastindex;
+       uint8_t *pQbuffer;
+       struct QBUFFER *pwbuffer;
+       uint8_t *iop_data;
+       int32_t allxfer_len = 0;
+
+       pwbuffer = arcmsr_get_iop_wqbuffer(acb);
+       iop_data = (uint8_t __iomem *)pwbuffer->data;
+       if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
+               acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+               wqbuf_firstindex = acb->wqbuf_firstindex;
+               wqbuf_lastindex = acb->wqbuf_lastindex;
+               while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) {
+                       pQbuffer = &acb->wqbuffer[wqbuf_firstindex];
+                       memcpy(iop_data, pQbuffer, 1);
+                       wqbuf_firstindex++;
+                       wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+                       iop_data++;
+                       allxfer_len++;
                }
+               acb->wqbuf_firstindex = wqbuf_firstindex;
+               pwbuffer->data_len = allxfer_len;
+               arcmsr_iop_message_wrote(acb);
        }
 }
 
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd)
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
+                                       struct scsi_cmnd *cmd)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
        struct CMD_MESSAGE_FIELD *pcmdmessagefld;
        int retvalue = 0, transfer_len = 0;
        char *buffer;
@@ -836,7 +1339,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
                                                (uint32_t ) cmd->cmnd[6] << 16 |
                                                (uint32_t ) cmd->cmnd[7] << 8  |
                                                (uint32_t ) cmd->cmnd[8];
-                                       /* 4 bytes: Areca io control code */
+                                               /* 4 bytes: Areca io control code */
 
        sg = scsi_sglist(cmd);
        buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
@@ -852,194 +1355,199 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
        }
        pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
        switch(controlcode) {
+
        case ARCMSR_MESSAGE_READ_RQBUFFER: {
-                       unsigned long *ver_addr;
-                       dma_addr_t buf_handle;
-                       uint8_t *pQbuffer, *ptmpQbuffer;
-                       int32_t allxfer_len = 0;
+               unsigned long *ver_addr;
+               dma_addr_t buf_handle;
+               uint8_t *pQbuffer, *ptmpQbuffer;
+               int32_t allxfer_len = 0;
+
+               ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+               if (!ver_addr) {
+                       retvalue = ARCMSR_MESSAGE_FAIL;
+                       goto message_out;
+               }
+               ptmpQbuffer = (uint8_t *) ver_addr;
+               while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
+                       && (allxfer_len < 1031)) {
+                       pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
+                       memcpy(ptmpQbuffer, pQbuffer, 1);
+                       acb->rqbuf_firstindex++;
+                       acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+                       ptmpQbuffer++;
+                       allxfer_len++;
+               }
+               if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 
-                       ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
-                       if (!ver_addr) {
-                               retvalue = ARCMSR_MESSAGE_FAIL;
-                               goto message_out;
-                       }
-                       ptmpQbuffer = (uint8_t *) ver_addr;
-                       while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
-                               && (allxfer_len < 1031)) {
-                               pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
-                               memcpy(ptmpQbuffer, pQbuffer, 1);
-                               acb->rqbuf_firstindex++;
-                               acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-                               ptmpQbuffer++;
-                               allxfer_len++;
-                       }
-                       if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-                               struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
-                                                       &reg->message_rbuffer;
-                               uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
-                               int32_t iop_len;
-
-                               acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
-                               iop_len = readl(&prbuffer->data_len);
-                               while (iop_len > 0) {
-                                       acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
-                                       acb->rqbuf_lastindex++;
-                                       acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-                                       iop_data++;
-                                       iop_len--;
-                               }
-                               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
-                                               &reg->inbound_doorbell);
+                       struct QBUFFER *prbuffer;
+                       uint8_t *iop_data;
+                       int32_t iop_len;
+
+                       acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+                       prbuffer = arcmsr_get_iop_rqbuffer(acb);
+                       iop_data = (uint8_t *)prbuffer->data;
+                       iop_len = readl(&prbuffer->data_len);
+                       while (iop_len > 0) {
+                               acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+                               acb->rqbuf_lastindex++;
+                               acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+                               iop_data++;
+                               iop_len--;
                        }
-                       memcpy(pcmdmessagefld->messagedatabuffer,
-                               (uint8_t *)ver_addr, allxfer_len);
-                       pcmdmessagefld->cmdmessage.Length = allxfer_len;
-                       pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
-                       pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+                       arcmsr_iop_message_read(acb);
+               }
+               memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len);
+               pcmdmessagefld->cmdmessage.Length = allxfer_len;
+               pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+               pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
                }
                break;
-       case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
-                       unsigned long *ver_addr;
-                       dma_addr_t buf_handle;
-                       int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
-                       uint8_t *pQbuffer, *ptmpuserbuffer;
 
-                       ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
-                       if (!ver_addr) {
-                               retvalue = ARCMSR_MESSAGE_FAIL;
-                               goto message_out;
-                       }
-                       ptmpuserbuffer = (uint8_t *)ver_addr;
-                       user_len = pcmdmessagefld->cmdmessage.Length;
-                       memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
-                       wqbuf_lastindex = acb->wqbuf_lastindex;
-                       wqbuf_firstindex = acb->wqbuf_firstindex;
-                       if (wqbuf_lastindex != wqbuf_firstindex) {
+       case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
+               unsigned long *ver_addr;
+               dma_addr_t buf_handle;
+               int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+               uint8_t *pQbuffer, *ptmpuserbuffer;
+
+               ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+               if (!ver_addr) {
+                       retvalue = ARCMSR_MESSAGE_FAIL;
+                       goto message_out;
+               }
+               ptmpuserbuffer = (uint8_t *)ver_addr;
+               user_len = pcmdmessagefld->cmdmessage.Length;
+               memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
+               wqbuf_lastindex = acb->wqbuf_lastindex;
+               wqbuf_firstindex = acb->wqbuf_firstindex;
+               if (wqbuf_lastindex != wqbuf_firstindex) {
+                       struct SENSE_DATA *sensebuffer =
+                               (struct SENSE_DATA *)cmd->sense_buffer;
+                       arcmsr_post_ioctldata2iop(acb);
+                       /* has error report sensedata */
+                       sensebuffer->ErrorCode = 0x70;
+                       sensebuffer->SenseKey = ILLEGAL_REQUEST;
+                       sensebuffer->AdditionalSenseLength = 0x0A;
+                       sensebuffer->AdditionalSenseCode = 0x20;
+                       sensebuffer->Valid = 1;
+                       retvalue = ARCMSR_MESSAGE_FAIL;
+               } else {
+                       my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+                               &(ARCMSR_MAX_QBUFFER - 1);
+                       if (my_empty_len >= user_len) {
+                               while (user_len > 0) {
+                                       pQbuffer =
+                                       &acb->wqbuffer[acb->wqbuf_lastindex];
+                                       memcpy(pQbuffer, ptmpuserbuffer, 1);
+                                       acb->wqbuf_lastindex++;
+                                       acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+                                       ptmpuserbuffer++;
+                                       user_len--;
+                               }
+                               if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+                                       acb->acb_flags &=
+                                               ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+                                       arcmsr_post_ioctldata2iop(acb);
+                               }
+                       } else {
+                               /* has error report sensedata */
                                struct SENSE_DATA *sensebuffer =
                                        (struct SENSE_DATA *)cmd->sense_buffer;
-                               arcmsr_post_Qbuffer(acb);
-                               /* has error report sensedata */
                                sensebuffer->ErrorCode = 0x70;
                                sensebuffer->SenseKey = ILLEGAL_REQUEST;
                                sensebuffer->AdditionalSenseLength = 0x0A;
                                sensebuffer->AdditionalSenseCode = 0x20;
                                sensebuffer->Valid = 1;
                                retvalue = ARCMSR_MESSAGE_FAIL;
-                       } else {
-                               my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
-                                               &(ARCMSR_MAX_QBUFFER - 1);
-                               if (my_empty_len >= user_len) {
-                                       while (user_len > 0) {
-                                               pQbuffer =
-                                               &acb->wqbuffer[acb->wqbuf_lastindex];
-                                               memcpy(pQbuffer, ptmpuserbuffer, 1);
-                                               acb->wqbuf_lastindex++;
-                                               acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-                                               ptmpuserbuffer++;
-                                               user_len--;
-                                       }
-                                       if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
-                                               acb->acb_flags &=
-                                                       ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
-                                               arcmsr_post_Qbuffer(acb);
-                                       }
-                               } else {
-                                       /* has error report sensedata */
-                                       struct SENSE_DATA *sensebuffer =
-                                               (struct SENSE_DATA *)cmd->sense_buffer;
-                                       sensebuffer->ErrorCode = 0x70;
-                                       sensebuffer->SenseKey = ILLEGAL_REQUEST;
-                                       sensebuffer->AdditionalSenseLength = 0x0A;
-                                       sensebuffer->AdditionalSenseCode = 0x20;
-                                       sensebuffer->Valid = 1;
-                                       retvalue = ARCMSR_MESSAGE_FAIL;
-                               }
+                       }
                        }
                        pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
                }
                break;
+
        case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
-                       uint8_t *pQbuffer = acb->rqbuffer;
+               uint8_t *pQbuffer = acb->rqbuffer;
 
-                       if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-                               acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
-                               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
-                                       &reg->inbound_doorbell);
-                       }
-                       acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
-                       acb->rqbuf_firstindex = 0;
-                       acb->rqbuf_lastindex = 0;
-                       memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
-                       pcmdmessagefld->cmdmessage.ReturnCode =
-                               ARCMSR_MESSAGE_RETURNCODE_OK;
+               if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+                       acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+                       arcmsr_iop_message_read(acb);
+               }
+               acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
+               acb->rqbuf_firstindex = 0;
+               acb->rqbuf_lastindex = 0;
+               memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+               pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
                }
                break;
+
        case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
-                       uint8_t *pQbuffer = acb->wqbuffer;
+               uint8_t *pQbuffer = acb->wqbuffer;
 
-                       if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-                               acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
-                               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
-                                               , &reg->inbound_doorbell);
-                       }
-                       acb->acb_flags |=
-                               (ACB_F_MESSAGE_WQBUFFER_CLEARED |
-                                       ACB_F_MESSAGE_WQBUFFER_READED);
-                       acb->wqbuf_firstindex = 0;
-                       acb->wqbuf_lastindex = 0;
-                       memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
-                       pcmdmessagefld->cmdmessage.ReturnCode =
-                               ARCMSR_MESSAGE_RETURNCODE_OK;
+               if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+                       acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+                       arcmsr_iop_message_read(acb);
+               }
+               acb->acb_flags |=
+                       (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+                               ACB_F_MESSAGE_WQBUFFER_READED);
+               acb->wqbuf_firstindex = 0;
+               acb->wqbuf_lastindex = 0;
+               memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+               pcmdmessagefld->cmdmessage.ReturnCode =
+                       ARCMSR_MESSAGE_RETURNCODE_OK;
                }
                break;
+
        case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
-                       uint8_t *pQbuffer;
+               uint8_t *pQbuffer;
 
-                       if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-                               acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
-                               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
-                                               , &reg->inbound_doorbell);
-                       }
-                       acb->acb_flags |=
-                               (ACB_F_MESSAGE_WQBUFFER_CLEARED
-                               | ACB_F_MESSAGE_RQBUFFER_CLEARED
-                               | ACB_F_MESSAGE_WQBUFFER_READED);
-                       acb->rqbuf_firstindex = 0;
-                       acb->rqbuf_lastindex = 0;
-                       acb->wqbuf_firstindex = 0;
-                       acb->wqbuf_lastindex = 0;
-                       pQbuffer = acb->rqbuffer;
-                       memset(pQbuffer, 0, sizeof (struct QBUFFER));
-                       pQbuffer = acb->wqbuffer;
-                       memset(pQbuffer, 0, sizeof (struct QBUFFER));
-                       pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+               if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+                       acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+                       arcmsr_iop_message_read(acb);
+               }
+               acb->acb_flags |=
+                       (ACB_F_MESSAGE_WQBUFFER_CLEARED
+                       | ACB_F_MESSAGE_RQBUFFER_CLEARED
+                       | ACB_F_MESSAGE_WQBUFFER_READED);
+               acb->rqbuf_firstindex = 0;
+               acb->rqbuf_lastindex = 0;
+               acb->wqbuf_firstindex = 0;
+               acb->wqbuf_lastindex = 0;
+               pQbuffer = acb->rqbuffer;
+               memset(pQbuffer, 0, sizeof(struct QBUFFER));
+               pQbuffer = acb->wqbuffer;
+               memset(pQbuffer, 0, sizeof(struct QBUFFER));
+               pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
                }
                break;
+
        case ARCMSR_MESSAGE_RETURN_CODE_3F: {
-                       pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+               pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
                }
                break;
+
        case ARCMSR_MESSAGE_SAY_HELLO: {
-                       int8_t * hello_string = "Hello! I am ARCMSR";
+               int8_t *hello_string = "Hello! I am ARCMSR";
 
-                       memcpy(pcmdmessagefld->messagedatabuffer, hello_string
-                               , (int16_t)strlen(hello_string));
-                       pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+               memcpy(pcmdmessagefld->messagedatabuffer, hello_string
+                       , (int16_t)strlen(hello_string));
+               pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
                }
                break;
+
        case ARCMSR_MESSAGE_SAY_GOODBYE:
                arcmsr_iop_parking(acb);
                break;
+
        case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
                arcmsr_flush_adapter_cache(acb);
                break;
+
        default:
                retvalue = ARCMSR_MESSAGE_FAIL;
        }
- message_out:
      message_out:
        sg = scsi_sglist(cmd);
        kunmap_atomic(buffer - sg->offset, KM_IRQ0);
-
        return retvalue;
 }
 
@@ -1109,8 +1617,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
        void (* done)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = cmd->device->host;
-       struct AdapterControlBlock *acb =
-               (struct AdapterControlBlock *) host->hostdata;
+       struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
        struct CommandControlBlock *ccb;
        int target = cmd->device->id;
        int lun = cmd->device->lun;
@@ -1153,26 +1660,27 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
        ccb = arcmsr_get_freeccb(acb);
        if (!ccb)
                return SCSI_MLQUEUE_HOST_BUSY;
+
        arcmsr_build_ccb(acb, ccb, cmd);
        arcmsr_post_ccb(acb, ccb);
        return 0;
 }
 
-static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
        char *acb_firm_model = acb->firm_model;
        char *acb_firm_version = acb->firm_version;
-       char __iomem *iop_firm_model = (char __iomem *) &reg->message_rwbuffer[15];
-       char __iomem *iop_firm_version = (char __iomem *) &reg->message_rwbuffer[17];
+       char *iop_firm_model = (char *) (&reg->message_rwbuffer[15]);
+       char *iop_firm_version = (char *) (&reg->message_rwbuffer[17]);
        int count;
 
        writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
-       if (arcmsr_wait_msgint_ready(acb))
-               printk(KERN_NOTICE
-                       "arcmsr%d: wait "
-                       "'get adapter firmware miscellaneous data' timeout \n"
-                       , acb->host->host_no);
+       if (arcmsr_hba_wait_msgint_ready(acb)) {
+               printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+                       miscellaneous data' timeout \n", acb->host->host_no);
+       }
+
        count = 8;
        while (count) {
                *acb_firm_model = readb(iop_firm_model);
@@ -1180,6 +1688,7 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
                iop_firm_model++;
                count--;
        }
+
        count = 16;
        while (count) {
                *acb_firm_version = readb(iop_firm_version);
@@ -1187,28 +1696,93 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
                iop_firm_version++;
                count--;
        }
-       printk(KERN_INFO
-               "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
+
+       printk(KERN_INFO        "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
                , acb->host->host_no
                , acb->firm_version);
+
        acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
        acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
        acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
        acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
 }
 
-static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+       uint32_t *lrwbuffer = reg->msgcode_rwbuffer_reg;
+       char *acb_firm_model = acb->firm_model;
+       char *acb_firm_version = acb->firm_version;
+       char *iop_firm_model = (char *) (&lrwbuffer[15]);
+       /*firm_model,15,60-67*/
+       char *iop_firm_version = (char *) (&lrwbuffer[17]);
+       /*firm_version,17,68-83*/
+       int count;
+
+       writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+       if (arcmsr_hbb_wait_msgint_ready(acb)) {
+               printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+                       miscellaneous data' timeout \n", acb->host->host_no);
+       }
+
+       count = 8;
+       while (count)
+       {
+               *acb_firm_model = readb(iop_firm_model);
+               acb_firm_model++;
+               iop_firm_model++;
+               count--;
+       }
+
+       count = 16;
+       while (count)
+       {
+               *acb_firm_version = readb(iop_firm_version);
+               acb_firm_version++;
+               iop_firm_version++;
+               count--;
+       }
+
+       printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
+                       acb->host->host_no,
+                       acb->firm_version);
+
+       lrwbuffer++;
+       acb->firm_request_len = readl(lrwbuffer++);
+       /*firm_request_len,1,04-07*/
+       acb->firm_numbers_queue = readl(lrwbuffer++);
+       /*firm_numbers_queue,2,08-11*/
+       acb->firm_sdram_size = readl(lrwbuffer++);
+       /*firm_sdram_size,3,12-15*/
+       acb->firm_hd_channels = readl(lrwbuffer);
+       /*firm_ide_channels,4,16-19*/
+}
+
+static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+{
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               arcmsr_get_hba_config(acb);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               arcmsr_get_hbb_config(acb);
+               }
+               break;
+       }
+}
+
+static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
        struct CommandControlBlock *poll_ccb)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
        struct CommandControlBlock *ccb;
        uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
-       int id, lun;
 
polling_ccb_retry:
      polling_hba_ccb_retry:
        poll_count++;
-       outbound_intstatus = readl(&reg->outbound_intstatus)
-                                       & acb->outbound_int_enable;
+       outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
        writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
        while (1) {
                if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
@@ -1218,17 +1792,14 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
                                msleep(25);
                                if (poll_count > 100)
                                        break;
-                               goto polling_ccb_retry;
+                               goto polling_hba_ccb_retry;
                        }
                }
-               ccb = (struct CommandControlBlock *)
-                       (acb->vir2phy_offset + (flag_ccb << 5));
-               if ((ccb->acb != acb) ||
-                       (ccb->startdone != ARCMSR_CCB_START)) {
-                       if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
-                               (ccb == poll_ccb)) {
-                               printk(KERN_NOTICE
-                                       "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+               ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+               poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+               if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+                       if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
+                               printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
                                        " poll command abort successfully \n"
                                        , acb->host->host_no
                                        , ccb->pcmd->device->id
@@ -1239,176 +1810,280 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
                                poll_ccb_done = 1;
                                continue;
                        }
-                       printk(KERN_NOTICE
-                               "arcmsr%d: polling get an illegal ccb"
-                               " command done ccb ='0x%p'"
+                       printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+                               " command done ccb = '0x%p'"
                                "ccboutstandingcount = %d \n"
                                , acb->host->host_no
                                , ccb
                                , atomic_read(&acb->ccboutstandingcount));
                        continue;
                }
-               id = ccb->pcmd->device->id;
-               lun = ccb->pcmd->device->lun;
-               if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
-                       if (acb->devstate[id][lun] == ARECA_RAID_GONE)
-                               acb->devstate[id][lun] = ARECA_RAID_GOOD;
-                       ccb->pcmd->result = DID_OK << 16;
-                       arcmsr_ccb_complete(ccb, 1);
-               } else {
-                       switch(ccb->arcmsr_cdb.DeviceStatus) {
-                       case ARCMSR_DEV_SELECT_TIMEOUT: {
-                                       acb->devstate[id][lun] = ARECA_RAID_GONE;
-                                       ccb->pcmd->result = DID_NO_CONNECT << 16;
-                                       arcmsr_ccb_complete(ccb, 1);
-                               }
-                               break;
-                       case ARCMSR_DEV_ABORTED:
-                       case ARCMSR_DEV_INIT_FAIL: {
-                                       acb->devstate[id][lun] = ARECA_RAID_GONE;
-                                       ccb->pcmd->result = DID_BAD_TARGET << 16;
-                                       arcmsr_ccb_complete(ccb, 1);
+               arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+       }
+}
+
+static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \
+                                       struct CommandControlBlock *poll_ccb)
+{
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               struct CommandControlBlock *ccb;
+               uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
+               int index;
+
+       polling_hbb_ccb_retry:
+               poll_count++;
+               /* clear doorbell interrupt */
+               writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+               while (1) {
+                       index = reg->doneq_index;
+                       if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
+                               if (poll_ccb_done)
+                                       break;
+                               else {
+                                       msleep(25);
+                                       if (poll_count > 100)
+                                               break;
+                                       goto polling_hbb_ccb_retry;
                                }
-                               break;
-                       case ARCMSR_DEV_CHECK_CONDITION: {
-                                       acb->devstate[id][lun] = ARECA_RAID_GOOD;
-                                       arcmsr_report_sense_info(ccb);
+                       }
+                       writel(0, &reg->done_qbuffer[index]);
+                       index++;
+                       /*if last index number set it to 0 */
+                       index %= ARCMSR_MAX_HBB_POSTQUEUE;
+                       reg->doneq_index = index;
+                       /* check ifcommand done with no error*/
+                       ccb = (struct CommandControlBlock *)\
+      (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+                       poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+                       if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+                               if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+                                       printk(KERN_NOTICE "arcmsr%d: \
+               scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
+                                               ,acb->host->host_no
+                                               ,ccb->pcmd->device->id
+                                               ,ccb->pcmd->device->lun
+                                               ,ccb);
+                                       ccb->pcmd->result = DID_ABORT << 16;
                                        arcmsr_ccb_complete(ccb, 1);
+                                       continue;
                                }
-                               break;
-                       default:
-                               printk(KERN_NOTICE
-                                       "arcmsr%d: scsi id = %d lun = %d"
-                                       " polling and getting command error done"
-                                       "but got unknown DeviceStatus = 0x%x \n"
+                               printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+                                       " command done ccb = '0x%p'"
+                                       "ccboutstandingcount = %d \n"
                                        , acb->host->host_no
-                                       , id
-                                       , lun
-                                       , ccb->arcmsr_cdb.DeviceStatus);
-                               acb->devstate[id][lun] = ARECA_RAID_GONE;
-                               ccb->pcmd->result = DID_BAD_TARGET << 16;
-                               arcmsr_ccb_complete(ccb, 1);
-                               break;
+                                       , ccb
+                                       , atomic_read(&acb->ccboutstandingcount));
+                               continue;
                        }
+                       arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+               }       /*drain reply FIFO*/
+}
+
+static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \
+                                       struct CommandControlBlock *poll_ccb)
+{
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               arcmsr_polling_hba_ccbdone(acb,poll_ccb);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               arcmsr_polling_hbb_ccbdone(acb,poll_ccb);
                }
        }
 }
-static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb)
+
+static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
 {
-       int i = 0, found = 0;
-       int id, lun;
-       uint32_t flag_ccb, outbound_intstatus;
-       struct MessageUnit __iomem *reg = acb->pmu;
-       struct CommandControlBlock *ccb;
-       /*clear and abort all outbound posted Q*/
-
-       while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
-(i++ < 256)){
-               ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
-(flag_ccb << 5));
-       if (ccb){
-               if ((ccb->acb != acb)||(ccb->startdone != \
-ARCMSR_CCB_START)){
-                               printk(KERN_NOTICE "arcmsr%d: polling get \
-an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n",
-                                       acb->host->host_no, ccb,
-                                       atomic_read(&acb->ccboutstandingcount));
-                               continue;
+       uint32_t cdb_phyaddr, ccb_phyaddr_hi32;
+       dma_addr_t dma_coherent_handle;
+       /*
+       ********************************************************************
+       ** here we need to tell iop 331 our freeccb.HighPart
+       ** if freeccb.HighPart is not zero
+       ********************************************************************
+       */
+       dma_coherent_handle = acb->dma_coherent_handle;
+       cdb_phyaddr = (uint32_t)(dma_coherent_handle);
+       ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+       /*
+       ***********************************************************************
+       **    if adapter type B, set window of "post command Q"
+       ***********************************************************************
+       */
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               if (ccb_phyaddr_hi32 != 0) {
+                       struct MessageUnit_A __iomem *reg = \
+                                       (struct MessageUnit_A *)acb->pmu;
+                       uint32_t intmask_org;
+                       intmask_org = arcmsr_disable_outbound_ints(acb);
+                       writel(ARCMSR_SIGNATURE_SET_CONFIG, \
+                                               &reg->message_rwbuffer[0]);
+                       writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+                       writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
+                                                       &reg->inbound_msgaddr0);
+                       if (arcmsr_hba_wait_msgint_ready(acb)) {
+                               printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
+                               part physical address timeout\n",
+                               acb->host->host_no);
+                               return 1;
                        }
+                       arcmsr_enable_outbound_ints(acb, intmask_org);
+               }
+               }
+               break;
 
-                       id = ccb->pcmd->device->id;
-                       lun = ccb->pcmd->device->lun;
-                       if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){
-                               if (acb->devstate[id][lun] == ARECA_RAID_GONE)
-                                       acb->devstate[id][lun] = ARECA_RAID_GOOD;
-                               ccb->pcmd->result = DID_OK << 16;
-                               arcmsr_ccb_complete(ccb, 1);
-                       }
-                       else {
-                               switch(ccb->arcmsr_cdb.DeviceStatus) {
-                               case ARCMSR_DEV_SELECT_TIMEOUT: {
-                                               acb->devstate[id][lun] = ARECA_RAID_GONE;
-                                               ccb->pcmd->result = DID_NO_CONNECT << 16;
-                                               arcmsr_ccb_complete(ccb, 1);
-                               }
-                               break;
+       case ACB_ADAPTER_TYPE_B: {
+               unsigned long post_queue_phyaddr;
+               uint32_t *rwbuffer;
 
-                               case ARCMSR_DEV_ABORTED:
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               uint32_t intmask_org;
+               intmask_org = arcmsr_disable_outbound_ints(acb);
+               reg->postq_index = 0;
+               reg->doneq_index = 0;
+               writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg);
+               if (arcmsr_hbb_wait_msgint_ready(acb)) {
+                       printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
+                               acb->host->host_no);
+                       return 1;
+               }
+               post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \
+               sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ;
+               rwbuffer = reg->msgcode_rwbuffer_reg;
+               /* driver "set config" signature */
+               writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
+               /* normal should be zero */
+               writel(ccb_phyaddr_hi32, rwbuffer++);
+               /* postQ size (256 + 8)*4        */
+               writel(post_queue_phyaddr, rwbuffer++);
+               /* doneQ size (256 + 8)*4        */
+               writel(post_queue_phyaddr + 1056, rwbuffer++);
+               /* ccb maxQ size must be --> [(256 + 8)*4]*/
+               writel(1056, rwbuffer);
+
+               writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg);
+               if (arcmsr_hbb_wait_msgint_ready(acb)) {
+                       printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
+                       timeout \n",acb->host->host_no);
+                       return 1;
+               }
 
-                               case ARCMSR_DEV_INIT_FAIL: {
-                                               acb->devstate[id][lun] =
-                                                       ARECA_RAID_GONE;
-                                               ccb->pcmd->result =
-                                                       DID_BAD_TARGET << 16;
-                               arcmsr_ccb_complete(ccb, 1);
-                               }
-                               break;
+               writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg);
+               if (arcmsr_hbb_wait_msgint_ready(acb)) {
+                       printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\
+                       ,acb->host->host_no);
+                       return 1;
+               }
+               arcmsr_enable_outbound_ints(acb, intmask_org);
+               }
+               break;
+       }
+       return 0;
+}
 
-                               case ARCMSR_DEV_CHECK_CONDITION: {
-                                               acb->devstate[id][lun] =
-                                                       ARECA_RAID_GOOD;
-                                               arcmsr_report_sense_info(ccb);
-                                               arcmsr_ccb_complete(ccb, 1);
-                               }
-                               break;
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
+{
+       uint32_t firmware_state = 0;
 
-                               default:
-                                               printk(KERN_NOTICE
-                                                     "arcmsr%d: scsi id = %d \
-                                                       lun = %d""polling and \
-                                                       getting command error \
-                                                       done""but got unknown \
-                                                       DeviceStatus = 0x%x \n",
-                                                       acb->host->host_no, id,
-                                          lun, ccb->arcmsr_cdb.DeviceStatus);
-                                               acb->devstate[id][lun] =
-                                                               ARECA_RAID_GONE;
-                                               ccb->pcmd->result =
-                                                       DID_BAD_TARGET << 16;
-                                               arcmsr_ccb_complete(ccb, 1);
-                               break;
-                              }
-       }
-                      found = 1;
-              }
+       switch (acb->adapter_type) {
+
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+               do {
+                       firmware_state = readl(&reg->outbound_msgaddr1);
+               } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
+               }
+               break;
+
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               do {
+                       firmware_state = readl(reg->iop2drv_doorbell_reg);
+               } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
+               }
+               break;
        }
-       if (found){
-               outbound_intstatus = readl(&reg->outbound_intstatus) & \
-                       acb->outbound_int_enable;
-               writel(outbound_intstatus, &reg->outbound_intstatus);
-               /*clear interrupt*/
+}
+
+static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+       acb->acb_flags |= ACB_F_MSG_START_BGRB;
+       writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
+       if (arcmsr_hba_wait_msgint_ready(acb)) {
+               printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+                               rebulid' timeout \n", acb->host->host_no);
        }
-       return;
 }
 
+static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
+{
+       struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+       acb->acb_flags |= ACB_F_MSG_START_BGRB;
+       writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg);
+       if (arcmsr_hbb_wait_msgint_ready(acb)) {
+               printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+                               rebulid' timeout \n",acb->host->host_no);
+       }
+}
 
-static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
 {
-       struct MessageUnit __iomem *reg = acb->pmu;
-       uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0;
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A:
+               arcmsr_start_hba_bgrb(acb);
+               break;
+       case ACB_ADAPTER_TYPE_B:
+               arcmsr_start_hbb_bgrb(acb);
+               break;
+       }
+}
 
-       do {
-               firmware_state = readl(&reg->outbound_msgaddr1);
-       } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK));
-       intmask_org = readl(&reg->outbound_intmask)
-                       | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
-       arcmsr_get_firmware_spec(acb);
+static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
+{
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_A: {
+               struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu;
+               uint32_t outbound_doorbell;
+               /* empty doorbell Qbuffer if door bell ringed */
+               outbound_doorbell = readl(&reg->outbound_doorbell);
+               /*clear doorbell interrupt */
+               writel(outbound_doorbell, &reg->outbound_doorbell);
+               writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+               }
+               break;
 
-       acb->acb_flags |= ACB_F_MSG_START_BGRB;
-       writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
-       if (arcmsr_wait_msgint_ready(acb)) {
-               printk(KERN_NOTICE "arcmsr%d: "
-                       "wait 'start adapter background rebulid' timeout\n",
-                       acb->host->host_no);
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+               /*clear interrupt and message state*/
+               writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+               writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+               /* let IOP know data has been read */
+               }
+               break;
        }
+}
 
-       outbound_doorbell = readl(&reg->outbound_doorbell);
-       writel(outbound_doorbell, &reg->outbound_doorbell);
-       writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
-       mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
-                       | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
-       writel(intmask_org & mask, &reg->outbound_intmask);
-       acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+{
+       uint32_t intmask_org;
+
+       arcmsr_wait_firmware_ready(acb);
+       arcmsr_iop_confirm(acb);
+       /* disable all outbound interrupt */
+       intmask_org = arcmsr_disable_outbound_ints(acb);
+       arcmsr_get_firmware_spec(acb);
+       /*start background rebuild*/
+       arcmsr_start_adapter_bgrb(acb);
+       /* empty doorbell Qbuffer if door bell ringed */
+       arcmsr_clear_doorbell_queue_buffer(acb);
+       /* enable outbound Post Queue,outbound doorbell Interrupt */
+       arcmsr_enable_outbound_ints(acb, intmask_org);
        acb->acb_flags |= ACB_F_IOP_INITED;
 }
 
@@ -1421,22 +2096,24 @@ static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
        if (atomic_read(&acb->ccboutstandingcount) != 0) {
                /* talk to iop 331 outstanding command aborted */
                arcmsr_abort_allcmd(acb);
+
                /* wait for 3 sec for all command aborted*/
-               msleep_interruptible(3000);
+               ssleep(3);
+
                /* disable all outbound interrupt */
                intmask_org = arcmsr_disable_outbound_ints(acb);
                /* clear all outbound posted Q */
-               arcmsr_done4_abort_postqueue(acb);
+               arcmsr_done4abort_postqueue(acb);
                for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
                        ccb = acb->pccb_pool[i];
                        if (ccb->startdone == ARCMSR_CCB_START) {
                                ccb->startdone = ARCMSR_CCB_ABORTED;
+                               arcmsr_ccb_complete(ccb, 1);
                        }
                }
                /* enable all outbound interrupt */
                arcmsr_enable_outbound_ints(acb, intmask_org);
        }
-
 }
 
 static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
@@ -1450,7 +2127,7 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
        for (i = 0; i < 400; i++) {
                if (!atomic_read(&acb->ccboutstandingcount))
                        break;
-               arcmsr_interrupt(acb);
+               arcmsr_interrupt(acb);/* FIXME: need spinlock */
                msleep(25);
        }
        arcmsr_iop_reset(acb);
@@ -1468,7 +2145,7 @@ static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
        /*
        ** Wait for 3 sec for all command done.
        */
-       msleep_interruptible(3000);
+       ssleep(3);
 
        intmask = arcmsr_disable_outbound_ints(acb);
        arcmsr_polling_ccbdone(acb, ccb);
@@ -1515,6 +2192,8 @@ static const char *arcmsr_info(struct Scsi_Host *host)
 
        switch (acb->pdev->device) {
        case PCI_DEVICE_ID_ARECA_1110:
+       case PCI_DEVICE_ID_ARECA_1200:
+       case PCI_DEVICE_ID_ARECA_1202:
        case PCI_DEVICE_ID_ARECA_1210:
                raid6 = 0;
                /*FALLTHRU*/
@@ -1522,6 +2201,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
        case PCI_DEVICE_ID_ARECA_1130:
        case PCI_DEVICE_ID_ARECA_1160:
        case PCI_DEVICE_ID_ARECA_1170:
+       case PCI_DEVICE_ID_ARECA_1201:
        case PCI_DEVICE_ID_ARECA_1220:
        case PCI_DEVICE_ID_ARECA_1230:
        case PCI_DEVICE_ID_ARECA_1260:
@@ -1544,287 +2224,82 @@ static const char *arcmsr_info(struct Scsi_Host *host)
                        ARCMSR_DRIVER_VERSION);
        return buf;
 }
-
+#ifdef CONFIG_SCSI_ARCMSR_AER
 static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
 {
-       struct Scsi_Host *host;
-       struct AdapterControlBlock *acb;
-       uint8_t bus, dev_fun;
-       int error;
-
-       error = pci_enable_device(pdev);
-       if (error)
-               return PCI_ERS_RESULT_DISCONNECT;
-       pci_set_master(pdev);
-
-       host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \
-(struct AdapterControlBlock));
-       if (!host)
-               return PCI_ERS_RESULT_DISCONNECT;
-       acb = (struct AdapterControlBlock *)host->hostdata;
-       memset(acb, 0, sizeof (struct AdapterControlBlock));
-
-       error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
-       if (error) {
-               error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-               if (error) {
-                       printk(KERN_WARNING
-                              "scsi%d: No suitable DMA mask available\n",
-                              host->host_no);
-                       return PCI_ERS_RESULT_DISCONNECT;
-               }
-       }
-       bus = pdev->bus->number;
-       dev_fun = pdev->devfn;
-       acb = (struct AdapterControlBlock *) host->hostdata;
-       memset(acb, 0, sizeof(struct AdapterControlBlock));
-       acb->pdev = pdev;
-       acb->host = host;
-       host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
-       host->max_lun = ARCMSR_MAX_TARGETLUN;
-       host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
-       host->max_cmd_len = 16;    /*this is issue of 64bit LBA, over 2T byte*/
-       host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
-       host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
-       host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
-       host->this_id = ARCMSR_SCSI_INITIATOR_ID;
-       host->unique_id = (bus << 8) | dev_fun;
-       host->irq = pdev->irq;
-       error = pci_request_regions(pdev, "arcmsr");
-       if (error)
-               return PCI_ERS_RESULT_DISCONNECT;
+       struct Scsi_Host *host = pci_get_drvdata(pdev);
+       struct AdapterControlBlock *acb =
+               (struct AdapterControlBlock *) host->hostdata;
+       uint32_t intmask_org;
+       int i, j;
 
-       acb->pmu = ioremap(pci_resource_start(pdev, 0),
-                          pci_resource_len(pdev, 0));
-       if (!acb->pmu) {
-               printk(KERN_NOTICE "arcmsr%d: memory"
-                       " mapping region fail \n", acb->host->host_no);
+       if (pci_enable_device(pdev)) {
                return PCI_ERS_RESULT_DISCONNECT;
        }
+       pci_set_master(pdev);
+       intmask_org = arcmsr_disable_outbound_ints(acb);
        acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
                           ACB_F_MESSAGE_RQBUFFER_CLEARED |
                           ACB_F_MESSAGE_WQBUFFER_READED);
        acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
-       INIT_LIST_HEAD(&acb->ccb_free_list);
-
-       error = arcmsr_alloc_ccb_pool(acb);
-       if (error)
-               return PCI_ERS_RESULT_DISCONNECT;
-
-       error = request_irq(pdev->irq, arcmsr_do_interrupt,
-                       IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
-       if (error)
-               return PCI_ERS_RESULT_DISCONNECT;
-
-       arcmsr_iop_init(acb);
-       if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
-             host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B;
-
-       pci_set_drvdata(pdev, host);
-
-       error = scsi_add_host(host, &pdev->dev);
-       if (error)
-               return PCI_ERS_RESULT_DISCONNECT;
+       for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+               for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+                       acb->devstate[i][j] = ARECA_RAID_GONE;
 
-       error = arcmsr_alloc_sysfs_attr(acb);
-       if (error)
-               return PCI_ERS_RESULT_DISCONNECT;
+       arcmsr_wait_firmware_ready(acb);
+       arcmsr_iop_confirm(acb);
+       /* disable all outbound interrupt */
+       arcmsr_get_firmware_spec(acb);
+       /*start background rebuild*/
+       arcmsr_start_adapter_bgrb(acb);
+       /* empty doorbell Qbuffer if door bell ringed */
+       arcmsr_clear_doorbell_queue_buffer(acb);
+       /* enable outbound Post Queue,outbound doorbell Interrupt */
+       arcmsr_enable_outbound_ints(acb, intmask_org);
+       acb->acb_flags |= ACB_F_IOP_INITED;
 
-       scsi_scan_host(host);
+       pci_enable_pcie_error_reporting(pdev);
        return PCI_ERS_RESULT_RECOVERED;
 }
 
 static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
-       struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
-       struct MessageUnit __iomem *reg = acb->pmu;
+       struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata;
        struct CommandControlBlock *ccb;
-       /*clear and abort all outbound posted Q*/
-       int i = 0, found = 0;
-       int id, lun;
-       uint32_t flag_ccb, outbound_intstatus;
-
-       while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
-                                                               (i++ < 256)){
-                       ccb = (struct CommandControlBlock *)(acb->vir2phy_offset
-                                                        + (flag_ccb << 5));
-                       if (ccb){
-                               if ((ccb->acb != acb)||(ccb->startdone !=
-                                                       ARCMSR_CCB_START)){
-                                       printk(KERN_NOTICE "arcmsr%d: polling \
-                                       get an illegal ccb"" command done ccb = '0x%p'"
-                                       "ccboutstandingcount = %d \n",
-                                       acb->host->host_no, ccb,
-                                       atomic_read(&acb->ccboutstandingcount));
-                                       continue;
-                               }
-
-                               id = ccb->pcmd->device->id;
-                               lun = ccb->pcmd->device->lun;
-                               if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
-                                       if (acb->devstate[id][lun] ==
-                                                               ARECA_RAID_GONE)
-                                               acb->devstate[id][lun] =
-                                                               ARECA_RAID_GOOD;
-                                       ccb->pcmd->result = DID_OK << 16;
-                                       arcmsr_ccb_complete(ccb, 1);
-                               }
-                               else {
-                                       switch(ccb->arcmsr_cdb.DeviceStatus) {
-                                       case ARCMSR_DEV_SELECT_TIMEOUT: {
-                                                       acb->devstate[id][lun] =
-                                                       ARECA_RAID_GONE;
-                                                       ccb->pcmd->result =
-                                                       DID_NO_CONNECT << 16;
-                                                       arcmsr_ccb_complete(ccb, 1);
-                                       }
-                                       break;
-
-                                       case ARCMSR_DEV_ABORTED:
-
-                                       case ARCMSR_DEV_INIT_FAIL: {
-                                                       acb->devstate[id][lun] =
-                                                        ARECA_RAID_GONE;
-                                                       ccb->pcmd->result =
-                                                       DID_BAD_TARGET << 16;
-                                                       arcmsr_ccb_complete(ccb, 1);
-                                       }
-                                       break;
-
-                                       case ARCMSR_DEV_CHECK_CONDITION: {
-                                                       acb->devstate[id][lun] =
-                                                        ARECA_RAID_GOOD;
-                                                       arcmsr_report_sense_info(ccb);
-                                                       arcmsr_ccb_complete(ccb, 1);
-                                       }
-                                       break;
+       uint32_t intmask_org;
+       int i = 0;
 
-                                       default:
-                                                       printk(KERN_NOTICE
-                                                               "arcmsr%d: scsi \
-                                                               id = %d lun = %d"
-                                                               " polling and \
-                                                               getting command \
-                                                               error done"
-                                                               "but got unknown \
-                                                       DeviceStatus = 0x%x \n"
-                                                       , acb->host->host_no,
-                                                               id, lun,
-                                               ccb->arcmsr_cdb.DeviceStatus);
-                                                       acb->devstate[id][lun] =
-                                                               ARECA_RAID_GONE;
-                                                       ccb->pcmd->result =
-                                                       DID_BAD_TARGET << 16;
-                                                       arcmsr_ccb_complete(ccb, 1);
-                                       break;
-                                       }
-                               }
-                               found = 1;
+       if (atomic_read(&acb->ccboutstandingcount) != 0) {
+               /* talk to iop 331 outstanding command aborted */
+               arcmsr_abort_allcmd(acb);
+               /* wait for 3 sec for all command aborted*/
+               ssleep(3);
+               /* disable all outbound interrupt */
+               intmask_org = arcmsr_disable_outbound_ints(acb);
+               /* clear all outbound posted Q */
+               arcmsr_done4abort_postqueue(acb);
+               for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+                       ccb = acb->pccb_pool[i];
+                       if (ccb->startdone == ARCMSR_CCB_START) {
+                               ccb->startdone = ARCMSR_CCB_ABORTED;
+                               arcmsr_ccb_complete(ccb, 1);
                        }
                }
-       if (found){
-               outbound_intstatus = readl(&reg->outbound_intstatus) &
-                                                       acb->outbound_int_enable;
-               writel(outbound_intstatus, &reg->outbound_intstatus);
-               /*clear interrupt*/
-                   }
-       return;
+               /* enable all outbound interrupt */
+               arcmsr_enable_outbound_ints(acb, intmask_org);
+       }
+       pci_disable_device(pdev);
 }
 
-
 static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev)
 {
-       struct Scsi_Host *host = pci_get_drvdata(pdev);
-       struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
-       struct MessageUnit __iomem *reg = acb->pmu;
-       struct CommandControlBlock *ccb;
-       /*clear and abort all outbound posted Q*/
-       int i = 0, found = 0;
-       int id, lun;
-       uint32_t flag_ccb, outbound_intstatus;
-
-       while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
-                                                               (i++ < 256)){
-                       ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
-                                                       (flag_ccb << 5));
-                       if (ccb){
-                               if ((ccb->acb != acb)||(ccb->startdone !=
-                                                       ARCMSR_CCB_START)){
-                                       printk(KERN_NOTICE
-                                               "arcmsr%d: polling get an illegal ccb"
-                                               " command done ccb = '0x%p'"
-                                               "ccboutstandingcount = %d \n",
-                                               acb->host->host_no, ccb,
-                                               atomic_read(&acb->ccboutstandingcount));
-                                       continue;
-                       }
-
-                       id = ccb->pcmd->device->id;
-                       lun = ccb->pcmd->device->lun;
-                       if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR))   {
-                               if (acb->devstate[id][lun] == ARECA_RAID_GONE)
-                                       acb->devstate[id][lun] = ARECA_RAID_GOOD;
-                               ccb->pcmd->result = DID_OK << 16;
-                               arcmsr_ccb_complete(ccb, 1);
-                       }
-                       else {
-                               switch(ccb->arcmsr_cdb.DeviceStatus) {
-                               case ARCMSR_DEV_SELECT_TIMEOUT: {
-                                               acb->devstate[id][lun] =
-                                                               ARECA_RAID_GONE;
-                                               ccb->pcmd->result =
-                                                       DID_NO_CONNECT << 16;
-                                               arcmsr_ccb_complete(ccb, 1);
-                               }
-                               break;
-
-                               case ARCMSR_DEV_ABORTED:
-
-                               case ARCMSR_DEV_INIT_FAIL: {
-                                               acb->devstate[id][lun] =
-                                                               ARECA_RAID_GONE;
-                                               ccb->pcmd->result =
-                                                       DID_BAD_TARGET << 16;
-                                               arcmsr_ccb_complete(ccb, 1);
-                               }
-                               break;
-
-                               case ARCMSR_DEV_CHECK_CONDITION: {
-                                               acb->devstate[id][lun] =
-                                                               ARECA_RAID_GOOD;
-                                               arcmsr_report_sense_info(ccb);
-                                               arcmsr_ccb_complete(ccb, 1);
-                               }
-                               break;
+                       struct Scsi_Host *host = pci_get_drvdata(pdev);
+                       struct AdapterControlBlock *acb = \
+                               (struct AdapterControlBlock *)host->hostdata;
 
-                               default:
-                                               printk(KERN_NOTICE "arcmsr%d: \
-                                                       scsi id = %d lun = %d"
-                                                               " polling and \
-                                               getting command error done"
-                                                               "but got unknown \
-                                                DeviceStatus = 0x%x \n"
-                                                               , acb->host->host_no,
-                                       id, lun, ccb->arcmsr_cdb.DeviceStatus);
-                                                       acb->devstate[id][lun] =
-                                                               ARECA_RAID_GONE;
-                                                       ccb->pcmd->result =
-                                                       DID_BAD_TARGET << 16;
-                                                       arcmsr_ccb_complete(ccb, 1);
-                               break;
-                               }
-                       }
-                       found = 1;
-               }
-       }
-       if (found){
-               outbound_intstatus = readl(&reg->outbound_intstatus) &
-                                               acb->outbound_int_enable;
-               writel(outbound_intstatus, &reg->outbound_intstatus);
-               /*clear interrupt*/
-       }
-       return;
+                       arcmsr_stop_adapter_bgrb(acb);
+                       arcmsr_flush_adapter_cache(acb);
 }
 
 static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
@@ -1840,5 +2315,6 @@ static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
                        break;
        default:
                        return PCI_ERS_RESULT_NEED_RESET;
-       }
+         }
 }
+#endif
index 03dbe60c264aa5c4490654a9c528f59766b5faab..52d0b87e9aa48f06cabb7c86ea6fff4b9b23ede0 100644 (file)
@@ -2041,7 +2041,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                sink = 1;
                                do_abort(instance);
                                cmd->result = DID_ERROR << 16;
-                               cmd->done(cmd);
+                               cmd->scsi_done(cmd);
                                return;
 #endif
                        case PHASE_DATAIN:
@@ -2100,7 +2100,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                sink = 1;
                                                do_abort(instance);
                                                cmd->result = DID_ERROR << 16;
-                                               cmd->done(cmd);
+                                               cmd->scsi_done(cmd);
                                                /* XXX - need to source or sink data here, as appropriate */
                                        } else {
 #ifdef REAL_DMA
@@ -2235,24 +2235,17 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
 
 #ifdef AUTOSENSE
+                                       if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+                                               hostdata->ses.cmd_len) {
+                                               scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+                                               hostdata->ses.cmd_len = 0 ;
+                                       }
+
                                        if ((cmd->cmnd[0] != REQUEST_SENSE) &&
                                            (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+                                               scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+
                                                ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
-                                               cmd->cmnd[0] = REQUEST_SENSE;
-                                               cmd->cmnd[1] &= 0xe0;
-                                               cmd->cmnd[2] = 0;
-                                               cmd->cmnd[3] = 0;
-                                               cmd->cmnd[4] = sizeof(cmd->sense_buffer);
-                                               cmd->cmnd[5] = 0;
-                                               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
-                                               cmd->use_sg = 0;
-                                               /* this is initialized from initialize_SCp
-                                               cmd->SCp.buffer = NULL;
-                                               cmd->SCp.buffers_residual = 0;
-                                               */
-                                               cmd->request_buffer = (char *) cmd->sense_buffer;
-                                               cmd->request_bufflen = sizeof(cmd->sense_buffer);
 
                                                local_irq_save(flags);
                                                LIST(cmd,hostdata->issue_queue);
index cac354086737e9b937062dab6e026a52c9289614..d858f3d412744583d320202ac44bbb12bd6cece5 100644 (file)
@@ -36,19 +36,18 @@ static struct platform_device *bvme6000_scsi_device;
 static __devinit int
 bvme6000_probe(struct device *dev)
 {
-       struct Scsi_Host * host = NULL;
+       struct Scsi_Host *host;
        struct NCR_700_Host_Parameters *hostdata;
 
        if (!MACH_IS_BVME6000)
                goto out;
 
-       hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
-       if (hostdata == NULL) {
+       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+       if (!hostdata) {
                printk(KERN_ERR "bvme6000-scsi: "
                                "Failed to allocate host data\n");
                goto out;
        }
-       memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
        /* Fill in the required pieces of hostdata */
        hostdata->base = (void __iomem *)BVME_NCR53C710_BASE;
index 2a458d66b6ffc7245255a060e95955c4fb00cd0f..024553f9c247c669ab4769aef2ee5ef0c58c361e 100644 (file)
@@ -1235,7 +1235,21 @@ scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
 }
 EXPORT_SYMBOL(scsi_print_sense_hdr);
 
+/*
+ * Print normalized SCSI sense header with device information and a prefix.
+ */
 void
+scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc,
+                         struct scsi_sense_hdr *sshdr)
+{
+       scmd_printk(KERN_INFO, scmd, "%s: ", desc);
+       scsi_show_sense_hdr(sshdr);
+       scmd_printk(KERN_INFO, scmd, "%s: ", desc);
+       scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
+EXPORT_SYMBOL(scsi_cmd_print_sense_hdr);
+
+static void
 scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
                       struct scsi_sense_hdr *sshdr)
 {
@@ -1258,7 +1272,7 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
        }
 }
 
-void
+static void
 scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
                         struct scsi_sense_hdr *sshdr)
 {
index 7b8a3457b6962c78734811fa918978aed2c9b07a..1591824cf4b3b7ed6c8c01202426b717032590e9 100644 (file)
@@ -778,7 +778,7 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb)
 {
        dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n",
-               srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+               srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
        list_add(&srb->list, &dcb->srb_waiting_list);
 }
 
@@ -787,7 +787,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb)
 {
        dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n",
-                srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+                srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
        list_add_tail(&srb->list, &dcb->srb_waiting_list);
 }
 
@@ -795,7 +795,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb,
 static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
 {
        dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n",
-               srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+               srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
        list_add_tail(&srb->list, &dcb->srb_going_list);
 }
 
@@ -805,7 +805,7 @@ static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
        struct ScsiReqBlk *i;
        struct ScsiReqBlk *tmp;
        dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n",
-               srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+               srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
 
        list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
                if (i == srb) {
@@ -821,7 +821,7 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
        struct ScsiReqBlk *i;
        struct ScsiReqBlk *tmp;
        dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n",
-               srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+               srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
 
        list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
                if (i == srb) {
@@ -836,7 +836,7 @@ static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
 {
        dprintkdbg(DBG_0,
                "srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n",
-               srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+               srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
        list_move(&srb->list, &dcb->srb_waiting_list);
 }
 
@@ -846,7 +846,7 @@ static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
 {
        dprintkdbg(DBG_0,
                "srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n",
-               srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+               srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
        list_move(&srb->list, &dcb->srb_going_list);
 }
 
@@ -982,7 +982,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
        int nseg;
        enum dma_data_direction dir = cmd->sc_data_direction;
        dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
-               cmd->pid, dcb->target_id, dcb->target_lun);
+               cmd->serial_number, dcb->target_id, dcb->target_lun);
 
        srb->dcb = dcb;
        srb->cmd = cmd;
@@ -1086,7 +1086,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_
        struct AdapterCtlBlk *acb =
            (struct AdapterCtlBlk *)cmd->device->host->hostdata;
        dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n",
-               cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+               cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
 
        /* Assume BAD_TARGET; will be cleared later */
        cmd->result = DID_BAD_TARGET << 16;
@@ -1139,7 +1139,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_
                /* process immediately */
                send_srb(acb, srb);
        }
-       dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid);
+       dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->serial_number);
        return 0;
 
 complete:
@@ -1203,7 +1203,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
                else
                        dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) "
                                 "cmnd=0x%02x <%02i-%i>\n",
-                               srb, srb->cmd, srb->cmd->pid,
+                               srb, srb->cmd, srb->cmd->serial_number,
                                srb->cmd->cmnd[0], srb->cmd->device->id,
                                srb->cmd->device->lun);
                printk("  sglist=%p cnt=%i idx=%i len=%zu\n",
@@ -1300,7 +1300,7 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
                (struct AdapterCtlBlk *)cmd->device->host->hostdata;
        dprintkl(KERN_INFO,
                "eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n",
-               cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+               cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
 
        if (timer_pending(&acb->waiting_timer))
                del_timer(&acb->waiting_timer);
@@ -1367,7 +1367,7 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
        struct DeviceCtlBlk *dcb;
        struct ScsiReqBlk *srb;
        dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n",
-               cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+               cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
 
        dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
        if (!dcb) {
@@ -1494,7 +1494,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
        u8 s_stat, scsicommand, i, identify_message;
        u8 *ptr;
        dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n",
-               srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+               srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
 
        srb->tag_number = TAG_NONE;     /* acb->tag_max_num: had error read in eeprom */
 
@@ -1504,7 +1504,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
 #if 1
        if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
                dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n",
-                       srb->cmd->pid, s_stat, s_stat2);
+                       srb->cmd->serial_number, s_stat, s_stat2);
                /*
                 * Try anyway?
                 *
@@ -1522,14 +1522,14 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
        if (acb->active_dcb) {
                dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a"
                        "command while another command (pid#%li) is active.",
-                       srb->cmd->pid,
+                       srb->cmd->serial_number,
                        acb->active_dcb->active_srb ?
-                           acb->active_dcb->active_srb->cmd->pid : 0);
+                           acb->active_dcb->active_srb->cmd->serial_number : 0);
                return 1;
        }
        if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
                dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n",
-                       srb->cmd->pid);
+                       srb->cmd->serial_number);
                return 1;
        }
        /* Allow starting of SCSI commands half a second before we allow the mid-level
@@ -1603,7 +1603,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
                if (tag_number >= dcb->max_command) {
                        dprintkl(KERN_WARNING, "start_scsi: (pid#%li) "
                                "Out of tags target=<%02i-%i>)\n",
-                               srb->cmd->pid, srb->cmd->device->id,
+                               srb->cmd->serial_number, srb->cmd->device->id,
                                srb->cmd->device->lun);
                        srb->state = SRB_READY;
                        DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
@@ -1622,7 +1622,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
 /*polling:*/
        /* Send CDB ..command block ......... */
        dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
                srb->cmd->cmnd[0], srb->tag_number);
        if (srb->flag & AUTO_REQSENSE) {
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
@@ -1647,7 +1647,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
                 * : Let's process it first!
                 */
                dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n",
-                       srb->cmd->pid, dcb->target_id, dcb->target_lun);
+                       srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
                srb->state = SRB_READY;
                free_tag(dcb, srb);
                srb->msg_count = 0;
@@ -1842,7 +1842,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
 static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
-       dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid);
+       dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->serial_number);
        if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
                *pscsi_status = PH_BUS_FREE;    /*.. initial phase */
 
@@ -1856,18 +1856,18 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
 {
        u16 i;
        u8 *ptr;
-       dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid);
+       dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->serial_number);
 
        clear_fifo(acb, "msgout_phase1");
        if (!(srb->state & SRB_MSGOUT)) {
                srb->state |= SRB_MSGOUT;
                dprintkl(KERN_DEBUG,
                        "msgout_phase1: (pid#%li) Phase unexpected\n",
-                       srb->cmd->pid); /* So what ? */
+                       srb->cmd->serial_number);       /* So what ? */
        }
        if (!srb->msg_count) {
                dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n",
-                       srb->cmd->pid);
+                       srb->cmd->serial_number);
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP);
                DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);      /* it's important for atn stop */
                DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
@@ -1887,7 +1887,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
 static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
-       dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid);
+       dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->serial_number);
        DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
 }
 
@@ -1898,7 +1898,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
        struct DeviceCtlBlk *dcb;
        u8 *ptr;
        u16 i;
-       dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid);
+       dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->serial_number);
 
        clear_fifo(acb, "command_phase1");
        DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
@@ -2042,7 +2042,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
        u16 scsi_status = *pscsi_status;
        u32 d_left_counter = 0;
        dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
 
        /*
         * KG: We need to drain the buffers before we draw any conclusions!
@@ -2172,7 +2172,7 @@ static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
        dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
        clear_fifo(acb, "data_out_phase1");
        /* do prepare before transfer when data out phase */
        data_io_transfer(acb, srb, XFERDATAOUT);
@@ -2184,7 +2184,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
        u16 scsi_status = *pscsi_status;
 
        dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
 
        /*
         * KG: DataIn is much more tricky than DataOut. When the device is finished
@@ -2205,7 +2205,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
 
                if (scsi_status & PARITYERROR) {
                        dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
-                               "Parity Error\n", srb->cmd->pid);
+                               "Parity Error\n", srb->cmd->serial_number);
                        srb->status |= PARITY_ERROR;
                }
                /*
@@ -2395,7 +2395,7 @@ static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
        dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
        data_io_transfer(acb, srb, XFERDATAIN);
 }
 
@@ -2407,7 +2407,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
        u8 bval;
        dprintkdbg(DBG_0,
                "data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
                ((io_dir & DMACMD_DIR) ? 'r' : 'w'),
                srb->total_xfer_length, srb->sg_index, srb->sg_count);
        if (srb == acb->tmp_srb)
@@ -2580,7 +2580,7 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
        dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
        srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
        srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);      /* get message */
        srb->state = SRB_COMPLETED;
@@ -2594,7 +2594,7 @@ static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
        dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n",
-               srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+               srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
        srb->state = SRB_STATUS;
        DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);      /* it's important for atn stop */
        DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
@@ -2636,7 +2636,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
        struct ScsiReqBlk *srb = NULL;
        struct ScsiReqBlk *i;
        dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n",
-                  srb->cmd->pid, tag, srb);
+                  srb->cmd->serial_number, tag, srb);
 
        if (!(dcb->tag_mask & (1 << tag)))
                dprintkl(KERN_DEBUG,
@@ -2655,7 +2655,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
                goto mingx0;
 
        dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n",
-               srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun);
+               srb->cmd->serial_number, srb->dcb->target_id, srb->dcb->target_lun);
        if (dcb->flag & ABORT_DEV_) {
                /*srb->state = SRB_ABORT_SENT; */
                enable_msgout_abort(acb, srb);
@@ -2865,7 +2865,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
        struct DeviceCtlBlk *dcb = acb->active_dcb;
-       dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid);
+       dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->serial_number);
 
        srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
        if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
@@ -2933,7 +2933,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                         */
                        dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
                                "SAVE POINTER rem=%i Ignore\n",
-                               srb->cmd->pid, srb->total_xfer_length);
+                               srb->cmd->serial_number, srb->total_xfer_length);
                        break;
 
                case RESTORE_POINTERS:
@@ -2943,7 +2943,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                case ABORT:
                        dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
                                "<%02i-%i> ABORT msg\n",
-                               srb->cmd->pid, dcb->target_id,
+                               srb->cmd->serial_number, dcb->target_id,
                                dcb->target_lun);
                        dcb->flag |= ABORT_DEV_;
                        enable_msgout_abort(acb, srb);
@@ -2975,7 +2975,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
 static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                u16 *pscsi_status)
 {
-       dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid);
+       dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->serial_number);
        clear_fifo(acb, "msgin_phase1");
        DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
        if (!(srb->state & SRB_MSGIN)) {
@@ -3041,7 +3041,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
        }
        srb = dcb->active_srb;
        acb->active_dcb = NULL;
-       dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid);
+       dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->serial_number);
 
        srb->scsi_phase = PH_BUS_FREE;  /* initial phase */
        clear_fifo(acb, "disconnect");
@@ -3072,13 +3072,13 @@ static void disconnect(struct AdapterCtlBlk *acb)
                                srb->state = SRB_READY;
                                dprintkl(KERN_DEBUG,
                                        "disconnect: (pid#%li) Unexpected\n",
-                                       srb->cmd->pid);
+                                       srb->cmd->serial_number);
                                srb->target_status = SCSI_STAT_SEL_TIMEOUT;
                                goto disc1;
                        } else {
                                /* Normal selection timeout */
                                dprintkdbg(DBG_KG, "disconnect: (pid#%li) "
-                                       "<%02i-%i> SelTO\n", srb->cmd->pid,
+                                       "<%02i-%i> SelTO\n", srb->cmd->serial_number,
                                        dcb->target_id, dcb->target_lun);
                                if (srb->retry_count++ > DC395x_MAX_RETRIES
                                    || acb->scan_devices) {
@@ -3090,7 +3090,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
                                srb_going_to_waiting_move(dcb, srb);
                                dprintkdbg(DBG_KG,
                                        "disconnect: (pid#%li) Retry\n",
-                                       srb->cmd->pid);
+                                       srb->cmd->serial_number);
                                waiting_set_timer(acb, HZ / 20);
                        }
                } else if (srb->state & SRB_DISCONNECT) {
@@ -3144,7 +3144,7 @@ static void reselect(struct AdapterCtlBlk *acb)
                if (!acb->scan_devices) {
                        dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> "
                                "Arb lost but Resel win rsel=%i stat=0x%04x\n",
-                               srb->cmd->pid, dcb->target_id,
+                               srb->cmd->serial_number, dcb->target_id,
                                dcb->target_lun, rsel_tar_lun_id,
                                DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
                        arblostflag = 1;
@@ -3318,7 +3318,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
        enum dma_data_direction dir = cmd->sc_data_direction;
        int ckc_only = 1;
 
-       dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
+       dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->serial_number,
                srb->cmd->device->id, srb->cmd->device->lun);
        dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
                   srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
@@ -3499,7 +3499,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
                if (srb->total_xfer_length)
                        dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> "
                                "cmnd=0x%02x Missed %i bytes\n",
-                               cmd->pid, cmd->device->id, cmd->device->lun,
+                               cmd->serial_number, cmd->device->id, cmd->device->lun,
                                cmd->cmnd[0], srb->total_xfer_length);
        }
 
@@ -3509,7 +3509,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
                dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
        else {
                dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n",
-                       cmd->pid, cmd->result);
+                       cmd->serial_number, cmd->result);
                srb_free_insert(acb, srb);
        }
        pci_unmap_srb(acb, srb);
@@ -3538,7 +3538,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
                        p = srb->cmd;
                        dir = p->sc_data_direction;
                        result = MK_RES(0, did_flag, 0, 0);
-                       printk("G:%li(%02i-%i) ", p->pid,
+                       printk("G:%li(%02i-%i) ", p->serial_number,
                               p->device->id, p->device->lun);
                        srb_going_remove(dcb, srb);
                        free_tag(dcb, srb);
@@ -3568,7 +3568,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
                        p = srb->cmd;
 
                        result = MK_RES(0, did_flag, 0, 0);
-                       printk("W:%li<%02i-%i>", p->pid, p->device->id,
+                       printk("W:%li<%02i-%i>", p->serial_number, p->device->id,
                               p->device->lun);
                        srb_waiting_remove(dcb, srb);
                        srb_free_insert(acb, srb);
@@ -3678,7 +3678,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
 {
        struct scsi_cmnd *cmd = srb->cmd;
        dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n",
-               cmd->pid, cmd->device->id, cmd->device->lun);
+               cmd->serial_number, cmd->device->id, cmd->device->lun);
 
        srb->flag |= AUTO_REQSENSE;
        srb->adapter_status = 0;
@@ -3709,7 +3709,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
        if (start_scsi(acb, dcb, srb)) {        /* Should only happen, if sb. else grabs the bus */
                dprintkl(KERN_DEBUG,
                        "request_sense: (pid#%li) failed <%02i-%i>\n",
-                       srb->cmd->pid, dcb->target_id, dcb->target_lun);
+                       srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
                srb_going_to_waiting_move(dcb, srb);
                waiting_set_timer(acb, HZ / 100);
        }
@@ -4717,13 +4717,13 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
                                dcb->target_id, dcb->target_lun,
                                list_size(&dcb->srb_waiting_list));
                 list_for_each_entry(srb, &dcb->srb_waiting_list, list)
-                       SPRINTF(" %li", srb->cmd->pid);
+                       SPRINTF(" %li", srb->cmd->serial_number);
                if (!list_empty(&dcb->srb_going_list))
                        SPRINTF("\nDCB (%02i-%i): Going  : %i:",
                                dcb->target_id, dcb->target_lun,
                                list_size(&dcb->srb_going_list));
                list_for_each_entry(srb, &dcb->srb_going_list, list)
-                       SPRINTF(" %li", srb->cmd->pid);
+                       SPRINTF(" %li", srb->cmd->serial_number);
                if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
                        SPRINTF("\n");
        }
index 502732ac270ddcfa7cbecec1e282f9ff0c944c42..bea9d659af1549e0dd2e5a8cd1f996eb78d65c25 100644 (file)
@@ -949,16 +949,14 @@ static int adpt_install_hba(struct pci_dev* pDev)
        }
        
        // Allocate and zero the data structure
-       pHba = kmalloc(sizeof(adpt_hba), GFP_KERNEL);
-       if( pHba == NULL) {
-               if(msg_addr_virt != base_addr_virt){
+       pHba = kzalloc(sizeof(adpt_hba), GFP_KERNEL);
+       if (!pHba) {
+               if (msg_addr_virt != base_addr_virt)
                        iounmap(msg_addr_virt);
-               }
                iounmap(base_addr_virt);
                pci_release_regions(pDev);
                return -ENOMEM;
        }
-       memset(pHba, 0, sizeof(adpt_hba));
 
        mutex_lock(&adpt_configuration_lock);
 
@@ -2622,14 +2620,13 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
 
        msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
 
-       status = kmalloc(4,GFP_KERNEL|ADDR32);
-       if (status==NULL) {
+       status = kzalloc(4, GFP_KERNEL|ADDR32);
+       if (!status) {
                adpt_send_nop(pHba, m);
                printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
                        pHba->name);
                return -ENOMEM;
        }
-       memset(status, 0, 4);
 
        writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
        writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
@@ -2668,12 +2665,11 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
 
        kfree(pHba->reply_pool);
 
-       pHba->reply_pool = kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
-       if(!pHba->reply_pool){
-               printk(KERN_ERR"%s: Could not allocate reply pool\n",pHba->name);
-               return -1;
+       pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+       if (!pHba->reply_pool) {
+               printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
+               return -ENOMEM;
        }
-       memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
 
        ptr = pHba->reply_pool;
        for(i = 0; i < pHba->reply_fifo_size; i++) {
@@ -2884,12 +2880,11 @@ static int adpt_i2o_build_sys_table(void)
 
        kfree(sys_tbl);
 
-       sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
-       if(!sys_tbl) {
+       sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+       if (!sys_tbl) {
                printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");     
                return -ENOMEM;
        }
-       memset(sys_tbl, 0, sys_tbl_len);
 
        sys_tbl->num_entries = hba_count;
        sys_tbl->version = I2OVERSION;
@@ -3351,7 +3346,7 @@ static int __init adpt_init(void)
        return count > 0 ? 0 : -ENODEV;
 }
 
-static void __exit adpt_exit(void)
+static void adpt_exit(void)
 {
        while (hba_chain)
                adpt_release(hba_chain);
index 9d52e45c7d36170a47f6e7da98ee179093a28336..2596165096d37f73c0ebbda03fb27d8686beffad 100644 (file)
@@ -137,11 +137,9 @@ static struct override {
 #ifdef OVERRIDE
 [] __initdata = OVERRIDE;
 #else
-[4] __initdata = { {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}};
+[4] __initdata = {
+       { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }
+};
 #endif
 
 #define NO_OVERRIDES ARRAY_SIZE(overrides)
@@ -176,7 +174,7 @@ static const struct signature {
  * Inputs : str - unused, ints - array of integer parameters with ints[0]
  *     equal to the number of ints.
  *
-*/
+ */
 
 static void __init dtc_setup(char *str, int *ints)
 {
@@ -233,7 +231,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
                } else
                        for (; !addr && (current_base < NO_BASES); ++current_base) {
 #if (DTCDEBUG & DTCDEBUG_INIT)
-                               printk("scsi-dtc : probing address %08x\n", bases[current_base].address);
+                               printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
 #endif
                                if (bases[current_base].noauto)
                                        continue;
@@ -244,7 +242,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
                                        if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
                                                addr = bases[current_base].address;
 #if (DTCDEBUG & DTCDEBUG_INIT)
-                                               printk("scsi-dtc : detected board.\n");
+                                               printk(KERN_DEBUG "scsi-dtc : detected board.\n");
 #endif
                                                goto found;
                                        }
@@ -253,7 +251,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
                        }
 
 #if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
-               printk("scsi-dtc : base = %08x\n", addr);
+               printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
 #endif
 
                if (!addr)
index a83e9f150b97f4d0d798b5b2b1d6618c8c3dd2b4..ec2233114bc9b6bbaf74d9281e5d4e9b53376653 100644 (file)
@@ -1758,7 +1758,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
 
        if (SCpnt->host_scribble)
                panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
-                     ha->board_name, SCpnt->pid, SCpnt);
+                     ha->board_name, SCpnt->serial_number, SCpnt);
 
        /* i is the mailbox number, look for the first free mailbox
           starting from last_cp_used */
@@ -1792,7 +1792,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
 
        if (do_trace)
                scmd_printk(KERN_INFO, SCpnt,
-                       "qcomm, mbox %d, pid %ld.\n", i, SCpnt->pid);
+                       "qcomm, mbox %d, pid %ld.\n", i, SCpnt->serial_number);
 
        cpp->reqsen = 1;
        cpp->dispri = 1;
@@ -1825,7 +1825,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
                unmap_dma(i, ha);
                SCpnt->host_scribble = NULL;
                scmd_printk(KERN_INFO, SCpnt,
-                       "qcomm, pid %ld, adapter busy.\n", SCpnt->pid);
+                       "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number);
                return 1;
        }
 
@@ -1841,13 +1841,13 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
 
        if (SCarg->host_scribble == NULL) {
                scmd_printk(KERN_INFO, SCarg,
-                       "abort, pid %ld inactive.\n", SCarg->pid);
+                       "abort, pid %ld inactive.\n", SCarg->serial_number);
                return SUCCESS;
        }
 
        i = *(unsigned int *)SCarg->host_scribble;
        scmd_printk(KERN_WARNING, SCarg,
-               "abort, mbox %d, pid %ld.\n", i, SCarg->pid);
+               "abort, mbox %d, pid %ld.\n", i, SCarg->serial_number);
 
        if (i >= shost->can_queue)
                panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name);
@@ -1892,7 +1892,7 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
                SCarg->host_scribble = NULL;
                ha->cp_stat[i] = FREE;
                printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
-                      ha->board_name, i, SCarg->pid);
+                      ha->board_name, i, SCarg->serial_number);
                SCarg->scsi_done(SCarg);
                return SUCCESS;
        }
@@ -1909,12 +1909,12 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
        struct hostdata *ha = (struct hostdata *)shost->hostdata;
 
        scmd_printk(KERN_INFO, SCarg,
-               "reset, enter, pid %ld.\n", SCarg->pid);
+               "reset, enter, pid %ld.\n", SCarg->serial_number);
 
        spin_lock_irq(shost->host_lock);
 
        if (SCarg->host_scribble == NULL)
-               printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->pid);
+               printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->serial_number);
 
        if (ha->in_reset) {
                printk("%s: reset, exit, already in reset.\n", ha->board_name);
@@ -1954,13 +1954,13 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
                if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
                        ha->cp_stat[i] = ABORTING;
                        printk("%s: reset, mbox %d aborting, pid %ld.\n",
-                              ha->board_name, i, SCpnt->pid);
+                              ha->board_name, i, SCpnt->serial_number);
                }
 
                else {
                        ha->cp_stat[i] = IN_RESET;
                        printk("%s: reset, mbox %d in reset, pid %ld.\n",
-                              ha->board_name, i, SCpnt->pid);
+                              ha->board_name, i, SCpnt->serial_number);
                }
 
                if (SCpnt->host_scribble == NULL)
@@ -2015,7 +2015,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
 
                        printk
                            ("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
-                            ha->board_name, i, SCpnt->pid);
+                            ha->board_name, i, SCpnt->serial_number);
                }
 
                else if (ha->cp_stat[i] == ABORTING) {
@@ -2029,7 +2029,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
 
                        printk
                            ("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
-                            ha->board_name, i, SCpnt->pid);
+                            ha->board_name, i, SCpnt->serial_number);
                }
 
                else
@@ -2043,7 +2043,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
        do_trace = 0;
 
        if (arg_done)
-               printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->pid);
+               printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->serial_number);
        else
                printk("%s: reset, exit.\n", ha->board_name);
 
@@ -2182,7 +2182,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
                        cpp = &ha->cp[k];
                        SCpnt = cpp->SCpnt;
                        ll[n] = SCpnt->request->nr_sectors;
-                       pl[n] = SCpnt->pid;
+                       pl[n] = SCpnt->serial_number;
 
                        if (!n)
                                continue;
@@ -2230,7 +2230,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
                            "%s pid %ld mb %d fc %d nr %d sec %ld ns %ld"
                             " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
                             (ihdlr ? "ihdlr" : "qcomm"),
-                            SCpnt->pid, k, flushcount,
+                            SCpnt->serial_number, k, flushcount,
                             n_ready, SCpnt->request->sector,
                             SCpnt->request->nr_sectors, cursec, YESNO(s),
                             YESNO(r), YESNO(rev), YESNO(input_only),
@@ -2277,7 +2277,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec,
                            "%s, pid %ld, mbox %d, adapter"
                             " busy, will abort.\n",
                             (ihdlr ? "ihdlr" : "qcomm"),
-                            SCpnt->pid, k);
+                            SCpnt->serial_number, k);
                        ha->cp_stat[k] = ABORTING;
                        continue;
                }
@@ -2391,11 +2391,11 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
 
        if (SCpnt->host_scribble == NULL)
                panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name,
-                     i, SCpnt->pid, SCpnt);
+                     i, SCpnt->serial_number, SCpnt);
 
        if (*(unsigned int *)SCpnt->host_scribble != i)
                panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
-                     ha->board_name, i, SCpnt->pid,
+                     ha->board_name, i, SCpnt->serial_number,
                      *(unsigned int *)SCpnt->host_scribble);
 
        sync_dma(i, ha);
@@ -2445,12 +2445,12 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
                               "target_status 0x%x, sense key 0x%x.\n",
                               ha->board_name,
                               SCpnt->device->channel, SCpnt->device->id,
-                              SCpnt->device->lun, SCpnt->pid,
+                              SCpnt->device->lun, SCpnt->serial_number,
                               spp->target_status, SCpnt->sense_buffer[2]);
 
                ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0;
 
-               if (ha->last_retried_pid == SCpnt->pid)
+               if (ha->last_retried_pid == SCpnt->serial_number)
                        ha->retries = 0;
 
                break;
@@ -2485,7 +2485,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
 #endif
 
                        ha->retries++;
-                       ha->last_retried_pid = SCpnt->pid;
+                       ha->last_retried_pid = SCpnt->serial_number;
                } else
                        status = DID_ERROR << 16;
 
@@ -2516,7 +2516,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
                scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"
                       " pid %ld, reg 0x%x, count %d.\n",
                       i, spp->adapter_status, spp->target_status,
-                      SCpnt->pid, reg, ha->iocount);
+                      SCpnt->serial_number, reg, ha->iocount);
 
        unmap_dma(i, ha);
 
index f33ad01064a9d8b0f8696331bd6d90da1fbbef3a..96180bb47e4189c3fa8304df15fc52d520689915 100644 (file)
@@ -107,59 +107,44 @@ static struct scsi_host_template driver_template;
 static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
                              int length, int rw)
 {
-    static u8 buff[512];
-    int size, len = 0;
-    off_t begin = 0, pos = 0;
+       int len = 0;
+       off_t begin = 0, pos = 0;
 
-    if (rw)
-       return -ENOSYS;
-    if (offset == 0)
-       memset(buff, 0, sizeof(buff));
+       if (rw)
+               return -ENOSYS;
 
-    size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
+       len += sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
                   "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
-    len += size; pos = begin + len;
-    size = sprintf(buffer + len, "queued commands:     %10ld\n"
+       len += sprintf(buffer + len, "queued commands:     %10ld\n"
                   "processed interrupts:%10ld\n", queue_counter, int_counter);
-    len += size; pos = begin + len;
-    
-    size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+       len += sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
                   shost->host_no, SD(shost)->name);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "Firmware revision: v%s\n", 
+       len += sprintf(buffer + len, "Firmware revision: v%s\n",
                   SD(shost)->revision);
-    len += size;
-    pos = begin + len;
-    size = sprintf(buffer + len, "IO: PIO\n");
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "Host Bus: %s\n", 
+       len += sprintf(buffer + len, "IO: PIO\n");
+       len += sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
+       len += sprintf(buffer + len, "Host Bus: %s\n",
                   (SD(shost)->bustype == 'P')?"PCI ":
                   (SD(shost)->bustype == 'E')?"EISA":"ISA ");
     
-    len += size; 
-    pos = begin + len;
+       pos = begin + len;
     
-    if (pos < offset) {
-       len = 0;
-       begin = pos;
-    }
-    if (pos > offset + length)
-       goto stop_output;
+       if (pos < offset) {
+               len = 0;
+               begin = pos;
+       }
+       if (pos > offset + length)
+               goto stop_output;
     
- stop_output:
-    DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
-    *start=buffer+(offset-begin);   /* Start of wanted data */
-    len-=(offset-begin);            /* Start slop */
-    if(len>length)
-       len = length;               /* Ending slop */
-    DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+stop_output:
+       DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+       *start = buffer + (offset - begin);   /* Start of wanted data */
+       len -= (offset - begin);            /* Start slop */
+       if (len > length)
+               len = length;               /* Ending slop */
+       DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
     
-    return (len);     
+       return len;
 }
 
 static int eata_pio_release(struct Scsi_Host *sh)
@@ -390,7 +375,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
 
        DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
                "eata_pio_queue pid %ld, y %d\n",
-               cmd->pid, y));
+               cmd->serial_number, y));
 
        cmd->scsi_done = (void *) done;
 
@@ -435,10 +420,10 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
                cmd->result = DID_BUS_BUSY << 16;
                scmd_printk(KERN_NOTICE, cmd,
                        "eata_pio_queue pid %ld, HBA busy, "
-                       "returning DID_BUS_BUSY, done.\n", cmd->pid);
+                       "returning DID_BUS_BUSY, done.\n", cmd->serial_number);
                done(cmd);
                cp->status = FREE;
-               return (0);
+               return 0;
        }
        /* FIXME: timeout */
        while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
@@ -450,9 +435,9 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
 
        DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
                "Queued base %#.4lx pid: %ld "
-               "slot %d irq %d\n", sh->base, cmd->pid, y, sh->irq));
+               "slot %d irq %d\n", sh->base, cmd->serial_number, y, sh->irq));
 
-       return (0);
+       return 0;
 }
 
 static int eata_pio_abort(struct scsi_cmnd *cmd)
@@ -461,7 +446,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd)
 
        DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
                "eata_pio_abort called pid: %ld\n",
-               cmd->pid));
+               cmd->serial_number));
 
        while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY)
                if (--loop == 0) {
@@ -497,7 +482,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
 
        DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
                "eata_pio_reset called pid:%ld\n",
-               cmd->pid));
+               cmd->serial_number));
 
        spin_lock_irq(host->host_lock);
 
@@ -516,7 +501,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
 
                sp = HD(cmd)->ccb[x].cmd;
                HD(cmd)->ccb[x].status = RESET;
-               printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+               printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->serial_number);
 
                if (sp == NULL)
                        panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
@@ -589,23 +574,28 @@ static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned i
        cp.cp_cdb[5] = 0;
 
        if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
-               return (NULL);
-       while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+               return NULL;
+
+       while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+               cpu_relax();
+
        outsw(base + HA_RDATA, &cp, cplen);
        outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
        for (z = 0; z < cppadlen; z++)
                outw(0, base + HA_RDATA);
 
-       while (inb(base + HA_RSTATUS) & HA_SBUSY);
+       while (inb(base + HA_RSTATUS) & HA_SBUSY)
+               cpu_relax();
+
        if (inb(base + HA_RSTATUS) & HA_SERROR)
-               return (NULL);
+               return NULL;
        else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-               return (NULL);
+               return NULL;
        else {
                insw(base + HA_RDATA, &buff, 127);
                while (inb(base + HA_RSTATUS) & HA_SDRQ)
                        inw(base + HA_RDATA);
-               return (buff);
+               return buff;
        }
 }
 
index 95cf7b6cd6225043f7a13ef33939b118303cba1c..4ed3a529706615f0bd94d51399cb39b5ee8b79b0 100644 (file)
@@ -2138,7 +2138,7 @@ irqreturn_t scsi_esp_intr(int irq, void *dev_id)
 }
 EXPORT_SYMBOL(scsi_esp_intr);
 
-static void __devinit esp_get_revision(struct esp *esp)
+static void esp_get_revision(struct esp *esp)
 {
        u8 val;
 
@@ -2187,7 +2187,7 @@ static void __devinit esp_get_revision(struct esp *esp)
        }
 }
 
-static void __devinit esp_init_swstate(struct esp *esp)
+static void esp_init_swstate(struct esp *esp)
 {
        int i;
 
@@ -2233,7 +2233,7 @@ static void esp_bootup_reset(struct esp *esp)
        esp_read8(ESP_INTRPT);
 }
 
-static void __devinit esp_set_clock_params(struct esp *esp)
+static void esp_set_clock_params(struct esp *esp)
 {
        int fmhz;
        u8 ccf;
@@ -2306,7 +2306,7 @@ static const char *esp_chip_names[] = {
 
 static struct scsi_transport_template *esp_transport_template;
 
-int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
+int scsi_esp_register(struct esp *esp, struct device *dev)
 {
        static int instance;
        int err;
@@ -2346,7 +2346,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
 }
 EXPORT_SYMBOL(scsi_esp_register);
 
-void __devexit scsi_esp_unregister(struct esp *esp)
+void scsi_esp_unregister(struct esp *esp)
 {
        scsi_remove_host(esp->host);
 }
index 36169d597e9808b21d4d0203a958b3c171fe98f0..5d282e6a6ae1d14105492faea3934893d213d471 100644 (file)
@@ -387,7 +387,9 @@ static void __iomem *    bios_mem;
 static int               bios_major;
 static int               bios_minor;
 static int               PCI_bus;
+#ifdef CONFIG_PCI
 static struct pci_dev  *PCI_dev;
+#endif
 static int               Quantum;      /* Quantum board variant */
 static int               interrupt_level;
 static volatile int      in_command;
@@ -1764,6 +1766,7 @@ struct scsi_host_template fdomain_driver_template = {
 };
 
 #ifndef PCMCIA
+#ifdef CONFIG_PCI
 
 static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
        { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
@@ -1771,7 +1774,7 @@ static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
        { }
 };
 MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
-
+#endif
 #define driver_template fdomain_driver_template
 #include "scsi_module.c"
 
index 880f70d24e6511e9fe92d5db66abe27b8aab4487..607336f56d550b8a6d487d3c1a723877c7641b32 100644 (file)
@@ -556,7 +556,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 }
 #endif
 
-#if NCR53C400_PSEUDO_DMA
+#ifdef NCR53C400_PSEUDO_DMA
 
 /**
  *     NCR5380_pread           -       pseudo DMA read
index 55e4d2dc2bbe227ea62dcb730d7a50516e27f3c1..3ac080ee6e2f2785230259e595d39d806ebeed26 100644 (file)
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Linux kernel 2.4.x, 2.6.x supported                                  *
+ * Linux kernel 2.6.x supported                                                *
  *                                                                      *
- * $Log: gdth.c,v $
- * Revision 1.74  2006/04/10 13:44:47  achim
- * Community changes for 2.6.x
- * Kernel 2.2.x no longer supported
- * scsi_request interface removed, thanks to Christoph Hellwig
- *
- * Revision 1.73  2004/03/31 13:33:03  achim
- * Special command 0xfd implemented to detect 64-bit DMA support
- *
- * Revision 1.72  2004/03/17 08:56:04  achim
- * 64-bit DMA only enabled if FW >= x.43
- *
- * Revision 1.71  2004/03/05 15:51:29  achim
- * Screen service: separate message buffer, bugfixes
- *
- * Revision 1.70  2004/02/27 12:19:07  achim
- * Bugfix: Reset bit in config (0xfe) call removed
- *
- * Revision 1.69  2004/02/20 09:50:24  achim
- * Compatibility changes for kernels < 2.4.20
- * Bugfix screen service command size
- * pci_set_dma_mask() error handling added
- *
- * Revision 1.68  2004/02/19 15:46:54  achim
- * 64-bit DMA bugfixes
- * Drive size bugfix for drives > 1TB
- *
- * Revision 1.67  2004/01/14 13:11:57  achim
- * Tool access over /proc no longer supported
- * Bugfixes IOCTLs
- *
- * Revision 1.66  2003/12/19 15:04:06  achim
- * Bugfixes support for drives > 2TB
- *
- * Revision 1.65  2003/12/15 11:21:56  achim
- * 64-bit DMA support added
- * Support for drives > 2 TB implemented
- * Kernels 2.2.x, 2.4.x, 2.6.x supported
- *
- * Revision 1.64  2003/09/17 08:30:26  achim
- * EISA/ISA controller scan disabled
- * Command line switch probe_eisa_isa added
- *
- * Revision 1.63  2003/07/12 14:01:00  Daniele Bellucci <bellucda@tiscali.it>
- * Minor cleanups in gdth_ioctl.
- *
- * Revision 1.62  2003/02/27 15:01:59  achim
- * Dynamic DMA mapping implemented
- * New (character device) IOCTL interface added
- * Other controller related changes made
- *
- * Revision 1.61  2002/11/08 13:09:52  boji
- * Added support for XSCALE based RAID Controllers
- * Fixed SCREENSERVICE initialization in SMP cases
- * Added checks for gdth_polling before GDTH_HA_LOCK
- *
- * Revision 1.60  2002/02/05 09:35:22  achim
- * MODULE_LICENSE only if kernel >= 2.4.11
- *
- * Revision 1.59  2002/01/30 09:46:33  achim
- * Small changes
- *
- * Revision 1.58  2002/01/29 15:30:02  achim
- * Set default value of shared_access to Y
- * New status S_CACHE_RESERV for clustering added
- *
- * Revision 1.57  2001/08/21 11:16:35  achim
- * Bugfix free_irq()
- *
- * Revision 1.56  2001/08/09 11:19:39  achim
- * Scsi_Host_Template changes
- *
- * Revision 1.55  2001/08/09 10:11:28  achim
- * Command HOST_UNFREEZE_IO before cache service init.
- *
- * Revision 1.54  2001/07/20 13:48:12  achim
- * Expand: gdth_analyse_hdrive() removed
- *
- * Revision 1.53  2001/07/17 09:52:49  achim
- * Small OEM related change
- *
- * Revision 1.52  2001/06/19 15:06:20  achim
- * New host command GDT_UNFREEZE_IO added
- *
- * Revision 1.51  2001/05/22 06:42:37  achim
- * PCI: Subdevice ID added
- *
- * Revision 1.50  2001/05/17 13:42:16  achim
- * Support for Intel Storage RAID Controllers added
- *
- * Revision 1.50  2001/05/17 12:12:34  achim
- * Support for Intel Storage RAID Controllers added
- *
- * Revision 1.49  2001/03/15 15:07:17  achim
- * New __setup interface for boot command line options added
- *
- * Revision 1.48  2001/02/06 12:36:28  achim
- * Bugfix Cluster protocol
- *
- * Revision 1.47  2001/01/10 14:42:06  achim
- * New switch shared_access added
- *
- * Revision 1.46  2001/01/09 08:11:35  achim
- * gdth_command() removed
- * meaning of Scsi_Pointer members changed
- *
- * Revision 1.45  2000/11/16 12:02:24  achim
- * Changes for kernel 2.4
- *
- * Revision 1.44  2000/10/11 08:44:10  achim
- * Clustering changes: New flag media_changed added
- *
- * Revision 1.43  2000/09/20 12:59:01  achim
- * DPMEM remap functions for all PCI controller types implemented
- * Small changes for ia64 platform
- *
- * Revision 1.42  2000/07/20 09:04:50  achim
- * Small changes for kernel 2.4
- *
- * Revision 1.41  2000/07/04 14:11:11  achim
- * gdth_analyse_hdrive() added to rescan drives after online expansion
- *
- * Revision 1.40  2000/06/27 11:24:16  achim
- * Changes Clustering, Screenservice
- *
- * Revision 1.39  2000/06/15 13:09:04  achim
- * Changes for gdth_do_cmd()
- *
- * Revision 1.38  2000/06/15 12:08:43  achim
- * Bugfix gdth_sync_event(), service SCREENSERVICE
- * Data direction for command 0xc2 changed to DOU
- *
- * Revision 1.37  2000/05/25 13:50:10  achim
- * New driver parameter virt_ctr added
- *
- * Revision 1.36  2000/05/04 08:50:46  achim
- * Event buffer now in gdth_ha_str
- *
- * Revision 1.35  2000/03/03 10:44:08  achim
- * New event_string only valid for the RP controller family
- *
- * Revision 1.34  2000/03/02 14:55:29  achim
- * New mechanism for async. event handling implemented
- *
- * Revision 1.33  2000/02/21 15:37:37  achim
- * Bugfix Alpha platform + DPMEM above 4GB
- *
- * Revision 1.32  2000/02/14 16:17:37  achim
- * Bugfix sense_buffer[] + raw devices
- *
- * Revision 1.31  2000/02/10 10:29:00  achim
- * Delete sense_buffer[0], if command OK
- *
- * Revision 1.30  1999/11/02 13:42:39  achim
- * ARRAY_DRV_LIST2 implemented
- * Now 255 log. and 100 host drives supported
- *
- * Revision 1.29  1999/10/05 13:28:47  achim
- * GDT_CLUST_RESET added
- *
- * Revision 1.28  1999/08/12 13:44:54  achim
- * MOUNTALL removed
- * Cluster drives -> removeable drives
- *
- * Revision 1.27  1999/06/22 07:22:38  achim
- * Small changes
- *
- * Revision 1.26  1999/06/10 16:09:12  achim
- * Cluster Host Drive support: Bugfixes
- *
- * Revision 1.25  1999/06/01 16:03:56  achim
- * gdth_init_pci(): Manipulate config. space to start RP controller
- *
- * Revision 1.24  1999/05/26 11:53:06  achim
- * Cluster Host Drive support added
- *
- * Revision 1.23  1999/03/26 09:12:31  achim
- * Default value for hdr_channel set to 0
- *
- * Revision 1.22  1999/03/22 16:27:16  achim
- * Bugfix: gdth_store_event() must not be locked with GDTH_LOCK_HA()
- *
- * Revision 1.21  1999/03/16 13:40:34  achim
- * Problems with reserved drives solved
- * gdth_eh_bus_reset() implemented
- *
- * Revision 1.20  1999/03/10 09:08:13  achim
- * Bugfix: Corrections in gdth_direction_tab[] made
- * Bugfix: Increase command timeout (gdth_update_timeout()) NOT in gdth_putq()
- *
- * Revision 1.19  1999/03/05 14:38:16  achim
- * Bugfix: Heads/Sectors mapping for reserved devices possibly wrong
- * -> gdth_eval_mapping() implemented, changes in gdth_bios_param()
- * INIT_RETRIES set to 100s to avoid DEINIT-Timeout for controllers
- * with BIOS disabled and memory test set to Intensive
- * Enhanced /proc support
- *
- * Revision 1.18  1999/02/24 09:54:33  achim
- * Command line parameter hdr_channel implemented
- * Bugfix for EISA controllers + Linux 2.2.x
- *
- * Revision 1.17  1998/12/17 15:58:11  achim
- * Command line parameters implemented
- * Changes for Alpha platforms
- * PCI controller scan changed
- * SMP support improved (spin_lock_irqsave(),...)
- * New async. events, new scan/reserve commands included
- *
- * Revision 1.16  1998/09/28 16:08:46  achim
- * GDT_PCIMPR: DPMEM remapping, if required
- * mdelay() added
- *
- * Revision 1.15  1998/06/03 14:54:06  achim
- * gdth_delay(), gdth_flush() implemented
- * Bugfix: gdth_release() changed
- *
- * Revision 1.14  1998/05/22 10:01:17  achim
- * mj: pcibios_strerror() removed
- * Improved SMP support (if version >= 2.1.95)
- * gdth_halt(): halt_called flag added (if version < 2.1)
- *
- * Revision 1.13  1998/04/16 09:14:57  achim
- * Reserve drives (for raw service) implemented
- * New error handling code enabled
- * Get controller name from board_info() IOCTL
- * Final round of PCI device driver patches by Martin Mares
- *
- * Revision 1.12  1998/03/03 09:32:37  achim
- * Fibre channel controller support added
- *
- * Revision 1.11  1998/01/27 16:19:14  achim
- * SA_SHIRQ added
- * add_timer()/del_timer() instead of GDTH_TIMER
- * scsi_add_timer()/scsi_del_timer() instead of SCSI_TIMER
- * New error handling included
- *
- * Revision 1.10  1997/10/31 12:29:57  achim
- * Read heads/sectors from host drive
- *
- * Revision 1.9  1997/09/04 10:07:25  achim
- * IO-mapping with virt_to_bus(), gdth_readb(), gdth_writeb(), ...
- * register_reboot_notifier() to get a notify on shutown used
- *
- * Revision 1.8  1997/04/02 12:14:30  achim
- * Version 1.00 (see gdth.h), tested with kernel 2.0.29
- *
- * Revision 1.7  1997/03/12 13:33:37  achim
- * gdth_reset() changed, new async. events
- *
- * Revision 1.6  1997/03/04 14:01:11  achim
- * Shutdown routine gdth_halt() implemented
- *
- * Revision 1.5  1997/02/21 09:08:36  achim
- * New controller included (RP, RP1, RP2 series)
- * IOCTL interface implemented
- *
- * Revision 1.4  1996/07/05 12:48:55  achim
- * Function gdth_bios_param() implemented
- * New constant GDTH_MAXC_P_L inserted
- * GDT_WRITE_THR, GDT_EXT_INFO implemented
- * Function gdth_reset() changed
- *
- * Revision 1.3  1996/05/10 09:04:41  achim
- * Small changes for Linux 1.2.13
- *
- * Revision 1.2  1996/05/09 12:45:27  achim
- * Loadable module support implemented
- * /proc support corrections made
- *
- * Revision 1.1  1996/04/11 07:35:57  achim
- * Initial revision
- *
  ************************************************************************/
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * max_ids:x                    x - target ID count per channel (1..MAXID)
  * rescan:Y                     rescan all channels/IDs 
  * rescan:N                     use all devices found until now
- * virt_ctr:Y                   map every channel to a virtual controller 
- * virt_ctr:N                   use multi channel support 
  * hdr_channel:x                x - number of virtual bus for host drives
  * shared_access:Y              disable driver reserve/release protocol to 
  *                              access a shared resource from several nodes, 
  * force_dma32:N                use 64 bit DMA mode, if supported
  *
  * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
- *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
+ *                          max_ids:127,rescan:N,hdr_channel:0,
  *                          shared_access:Y,probe_eisa_isa:N,force_dma32:N".
  * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
  * 
  * '1' in place of 'Y' and '0' in place of 'N'.
  * 
  * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
- *           max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0 
+ *           max_ids=127 rescan=0 hdr_channel=0 shared_access=0
  *           probe_eisa_isa=0 force_dma32=0"
  * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
  */
 
 /* The meaning of the Scsi_Pointer members in this driver is as follows:
  * ptr:                     Chaining
- * this_residual:           Command priority
- * buffer:                  phys. DMA sense buffer 
- * dma_handle:              phys. DMA buffer (kernel >= 2.4.0)
- * buffers_residual:        Timeout value
- * Status:                  Command status (gdth_do_cmd()), DMA mem. mappings
- * Message:                 Additional info (gdth_do_cmd()), DMA direction
- * have_data_in:            Flag for gdth_wait_completion()
- * sent_command:            Opcode special command
- * phase:                   Service/parameter/return code special command
+ * this_residual:           gdth_bufflen
+ * buffer:                  gdth_sglist
+ * dma_handle:              unused
+ * buffers_residual:        gdth_sg_count
+ * Status:                  unused
+ * Message:                 unused
+ * have_data_in:            unused
+ * sent_command:            unused
+ * phase:                   unused
  */
 
 
 #include <linux/proc_fs.h>
 #include <linux/time.h>
 #include <linux/timer.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)
 #include <linux/dma-mapping.h>
-#else
-#define DMA_32BIT_MASK 0x00000000ffffffffULL
-#define DMA_64BIT_MASK 0xffffffffffffffffULL
-#endif
+#include <linux/list.h>
 
 #ifdef GDTH_RTC
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/spinlock.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <linux/blkdev.h>
-#else
-#include <linux/blk.h>
-#include "sd.h"
-#endif
+#include <linux/scatterlist.h>
 
 #include "scsi.h"
 #include <scsi/scsi_host.h>
-#include "gdth_kcompat.h"
 #include "gdth.h"
 
 static void gdth_delay(int milliseconds);
 static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
 static irqreturn_t gdth_interrupt(int irq, void *dev_id);
-static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
-static int gdth_async_event(int hanum);
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+                                    int gdth_from_wait, int* pIndex);
+static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+                                                               Scsi_Cmnd *scp);
+static int gdth_async_event(gdth_ha_str *ha);
 static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
 
-static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
-static void gdth_next(int hanum);
-static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
-static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp);
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority);
+static void gdth_next(gdth_ha_str *ha);
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b);
+static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
 static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source,
                                       ushort idx, gdth_evt_data *evt);
 static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr);
@@ -439,42 +159,34 @@ static void gdth_readapp_event(gdth_ha_str *ha, unchar application,
                                gdth_evt_str *estr);
 static void gdth_clear_events(void);
 
-static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
-                                    char *buffer,ushort count);
-static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp);
-static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
+static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
+                                    char *buffer, ushort count, int to_buffer);
+static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
 
-static int gdth_search_eisa(ushort eisa_adr);
-static int gdth_search_isa(ulong32 bios_adr);
-static int gdth_search_pci(gdth_pci_str *pcistr);
-static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, 
-                            ushort vendor, ushort dev);
-static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt);
-static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha);
-static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha);
-static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha);
-
-static void gdth_enable_int(int hanum);
-static int gdth_get_status(unchar *pIStatus,int irq);
-static int gdth_test_busy(int hanum);
-static int gdth_get_cmd_index(int hanum);
-static void gdth_release_event(int hanum);
-static int gdth_wait(int hanum,int index,ulong32 time);
-static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
-                             ulong64 p2,ulong64 p3);
-static int gdth_search_drives(int hanum);
-static int gdth_analyse_hdrive(int hanum, ushort hdrive);
-
-static const char *gdth_ctr_name(int hanum);
+static void gdth_enable_int(gdth_ha_str *ha);
+static unchar gdth_get_status(gdth_ha_str *ha, int irq);
+static int gdth_test_busy(gdth_ha_str *ha);
+static int gdth_get_cmd_index(gdth_ha_str *ha);
+static void gdth_release_event(gdth_ha_str *ha);
+static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time);
+static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
+                                             ulong32 p1, ulong64 p2,ulong64 p3);
+static int gdth_search_drives(gdth_ha_str *ha);
+static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive);
+
+static const char *gdth_ctr_name(gdth_ha_str *ha);
 
 static int gdth_open(struct inode *inode, struct file *filep);
 static int gdth_close(struct inode *inode, struct file *filep);
 static int gdth_ioctl(struct inode *inode, struct file *filep,
                       unsigned int cmd, unsigned long arg);
 
-static void gdth_flush(int hanum);
+static void gdth_flush(gdth_ha_str *ha);
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
 static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
+static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
+                               struct gdth_cmndinfo *cmndinfo);
 static void gdth_scsi_done(struct scsi_cmnd *scp);
 
 #ifdef DEBUG_GDTH
@@ -571,29 +283,17 @@ static struct timer_list gdth_timer;
 #define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)
 #define INDEX_OK(i,t)   ((i)<ARRAY_SIZE(t))
 
-#define NUMDATA(a)      ( (gdth_num_str  *)((a)->hostdata))
-#define HADATA(a)       (&((gdth_ext_str *)((a)->hostdata))->haext)
-#define CMDDATA(a)      (&((gdth_ext_str *)((a)->hostdata))->cmdext)
-
 #define BUS_L2P(a,b)    ((b)>(a)->virt_bus ? (b-1):(b))
 
-#define gdth_readb(addr)        readb(addr)
-#define gdth_readw(addr)        readw(addr)
-#define gdth_readl(addr)        readl(addr)
-#define gdth_writeb(b,addr)     writeb((b),(addr))
-#define gdth_writew(b,addr)     writew((b),(addr))
-#define gdth_writel(b,addr)     writel((b),(addr))
-
+#ifdef CONFIG_ISA
 static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
+#endif
+#if defined(CONFIG_EISA) || defined(CONFIG_ISA)
 static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
+#endif
 static unchar   gdth_polling;                           /* polling if TRUE */
-static unchar   gdth_from_wait  = FALSE;                /* gdth_wait() */
-static int      wait_index,wait_hanum;                  /* gdth_wait() */
 static int      gdth_ctr_count  = 0;                    /* controller count */
-static int      gdth_ctr_vcount = 0;                    /* virt. ctr. count */
-static int      gdth_ctr_released = 0;                  /* gdth_release() */
-static struct Scsi_Host *gdth_ctr_tab[MAXHA];           /* controller table */
-static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS];   /* virt. ctr. table */
+static LIST_HEAD(gdth_instances);                       /* controller list */
 static unchar   gdth_write_through = FALSE;             /* write through */
 static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */
 static int elastidx;
@@ -645,8 +345,6 @@ static int hdr_channel = 0;
 static int max_ids = MAXID;
 /* rescan all IDs */
 static int rescan = 0;
-/* map channels to virtual controllers */
-static int virt_ctr = 0;
 /* shared access */
 static int shared_access = 1;
 /* enable support for EISA and ISA controllers */
@@ -655,7 +353,6 @@ static int probe_eisa_isa = 0;
 static int force_dma32 = 0;
 
 /* parameters for modprobe/insmod */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
 module_param_array(irq, int, NULL, 0);
 module_param(disable, int, 0);
 module_param(reserve_mode, int, 0);
@@ -664,24 +361,9 @@ module_param(reverse_scan, int, 0);
 module_param(hdr_channel, int, 0);
 module_param(max_ids, int, 0);
 module_param(rescan, int, 0);
-module_param(virt_ctr, int, 0);
 module_param(shared_access, int, 0);
 module_param(probe_eisa_isa, int, 0);
 module_param(force_dma32, int, 0);
-#else
-MODULE_PARM(irq, "i");
-MODULE_PARM(disable, "i");
-MODULE_PARM(reserve_mode, "i");
-MODULE_PARM(reserve_list, "4-" __MODULE_STRING(MAX_RES_ARGS) "i");
-MODULE_PARM(reverse_scan, "i");
-MODULE_PARM(hdr_channel, "i");
-MODULE_PARM(max_ids, "i");
-MODULE_PARM(rescan, "i");
-MODULE_PARM(virt_ctr, "i");
-MODULE_PARM(shared_access, "i");
-MODULE_PARM(probe_eisa_isa, "i");
-MODULE_PARM(force_dma32, "i");
-#endif
 MODULE_AUTHOR("Achim Leubner");
 MODULE_LICENSE("GPL");
 
@@ -692,6 +374,47 @@ static const struct file_operations gdth_fops = {
     .release = gdth_close,
 };
 
+/*
+ * gdth scsi_command access wrappers.
+ *   below 6 functions are used throughout the driver to access scsi_command's
+ *   io parameters. The reason we do not use the regular accessors from
+ *   scsi_cmnd.h is because of gdth_execute(). Since it is unrecommended for
+ *   llds to directly set scsi_cmnd's IO members. This driver will use SCp
+ *   members for IO parameters, and will copy scsi_cmnd's members to Scp
+ *   members in queuecommand. For internal commands through gdth_execute()
+ *   SCp's members will be set directly.
+ */
+static inline unsigned gdth_bufflen(struct scsi_cmnd *cmd)
+{
+       return (unsigned)cmd->SCp.this_residual;
+}
+
+static inline void gdth_set_bufflen(struct scsi_cmnd *cmd, unsigned bufflen)
+{
+       cmd->SCp.this_residual = bufflen;
+}
+
+static inline unsigned gdth_sg_count(struct scsi_cmnd *cmd)
+{
+       return (unsigned)cmd->SCp.buffers_residual;
+}
+
+static inline void gdth_set_sg_count(struct scsi_cmnd *cmd, unsigned sg_count)
+{
+       cmd->SCp.buffers_residual = sg_count;
+}
+
+static inline struct scatterlist *gdth_sglist(struct scsi_cmnd *cmd)
+{
+       return cmd->SCp.buffer;
+}
+
+static inline void gdth_set_sglist(struct scsi_cmnd *cmd,
+                                   struct scatterlist *sglist)
+{
+       cmd->SCp.buffer = sglist;
+}
+
 #include "gdth_proc.h"
 #include "gdth_proc.c"
 
@@ -701,6 +424,45 @@ static struct notifier_block gdth_notifier = {
 };
 static int notifier_disabled = 0;
 
+static gdth_ha_str *gdth_find_ha(int hanum)
+{
+       gdth_ha_str *ha;
+
+       list_for_each_entry(ha, &gdth_instances, list)
+               if (hanum == ha->hanum)
+                       return ha;
+
+       return NULL;
+}
+
+static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha)
+{
+       struct gdth_cmndinfo *priv = NULL;
+       ulong flags;
+       int i;
+
+       spin_lock_irqsave(&ha->smp_lock, flags);
+
+       for (i=0; i<GDTH_MAXCMDS; ++i) {
+               if (ha->cmndinfo[i].index == 0) {
+                       priv = &ha->cmndinfo[i];
+                       priv->index = i+1;
+                       memset(priv, 0, sizeof(*priv));
+                       break;
+               }
+       }
+
+       spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+       return priv;
+}
+
+static void gdth_put_cmndinfo(struct gdth_cmndinfo *priv)
+{
+       BUG_ON(!priv);
+       priv->index = 0;
+}
+
 static void gdth_delay(int milliseconds)
 {
     if (milliseconds == 0) {
@@ -710,80 +472,62 @@ static void gdth_delay(int milliseconds)
     }
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static void gdth_scsi_done(struct scsi_cmnd *scp)
 {
-    TRACE2(("gdth_scsi_done()\n"));
+       struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+       int internal_command = cmndinfo->internal_command;
+
+       TRACE2(("gdth_scsi_done()\n"));
 
-    if (scp->request)
-        complete((struct completion *)scp->request);
+       gdth_put_cmndinfo(cmndinfo);
+       scp->host_scribble = NULL;
+
+       if (internal_command)
+               complete((struct completion *)scp->request);
+       else
+               scp->scsi_done(scp);
 }
 
 int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
                    int timeout, u32 *info)
 {
+    gdth_ha_str *ha = shost_priv(sdev->host);
     Scsi_Cmnd *scp;
+    struct gdth_cmndinfo cmndinfo;
+    struct scatterlist one_sg;
     DECLARE_COMPLETION_ONSTACK(wait);
     int rval;
 
-    scp = kmalloc(sizeof(*scp), GFP_KERNEL);
+    scp = kzalloc(sizeof(*scp), GFP_KERNEL);
     if (!scp)
         return -ENOMEM;
-    memset(scp, 0, sizeof(*scp));
+
     scp->device = sdev;
+    memset(&cmndinfo, 0, sizeof(cmndinfo));
+
     /* use request field to save the ptr. to completion struct. */
     scp->request = (struct request *)&wait;
     scp->timeout_per_command = timeout*HZ;
-    scp->request_buffer = gdtcmd;
+    sg_init_one(&one_sg, gdtcmd, sizeof(*gdtcmd));
+    gdth_set_sglist(scp, &one_sg);
+    gdth_set_sg_count(scp, 1);
+    gdth_set_bufflen(scp, sizeof(*gdtcmd));
     scp->cmd_len = 12;
     memcpy(scp->cmnd, cmnd, 12);
-    scp->SCp.this_residual = IOCTL_PRI;   /* priority */
-    scp->done = gdth_scsi_done; /* some fn. test this */
-    gdth_queuecommand(scp, gdth_scsi_done);
-    wait_for_completion(&wait);
-
-    rval = scp->SCp.Status;
-    if (info)
-        *info = scp->SCp.Message;
-    kfree(scp);
-    return rval;
-}
-#else
-static void gdth_scsi_done(Scsi_Cmnd *scp)
-{
-    TRACE2(("gdth_scsi_done()\n"));
-
-    scp->request.rq_status = RQ_SCSI_DONE;
-    if (scp->request.waiting)
-        complete(scp->request.waiting);
-}
+    cmndinfo.priority = IOCTL_PRI;
+    cmndinfo.internal_command = 1;
 
-int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
-                   int timeout, u32 *info)
-{
-    Scsi_Cmnd *scp = scsi_allocate_device(sdev, 1, FALSE);
-    unsigned bufflen = gdtcmd ? sizeof(gdth_cmd_str) : 0;
-    DECLARE_COMPLETION_ONSTACK(wait);
-    int rval;
+    TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0]));
+    __gdth_queuecommand(ha, scp, &cmndinfo);
 
-    if (!scp)
-        return -ENOMEM;
-    scp->cmd_len = 12;
-    scp->use_sg = 0;
-    scp->SCp.this_residual = IOCTL_PRI;   /* priority */
-    scp->request.rq_status = RQ_SCSI_BUSY;
-    scp->request.waiting = &wait;
-    scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
     wait_for_completion(&wait);
 
-    rval = scp->SCp.Status;
+    rval = cmndinfo.status;
     if (info)
-        *info = scp->SCp.Message;
-
-    scsi_release_command(scp);
+        *info = cmndinfo.info;
+    kfree(scp);
     return rval;
 }
-#endif
 
 int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
                  int timeout, u32 *info)
@@ -815,7 +559,7 @@ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs
 }
 
 /* controller search and initialization functions */
-
+#ifdef CONFIG_EISA
 static int __init gdth_search_eisa(ushort eisa_adr)
 {
     ulong32 id;
@@ -832,8 +576,9 @@ static int __init gdth_search_eisa(ushort eisa_adr)
 
     return 0;                                   
 }
+#endif /* CONFIG_EISA */
 
-
+#ifdef CONFIG_ISA
 static int __init gdth_search_isa(ulong32 bios_adr)
 {
     void __iomem *addr;
@@ -841,14 +586,18 @@ static int __init gdth_search_isa(ulong32 bios_adr)
 
     TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
     if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
-        id = gdth_readl(addr);
+        id = readl(addr);
         iounmap(addr);
         if (id == GDT2_ID)                          /* GDT2000 */
             return 1;
     }
     return 0;
 }
+#endif /* CONFIG_ISA */
 
+#ifdef CONFIG_PCI
+static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
+                            ushort vendor, ushort dev);
 
 static int __init gdth_search_pci(gdth_pci_str *pcistr)
 {
@@ -928,7 +677,6 @@ static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
     }       
 }   
 
-
 static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
 {    
     gdth_pci_str temp;
@@ -965,8 +713,9 @@ static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
         }
     } while (changed);
 }
+#endif /* CONFIG_PCI */
 
-
+#ifdef CONFIG_EISA
 static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
 {
     ulong32 retries,id;
@@ -1058,8 +807,9 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
     ha->dma64_support = 0;
     return 1;
 }
+#endif /* CONFIG_EISA */
 
-       
+#ifdef CONFIG_ISA
 static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
 {
     register gdt2_dpram_str __iomem *dp2_ptr;
@@ -1075,22 +825,22 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
         return 0;
     }
     dp2_ptr = ha->brd;
-    gdth_writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
+    writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
     /* reset interface area */
     memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u));
-    if (gdth_readl(&dp2_ptr->u) != 0) {
+    if (readl(&dp2_ptr->u) != 0) {
         printk("GDT-ISA: Initialization error (DPMEM write error)\n");
         iounmap(ha->brd);
         return 0;
     }
 
     /* disable board interrupts, read DRQ and IRQ */
-    gdth_writeb(0xff, &dp2_ptr->io.irqdel);
-    gdth_writeb(0x00, &dp2_ptr->io.irqen);
-    gdth_writeb(0x00, &dp2_ptr->u.ic.S_Status);
-    gdth_writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
+    writeb(0xff, &dp2_ptr->io.irqdel);
+    writeb(0x00, &dp2_ptr->io.irqen);
+    writeb(0x00, &dp2_ptr->u.ic.S_Status);
+    writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
 
-    irq_drq = gdth_readb(&dp2_ptr->io.rq);
+    irq_drq = readb(&dp2_ptr->io.rq);
     for (i=0; i<3; ++i) {
         if ((irq_drq & 1)==0)
             break;
@@ -1098,7 +848,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
     }
     ha->drq = gdth_drq_tab[i];
 
-    irq_drq = gdth_readb(&dp2_ptr->io.rq) >> 3;
+    irq_drq = readb(&dp2_ptr->io.rq) >> 3;
     for (i=1; i<5; ++i) {
         if ((irq_drq & 1)==0)
             break;
@@ -1107,12 +857,12 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
     ha->irq = gdth_irq_tab[i];
 
     /* deinitialize services */
-    gdth_writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
-    gdth_writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
-    gdth_writeb(0, &dp2_ptr->io.event);
+    writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
+    writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
+    writeb(0, &dp2_ptr->io.event);
     retries = INIT_RETRIES;
     gdth_delay(20);
-    while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
+    while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error (DEINIT failed)\n");
             iounmap(ha->brd);
@@ -1120,9 +870,9 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
         }
         gdth_delay(1);
     }
-    prot_ver = (unchar)gdth_readl(&dp2_ptr->u.ic.S_Info[0]);
-    gdth_writeb(0, &dp2_ptr->u.ic.Status);
-    gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+    prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]);
+    writeb(0, &dp2_ptr->u.ic.Status);
+    writeb(0xff, &dp2_ptr->io.irqdel);
     if (prot_ver != PROTOCOL_VERSION) {
         printk("GDT-ISA: Illegal protocol version\n");
         iounmap(ha->brd);
@@ -1136,15 +886,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
     ha->brd_phys = bios_adr >> 4;
 
     /* special request to controller BIOS */
-    gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
-    gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
-    gdth_writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
-    gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
-    gdth_writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
-    gdth_writeb(0, &dp2_ptr->io.event);
+    writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
+    writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
+    writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
+    writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
+    writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
+    writeb(0, &dp2_ptr->io.event);
     retries = INIT_RETRIES;
     gdth_delay(20);
-    while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
+    while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error\n");
             iounmap(ha->brd);
@@ -1152,14 +902,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
         }
         gdth_delay(1);
     }
-    gdth_writeb(0, &dp2_ptr->u.ic.Status);
-    gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+    writeb(0, &dp2_ptr->u.ic.Status);
+    writeb(0xff, &dp2_ptr->io.irqdel);
 
     ha->dma64_support = 0;
     return 1;
 }
+#endif /* CONFIG_ISA */
 
-
+#ifdef CONFIG_PCI
 static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
 {
     register gdt6_dpram_str __iomem *dp6_ptr;
@@ -1190,8 +941,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
         }
         /* check and reset interface area */
         dp6_ptr = ha->brd;
-        gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
-        if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) {
+        writel(DPMEM_MAGIC, &dp6_ptr->u);
+        if (readl(&dp6_ptr->u) != DPMEM_MAGIC) {
             printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
                    pcistr->dpmem);
             found = FALSE;
@@ -1202,7 +953,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
                 }
-                if (gdth_readw(ha->brd) != 0xffff) {
+                if (readw(ha->brd) != 0xffff) {
                     TRACE2(("init_pci_old() address 0x%x busy\n", i));
                     continue;
                 }
@@ -1215,8 +966,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
                     return 0;
                 }
                 dp6_ptr = ha->brd;
-                gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
-                if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) {
+                writel(DPMEM_MAGIC, &dp6_ptr->u);
+                if (readl(&dp6_ptr->u) == DPMEM_MAGIC) {
                     printk("GDT-PCI: Use free address at 0x%x\n", i);
                     found = TRUE;
                     break;
@@ -1229,24 +980,24 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
         }
         memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u));
-        if (gdth_readl(&dp6_ptr->u) != 0) {
+        if (readl(&dp6_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
             iounmap(ha->brd);
             return 0;
         }
         
         /* disable board interrupts, deinit services */
-        gdth_writeb(0xff, &dp6_ptr->io.irqdel);
-        gdth_writeb(0x00, &dp6_ptr->io.irqen);
-        gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status);
-        gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
-
-        gdth_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
-        gdth_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
-        gdth_writeb(0, &dp6_ptr->io.event);
+        writeb(0xff, &dp6_ptr->io.irqdel);
+        writeb(0x00, &dp6_ptr->io.irqen);
+        writeb(0x00, &dp6_ptr->u.ic.S_Status);
+        writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
+
+        writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
+        writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
+        writeb(0, &dp6_ptr->io.event);
         retries = INIT_RETRIES;
         gdth_delay(20);
-        while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
+        while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                 iounmap(ha->brd);
@@ -1254,9 +1005,9 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
             gdth_delay(1);
         }
-        prot_ver = (unchar)gdth_readl(&dp6_ptr->u.ic.S_Info[0]);
-        gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
-        gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+        prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]);
+        writeb(0, &dp6_ptr->u.ic.S_Status);
+        writeb(0xff, &dp6_ptr->io.irqdel);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
             iounmap(ha->brd);
@@ -1267,15 +1018,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
         ha->ic_all_size = sizeof(dp6_ptr->u);
         
         /* special command to controller BIOS */
-        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
-        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
-        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
-        gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
-        gdth_writeb(0, &dp6_ptr->io.event);
+        writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
+        writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
+        writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
+        writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
+        writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
+        writeb(0, &dp6_ptr->io.event);
         retries = INIT_RETRIES;
         gdth_delay(20);
-        while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
+        while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
                 iounmap(ha->brd);
@@ -1283,8 +1034,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
             gdth_delay(1);
         }
-        gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
-        gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+        writeb(0, &dp6_ptr->u.ic.S_Status);
+        writeb(0xff, &dp6_ptr->io.irqdel);
 
         ha->dma64_support = 0;
 
@@ -1300,8 +1051,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
         }
         /* check and reset interface area */
         dp6c_ptr = ha->brd;
-        gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
-        if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
+        writel(DPMEM_MAGIC, &dp6c_ptr->u);
+        if (readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
             printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
                    pcistr->dpmem);
             found = FALSE;
@@ -1312,7 +1063,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
                 }
-                if (gdth_readw(ha->brd) != 0xffff) {
+                if (readw(ha->brd) != 0xffff) {
                     TRACE2(("init_pci_plx() address 0x%x busy\n", i));
                     continue;
                 }
@@ -1325,8 +1076,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
                     return 0;
                 }
                 dp6c_ptr = ha->brd;
-                gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
-                if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
+                writel(DPMEM_MAGIC, &dp6c_ptr->u);
+                if (readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
                     printk("GDT-PCI: Use free address at 0x%x\n", i);
                     found = TRUE;
                     break;
@@ -1339,7 +1090,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
         }
         memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u));
-        if (gdth_readl(&dp6c_ptr->u) != 0) {
+        if (readl(&dp6c_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
             iounmap(ha->brd);
             return 0;
@@ -1349,17 +1100,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
         outb(0x00,PTR2USHORT(&ha->plx->control1));
         outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
         
-        gdth_writeb(0x00, &dp6c_ptr->u.ic.S_Status);
-        gdth_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
+        writeb(0x00, &dp6c_ptr->u.ic.S_Status);
+        writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
 
-        gdth_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
-        gdth_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
+        writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
+        writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
 
         outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
 
         retries = INIT_RETRIES;
         gdth_delay(20);
-        while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
+        while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                 iounmap(ha->brd);
@@ -1367,8 +1118,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
             gdth_delay(1);
         }
-        prot_ver = (unchar)gdth_readl(&dp6c_ptr->u.ic.S_Info[0]);
-        gdth_writeb(0, &dp6c_ptr->u.ic.Status);
+        prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]);
+        writeb(0, &dp6c_ptr->u.ic.Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
             iounmap(ha->brd);
@@ -1379,17 +1130,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
         ha->ic_all_size = sizeof(dp6c_ptr->u);
 
         /* special command to controller BIOS */
-        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
-        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
-        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
-        gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
+        writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
+        writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
+        writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
+        writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
+        writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
         
         outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
 
         retries = INIT_RETRIES;
         gdth_delay(20);
-        while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
+        while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
                 iounmap(ha->brd);
@@ -1397,7 +1148,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
             gdth_delay(1);
         }
-        gdth_writeb(0, &dp6c_ptr->u.ic.S_Status);
+        writeb(0, &dp6c_ptr->u.ic.S_Status);
 
         ha->dma64_support = 0;
 
@@ -1425,12 +1176,12 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
 
         /* Ensure that it is safe to access the non HW portions of DPMEM.
          * Aditional check needed for Xscale based RAID controllers */
-        while( ((int)gdth_readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
+        while( ((int)readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
             gdth_delay(1);
         
         /* check and reset interface area */
-        gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
-        if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
+        writel(DPMEM_MAGIC, &dp6m_ptr->u);
+        if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
             printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
                    pcistr->dpmem);
             found = FALSE;
@@ -1441,7 +1192,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
                 }
-                if (gdth_readw(ha->brd) != 0xffff) {
+                if (readw(ha->brd) != 0xffff) {
                     TRACE2(("init_pci_mpr() address 0x%x busy\n", i));
                     continue;
                 }
@@ -1454,8 +1205,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
                     return 0;
                 }
                 dp6m_ptr = ha->brd;
-                gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
-                if (gdth_readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
+                writel(DPMEM_MAGIC, &dp6m_ptr->u);
+                if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
                     printk("GDT-PCI: Use free address at 0x%x\n", i);
                     found = TRUE;
                     break;
@@ -1470,18 +1221,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
         memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u));
         
         /* disable board interrupts, deinit services */
-        gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
+        writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
                     &dp6m_ptr->i960r.edoor_en_reg);
-        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
-        gdth_writeb(0x00, &dp6m_ptr->u.ic.S_Status);
-        gdth_writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
+        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        writeb(0x00, &dp6m_ptr->u.ic.S_Status);
+        writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
 
-        gdth_writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
-        gdth_writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
-        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
+        writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
         retries = INIT_RETRIES;
         gdth_delay(20);
-        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
+        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                 iounmap(ha->brd);
@@ -1489,8 +1240,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
             gdth_delay(1);
         }
-        prot_ver = (unchar)gdth_readl(&dp6m_ptr->u.ic.S_Info[0]);
-        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+        prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]);
+        writeb(0, &dp6m_ptr->u.ic.S_Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
             iounmap(ha->brd);
@@ -1501,15 +1252,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
         ha->ic_all_size = sizeof(dp6m_ptr->u);
         
         /* special command to controller BIOS */
-        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
-        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
-        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
-        gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
-        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
+        writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
+        writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
+        writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
+        writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
         retries = INIT_RETRIES;
         gdth_delay(20);
-        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
+        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
                 iounmap(ha->brd);
@@ -1517,14 +1268,14 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
             gdth_delay(1);
         }
-        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+        writeb(0, &dp6m_ptr->u.ic.S_Status);
 
         /* read FW version to detect 64-bit DMA support */
-        gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
-        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
         retries = INIT_RETRIES;
         gdth_delay(20);
-        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
+        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                 iounmap(ha->brd);
@@ -1532,8 +1283,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
             }
             gdth_delay(1);
         }
-        prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
-        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+        prot_ver = (unchar)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
+        writeb(0, &dp6m_ptr->u.ic.S_Status);
         if (prot_ver < 0x2b)      /* FW < x.43: no 64-bit DMA support */
             ha->dma64_support = 0;
         else 
@@ -1542,20 +1293,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
 
     return 1;
 }
-
+#endif /* CONFIG_PCI */
 
 /* controller protocol functions */
 
-static void __init gdth_enable_int(int hanum)
+static void __init gdth_enable_int(gdth_ha_str *ha)
 {
-    gdth_ha_str *ha;
     ulong flags;
     gdt2_dpram_str __iomem *dp2_ptr;
     gdt6_dpram_str __iomem *dp6_ptr;
     gdt6m_dpram_str __iomem *dp6m_ptr;
 
-    TRACE(("gdth_enable_int() hanum %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE(("gdth_enable_int() hanum %d\n",ha->hanum));
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     if (ha->type == GDT_EISA) {
@@ -1564,93 +1313,80 @@ static void __init gdth_enable_int(int hanum)
         outb(0x01, ha->bmic + EINTENABREG);
     } else if (ha->type == GDT_ISA) {
         dp2_ptr = ha->brd;
-        gdth_writeb(1, &dp2_ptr->io.irqdel);
-        gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);
-        gdth_writeb(1, &dp2_ptr->io.irqen);
+        writeb(1, &dp2_ptr->io.irqdel);
+        writeb(0, &dp2_ptr->u.ic.Cmd_Index);
+        writeb(1, &dp2_ptr->io.irqen);
     } else if (ha->type == GDT_PCI) {
         dp6_ptr = ha->brd;
-        gdth_writeb(1, &dp6_ptr->io.irqdel);
-        gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);
-        gdth_writeb(1, &dp6_ptr->io.irqen);
+        writeb(1, &dp6_ptr->io.irqdel);
+        writeb(0, &dp6_ptr->u.ic.Cmd_Index);
+        writeb(1, &dp6_ptr->io.irqen);
     } else if (ha->type == GDT_PCINEW) {
         outb(0xff, PTR2USHORT(&ha->plx->edoor_reg));
         outb(0x03, PTR2USHORT(&ha->plx->control1));
     } else if (ha->type == GDT_PCIMPR) {
         dp6m_ptr = ha->brd;
-        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
-        gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
+        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
                     &dp6m_ptr->i960r.edoor_en_reg);
     }
     spin_unlock_irqrestore(&ha->smp_lock, flags);
 }
 
-
-static int gdth_get_status(unchar *pIStatus,int irq)
+/* return IStatus if interrupt was from this card else 0 */
+static unchar gdth_get_status(gdth_ha_str *ha, int irq)
 {
-    register gdth_ha_str *ha;
-    int i;
+    unchar IStatus = 0;
+
+    TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count));
 
-    TRACE(("gdth_get_status() irq %d ctr_count %d\n",
-           irq,gdth_ctr_count));
-    
-    *pIStatus = 0;
-    for (i=0; i<gdth_ctr_count; ++i) {
-        ha = HADATA(gdth_ctr_tab[i]);
         if (ha->irq != (unchar)irq)             /* check IRQ */
-            continue;
+            return false;
         if (ha->type == GDT_EISA)
-            *pIStatus = inb((ushort)ha->bmic + EDOORREG);
+            IStatus = inb((ushort)ha->bmic + EDOORREG);
         else if (ha->type == GDT_ISA)
-            *pIStatus =
-                gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+            IStatus =
+                readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
         else if (ha->type == GDT_PCI)
-            *pIStatus =
-                gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+            IStatus =
+                readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
         else if (ha->type == GDT_PCINEW) 
-            *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
+            IStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
         else if (ha->type == GDT_PCIMPR)
-            *pIStatus =
-                gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
-   
-        if (*pIStatus)                                  
-            return i;                           /* board found */
-    }
-    return -1;
+            IStatus =
+                readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
+
+        return IStatus;
 }
-                 
-    
-static int gdth_test_busy(int hanum)
+
+static int gdth_test_busy(gdth_ha_str *ha)
 {
-    register gdth_ha_str *ha;
     register int gdtsema0 = 0;
 
-    TRACE(("gdth_test_busy() hanum %d\n",hanum));
-    
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE(("gdth_test_busy() hanum %d\n", ha->hanum));
+
     if (ha->type == GDT_EISA)
         gdtsema0 = (int)inb(ha->bmic + SEMA0REG);
     else if (ha->type == GDT_ISA)
-        gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+        gdtsema0 = (int)readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
     else if (ha->type == GDT_PCI)
-        gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+        gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
     else if (ha->type == GDT_PCINEW) 
         gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
     else if (ha->type == GDT_PCIMPR)
         gdtsema0 = 
-            (int)gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+            (int)readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
 
     return (gdtsema0 & 1);
 }
 
 
-static int gdth_get_cmd_index(int hanum)
+static int gdth_get_cmd_index(gdth_ha_str *ha)
 {
-    register gdth_ha_str *ha;
     int i;
 
-    TRACE(("gdth_get_cmd_index() hanum %d\n",hanum));
+    TRACE(("gdth_get_cmd_index() hanum %d\n", ha->hanum));
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     for (i=0; i<GDTH_MAXCMDS; ++i) {
         if (ha->cmd_tab[i].cmnd == UNUSED_CMND) {
             ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer;
@@ -1663,30 +1399,26 @@ static int gdth_get_cmd_index(int hanum)
 }
 
 
-static void gdth_set_sema0(int hanum)
+static void gdth_set_sema0(gdth_ha_str *ha)
 {
-    register gdth_ha_str *ha;
-
-    TRACE(("gdth_set_sema0() hanum %d\n",hanum));
+    TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum));
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     if (ha->type == GDT_EISA) {
         outb(1, ha->bmic + SEMA0REG);
     } else if (ha->type == GDT_ISA) {
-        gdth_writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+        writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
     } else if (ha->type == GDT_PCI) {
-        gdth_writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+        writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
     } else if (ha->type == GDT_PCINEW) { 
         outb(1, PTR2USHORT(&ha->plx->sema0_reg));
     } else if (ha->type == GDT_PCIMPR) {
-        gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+        writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
     }
 }
 
 
-static void gdth_copy_command(int hanum)
+static void gdth_copy_command(gdth_ha_str *ha)
 {
-    register gdth_ha_str *ha;
     register gdth_cmd_str *cmd_ptr;
     register gdt6m_dpram_str __iomem *dp6m_ptr;
     register gdt6c_dpram_str __iomem *dp6c_ptr;
@@ -1694,9 +1426,8 @@ static void gdth_copy_command(int hanum)
     gdt2_dpram_str __iomem *dp2_ptr;
     ushort cp_count,dp_offset,cmd_no;
     
-    TRACE(("gdth_copy_command() hanum %d\n",hanum));
+    TRACE(("gdth_copy_command() hanum %d\n", ha->hanum));
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     cp_count = ha->cmd_len;
     dp_offset= ha->cmd_offs_dpmem;
     cmd_no   = ha->cmd_cnt;
@@ -1715,42 +1446,39 @@ static void gdth_copy_command(int hanum)
     /* set offset and service, copy command to DPMEM */
     if (ha->type == GDT_ISA) {
         dp2_ptr = ha->brd;
-        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+        writew(dp_offset + DPMEM_COMMAND_OFFSET,
                     &dp2_ptr->u.ic.comm_queue[cmd_no].offset);
-        gdth_writew((ushort)cmd_ptr->Service, 
+        writew((ushort)cmd_ptr->Service,
                     &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
         memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     } else if (ha->type == GDT_PCI) {
         dp6_ptr = ha->brd;
-        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+        writew(dp_offset + DPMEM_COMMAND_OFFSET,
                     &dp6_ptr->u.ic.comm_queue[cmd_no].offset);
-        gdth_writew((ushort)cmd_ptr->Service, 
+        writew((ushort)cmd_ptr->Service,
                     &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
         memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     } else if (ha->type == GDT_PCINEW) {
         dp6c_ptr = ha->brd;
-        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+        writew(dp_offset + DPMEM_COMMAND_OFFSET,
                     &dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
-        gdth_writew((ushort)cmd_ptr->Service, 
+        writew((ushort)cmd_ptr->Service,
                     &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
         memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     } else if (ha->type == GDT_PCIMPR) {
         dp6m_ptr = ha->brd;
-        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+        writew(dp_offset + DPMEM_COMMAND_OFFSET,
                     &dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
-        gdth_writew((ushort)cmd_ptr->Service, 
+        writew((ushort)cmd_ptr->Service,
                     &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
         memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     }
 }
 
 
-static void gdth_release_event(int hanum)
+static void gdth_release_event(gdth_ha_str *ha)
 {
-    register gdth_ha_str *ha;
-
-    TRACE(("gdth_release_event() hanum %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE(("gdth_release_event() hanum %d\n", ha->hanum));
 
 #ifdef GDTH_STATISTICS
     {
@@ -1774,56 +1502,50 @@ static void gdth_release_event(int hanum)
             outl(ha->ccb_phys, ha->bmic + MAILBOXREG);
         outb(ha->pccb->Service, ha->bmic + LDOORREG);
     } else if (ha->type == GDT_ISA) {
-        gdth_writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event);
+        writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event);
     } else if (ha->type == GDT_PCI) {
-        gdth_writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event);
+        writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event);
     } else if (ha->type == GDT_PCINEW) { 
         outb(1, PTR2USHORT(&ha->plx->ldoor_reg));
     } else if (ha->type == GDT_PCIMPR) {
-        gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg);
+        writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg);
     }
 }
 
-    
-static int gdth_wait(int hanum,int index,ulong32 time)
+static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
 {
-    gdth_ha_str *ha;
     int answer_found = FALSE;
+    int wait_index = 0;
 
-    TRACE(("gdth_wait() hanum %d index %d time %d\n",hanum,index,time));
+    TRACE(("gdth_wait() hanum %d index %d time %d\n", ha->hanum, index, time));
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     if (index == 0)
         return 1;                               /* no wait required */
 
-    gdth_from_wait = TRUE;
     do {
-        gdth_interrupt((int)ha->irq,ha);
-        if (wait_hanum==hanum && wait_index==index) {
+        __gdth_interrupt(ha, (int)ha->irq, true, &wait_index);
+        if (wait_index == index) {
             answer_found = TRUE;
             break;
         }
         gdth_delay(1);
     } while (--time);
-    gdth_from_wait = FALSE;
-    
-    while (gdth_test_busy(hanum))
+
+    while (gdth_test_busy(ha))
         gdth_delay(0);
 
     return (answer_found);
 }
 
 
-static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
-                             ulong64 p2,ulong64 p3)
+static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
+                                            ulong32 p1, ulong64 p2, ulong64 p3)
 {
-    register gdth_ha_str *ha;
     register gdth_cmd_str *cmd_ptr;
     int retries,index;
 
     TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode));
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     cmd_ptr = ha->pccb;
     memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str));
 
@@ -1831,11 +1553,11 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
     for (retries = INIT_RETRIES;;) {
         cmd_ptr->Service          = service;
         cmd_ptr->RequestBuffer    = INTERNAL_CMND;
-        if (!(index=gdth_get_cmd_index(hanum))) {
+        if (!(index=gdth_get_cmd_index(ha))) {
             TRACE(("GDT: No free command index found\n"));
             return 0;
         }
-        gdth_set_sema0(hanum);
+        gdth_set_sema0(ha);
         cmd_ptr->OpCode           = opcode;
         cmd_ptr->BoardNode        = LOCALBOARD;
         if (service == CACHESERVICE) {
@@ -1875,10 +1597,10 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
         ha->cmd_len          = sizeof(gdth_cmd_str);
         ha->cmd_offs_dpmem   = 0;
         ha->cmd_cnt          = 0;
-        gdth_copy_command(hanum);
-        gdth_release_event(hanum);
+        gdth_copy_command(ha);
+        gdth_release_event(ha);
         gdth_delay(20);
-        if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
+        if (!gdth_wait(ha, index, INIT_TIMEOUT)) {
             printk("GDT: Initialization error (timeout service %d)\n",service);
             return 0;
         }
@@ -1893,9 +1615,8 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
 
 /* search for devices */
 
-static int __init gdth_search_drives(int hanum)
+static int __init gdth_search_drives(gdth_ha_str *ha)
 {
-    register gdth_ha_str *ha;
     ushort cdev_cnt, i;
     int ok;
     ulong32 bus_no, drv_cnt, drv_no, j;
@@ -1915,22 +1636,21 @@ static int __init gdth_search_drives(int hanum)
     ulong flags;
 #endif     
    
-    TRACE(("gdth_search_drives() hanum %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE(("gdth_search_drives() hanum %d\n", ha->hanum));
     ok = 0;
 
     /* initialize controller services, at first: screen service */
     ha->screen_feat = 0;
     if (!force_dma32) {
-        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0);
+        ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_X_INIT_SCR, 0, 0, 0);
         if (ok)
             ha->screen_feat = GDT_64BIT;
     }
     if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
-        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0);
+        ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0);
     if (!ok) {
         printk("GDT-HA %d: Initialization error screen service (code %d)\n",
-               hanum, ha->status);
+               ha->hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
@@ -1954,25 +1674,26 @@ static int __init gdth_search_drives(int hanum)
     TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
             *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
     /* 3. send to controller firmware */
-    gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0],
+    gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(ulong32 *)&rtc[0],
                       *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]);
 #endif  
  
     /* unfreeze all IOs */
-    gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0);
+    gdth_internal_cmd(ha, CACHESERVICE, GDT_UNFREEZE_IO, 0, 0, 0);
  
     /* initialize cache service */
     ha->cache_feat = 0;
     if (!force_dma32) {
-        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0);
+        ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INIT_HOST, LINUX_OS,
+                                                                         0, 0);
         if (ok)
             ha->cache_feat = GDT_64BIT;
     }
     if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
-        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0);
+        ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0);
     if (!ok) {
         printk("GDT-HA %d: Initialization error cache service (code %d)\n",
-               hanum, ha->status);
+               ha->hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
@@ -2001,9 +1722,9 @@ static int __init gdth_search_drives(int hanum)
         pmod->cmd_buff_size    = 0;
         pmod->reserved1        = 0;            
         pmod->reserved2        = 0;            
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES,
+        if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SET_PERF_MODES,
                               INVALID_CHANNEL,sizeof(gdth_perf_modes))) {
-            printk("GDT-HA %d: Interrupt coalescing activated\n", hanum);
+            printk("GDT-HA %d: Interrupt coalescing activated\n", ha->hanum);
         }
     }
 #endif
@@ -2015,7 +1736,7 @@ static int __init gdth_search_drives(int hanum)
     iocr->hdr.first_chan     = 0;
     iocr->hdr.last_chan      = MAXBUS-1;
     iocr->hdr.list_offset    = GDTOFFSOF(gdth_raw_iochan_str, list[0]);
-    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_RAW_DESC,
+    if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_RAW_DESC,
                           INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) {
         TRACE2(("IOCHAN_RAW_DESC supported!\n"));
         ha->bus_cnt = iocr->hdr.chan_count;
@@ -2030,13 +1751,13 @@ static int __init gdth_search_drives(int hanum)
         chn = (gdth_getch_str *)ha->pscratch;
         for (bus_no = 0; bus_no < MAXBUS; ++bus_no) {
             chn->channel_no = bus_no;
-            if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+            if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
                                    SCSI_CHAN_CNT | L_CTRL_PATTERN,
                                    IO_CHANNEL | INVALID_CHANNEL,
                                    sizeof(gdth_getch_str))) {
                 if (bus_no == 0) {
                     printk("GDT-HA %d: Error detecting channel count (0x%x)\n",
-                           hanum, ha->status);
+                           ha->hanum, ha->status);
                     return 0;
                 }
                 break;
@@ -2051,10 +1772,10 @@ static int __init gdth_search_drives(int hanum)
     TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt));
 
     /* read cache configuration */
-    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
+    if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_INFO,
                            INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
         printk("GDT-HA %d: Initialization error cache service (code %d)\n",
-               hanum, ha->status);
+               ha->hanum, ha->status);
         return 0;
     }
     ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar;
@@ -2064,11 +1785,11 @@ static int __init gdth_search_drives(int hanum)
 
     /* read board info and features */
     ha->more_proc = FALSE;
-    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
+    if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_INFO,
                           INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
         memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch,
                sizeof(gdth_binfo_str));
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
+        if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_FEATURES,
                               INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
             TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
             ha->bfeat = *(gdth_bfeat_str *)ha->pscratch;
@@ -2076,7 +1797,7 @@ static int __init gdth_search_drives(int hanum)
         }
     } else {
         TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n"));
-        strcpy(ha->binfo.type_string, gdth_ctr_name(hanum));
+        strcpy(ha->binfo.type_string, gdth_ctr_name(ha));
     }
     TRACE2(("Controller name: %s\n",ha->binfo.type_string));
 
@@ -2089,7 +1810,7 @@ static int __init gdth_search_drives(int hanum)
         ioc->hdr.first_chan     = 0;
         ioc->hdr.last_chan      = MAXBUS-1;
         ioc->hdr.list_offset    = GDTOFFSOF(gdth_iochan_str, list[0]);
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_DESC,
+        if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_DESC,
                               INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
             for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
                 ha->raw[bus_no].address = ioc->list[bus_no].address;
@@ -2104,7 +1825,7 @@ static int __init gdth_search_drives(int hanum)
         for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
             chn = (gdth_getch_str *)ha->pscratch;
             chn->channel_no = ha->raw[bus_no].local_no;
-            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+            if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
                                   SCSI_CHAN_CNT | L_CTRL_PATTERN,
                                   ha->raw[bus_no].address | INVALID_CHANNEL,
                                   sizeof(gdth_getch_str))) {
@@ -2116,7 +1837,7 @@ static int __init gdth_search_drives(int hanum)
                 drl = (gdth_drlist_str *)ha->pscratch;
                 drl->sc_no = ha->raw[bus_no].local_no;
                 drl->sc_cnt = ha->raw[bus_no].pdev_cnt;
-                if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
                                       SCSI_DR_LIST | L_CTRL_PATTERN,
                                       ha->raw[bus_no].address | INVALID_CHANNEL,
                                       sizeof(gdth_drlist_str))) {
@@ -2129,10 +1850,10 @@ static int __init gdth_search_drives(int hanum)
         }
 
         /* logical drives */
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_CNT,
+        if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT,
                               INVALID_CHANNEL,sizeof(ulong32))) {
             drv_cnt = *(ulong32 *)ha->pscratch;
-            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_LIST,
+            if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST,
                                   INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
                 for (j = 0; j < drv_cnt; ++j) {
                     drv_no = ((ulong32 *)ha->pscratch)[j];
@@ -2146,7 +1867,7 @@ static int __init gdth_search_drives(int hanum)
             alst->entries_avail = MAX_LDRIVES;
             alst->first_entry = 0;
             alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
-            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+            if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
                                   ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, 
                                   INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
                                   (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 
@@ -2157,7 +1878,7 @@ static int __init gdth_search_drives(int hanum)
                     ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
                     ha->hdr[j].master_no = alst->list[j].cd_handle;
                 }
-            } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+            } else if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
                                          ARRAY_DRV_LIST | LA_CTRL_PATTERN,
                                          0, 35 * sizeof(gdth_alist_str))) {
                 for (j = 0; j < 35; ++j) {
@@ -2175,24 +1896,24 @@ static int __init gdth_search_drives(int hanum)
     /* initialize raw service */
     ha->raw_feat = 0;
     if (!force_dma32) {
-        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0);
+        ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_X_INIT_RAW, 0, 0, 0);
         if (ok)
             ha->raw_feat = GDT_64BIT;
     }
     if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
-        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0);
+        ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0);
     if (!ok) {
         printk("GDT-HA %d: Initialization error raw service (code %d)\n",
-               hanum, ha->status);
+               ha->hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
 
     /* set/get features raw service (scatter/gather) */
-    if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
-                          0,0)) {
+    if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_SET_FEAT, SCATTER_GATHER,
+                          0, 0)) {
         TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
-        if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
+        if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) {
             TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n",
                     ha->info));
             ha->raw_feat |= (ushort)ha->info;
@@ -2200,10 +1921,10 @@ static int __init gdth_search_drives(int hanum)
     } 
 
     /* set/get features cache service (equal to raw service) */
-    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0,
+    if (gdth_internal_cmd(ha, CACHESERVICE, GDT_SET_FEAT, 0,
                           SCATTER_GATHER,0)) {
         TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n"));
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
+        if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) {
             TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n",
                     ha->info));
             ha->cache_feat |= (ushort)ha->info;
@@ -2212,22 +1933,22 @@ static int __init gdth_search_drives(int hanum)
 
     /* reserve drives for raw service */
     if (reserve_mode != 0) {
-        gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE_ALL,
+        gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE_ALL,
                           reserve_mode == 1 ? 1 : 3, 0, 0);
         TRACE2(("gdth_search_drives(): RESERVE_ALL code %d\n", 
                 ha->status));
     }
     for (i = 0; i < MAX_RES_ARGS; i += 4) {
-        if (reserve_list[i] == hanum && reserve_list[i+1] < ha->bus_cnt && 
+        if (reserve_list[i] == ha->hanum && reserve_list[i+1] < ha->bus_cnt &&
             reserve_list[i+2] < ha->tid_cnt && reserve_list[i+3] < MAXLUN) {
             TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d lun %d\n",
                     reserve_list[i], reserve_list[i+1],
                     reserve_list[i+2], reserve_list[i+3]));
-            if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
+            if (!gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE, 0,
                                    reserve_list[i+1], reserve_list[i+2] | 
                                    (reserve_list[i+3] << 8))) {
                 printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n",
-                       hanum, ha->status);
+                       ha->hanum, ha->status);
              }
         }
     }
@@ -2236,58 +1957,44 @@ static int __init gdth_search_drives(int hanum)
     oemstr = (gdth_oem_str_ioctl *)ha->pscratch;
     oemstr->params.ctl_version = 0x01;
     oemstr->params.buffer_size = sizeof(oemstr->text);
-    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+    if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
                           CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL,
                           sizeof(gdth_oem_str_ioctl))) {
         TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n"));
         printk("GDT-HA %d: Vendor: %s Name: %s\n",
-               hanum,oemstr->text.oem_company_name,ha->binfo.type_string);
+               ha->hanum, oemstr->text.oem_company_name, ha->binfo.type_string);
         /* Save the Host Drive inquiry data */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,
                 sizeof(ha->oem_name));
-#else
-        strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7);
-        ha->oem_name[7] = '\0';
-#endif
     } else {
         /* Old method, based on PCI ID */
         TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n"));
         printk("GDT-HA %d: Name: %s\n",
-               hanum,ha->binfo.type_string);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+               ha->hanum, ha->binfo.type_string);
         if (ha->oem_id == OEM_ID_INTEL)
             strlcpy(ha->oem_name,"Intel  ", sizeof(ha->oem_name));
         else
             strlcpy(ha->oem_name,"ICP    ", sizeof(ha->oem_name));
-#else 
-        if (ha->oem_id == OEM_ID_INTEL)
-            strcpy(ha->oem_name,"Intel  ");
-        else
-            strcpy(ha->oem_name,"ICP    ");
-#endif
     }
 
     /* scanning for host drives */
     for (i = 0; i < cdev_cnt; ++i) 
-        gdth_analyse_hdrive(hanum,i);
+        gdth_analyse_hdrive(hai);
     
     TRACE(("gdth_search_drives() OK\n"));
     return 1;
 }
 
-static int gdth_analyse_hdrive(int hanum,ushort hdrive)
+static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
 {
-    register gdth_ha_str *ha;
     ulong32 drv_cyls;
     int drv_hds, drv_secs;
 
-    TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
+    TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive));
     if (hdrive >= MAX_HDRIVES)
         return 0;
-    ha = HADATA(gdth_ctr_tab[hanum]);
 
-    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0)) 
+    if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_INFO, hdrive, 0, 0))
         return 0;
     ha->hdr[hdrive].present = TRUE;
     ha->hdr[hdrive].size = ha->info;
@@ -2307,7 +2014,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
     ha->hdr[hdrive].size  = drv_cyls * drv_hds * drv_secs;
     
     if (ha->cache_feat & GDT_64BIT) {
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0)
+        if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0)
             && ha->info2 != 0) {
             ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info;
         }
@@ -2316,14 +2023,14 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
             hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
 
     /* get informations about device */
-    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
+    if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) {
         TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
                 hdrive,ha->info));
         ha->hdr[hdrive].devtype = (ushort)ha->info;
     }
 
     /* cluster info */
-    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) {
+    if (gdth_internal_cmd(ha, CACHESERVICE, GDT_CLUST_INFO, hdrive, 0, 0)) {
         TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
                 hdrive,ha->info));
         if (!shared_access)
@@ -2331,7 +2038,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
     }
 
     /* R/W attributes */
-    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
+    if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) {
         TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
                 hdrive,ha->info));
         ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
@@ -2343,27 +2050,26 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
 
 /* command queueing/sending functions */
 
-static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority)
 {
-    register gdth_ha_str *ha;
+    struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
     register Scsi_Cmnd *pscp;
     register Scsi_Cmnd *nscp;
     ulong flags;
     unchar b, t;
 
     TRACE(("gdth_putq() priority %d\n",priority));
-    ha = HADATA(gdth_ctr_tab[hanum]);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
-    if (scp->done != gdth_scsi_done) {
-        scp->SCp.this_residual = (int)priority;
-        b = virt_ctr ? NUMDATA(scp->device->host)->busnum:scp->device->channel;
+    if (!cmndinfo->internal_command) {
+        cmndinfo->priority = priority;
+        b = scp->device->channel;
         t = scp->device->id;
         if (priority >= DEFAULT_PRI) {
             if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
                 (b==ha->virt_bus && t<MAX_HDRIVES && ha->hdr[t].lock)) {
                 TRACE2(("gdth_putq(): locked IO ->update_timeout()\n"));
-                scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+                cmndinfo->timeout = gdth_update_timeout(scp, 0);
             }
         }
     }
@@ -2375,7 +2081,7 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
         pscp = ha->req_first;
         nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
         /* priority: 0-highest,..,0xff-lowest */
-        while (nscp && (unchar)nscp->SCp.this_residual <= priority) {
+        while (nscp && gdth_cmnd_priv(nscp)->priority <= priority) {
             pscp = nscp;
             nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
         }
@@ -2395,9 +2101,8 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
 #endif
 }
 
-static void gdth_next(int hanum)
+static void gdth_next(gdth_ha_str *ha)
 {
-    register gdth_ha_str *ha;
     register Scsi_Cmnd *pscp;
     register Scsi_Cmnd *nscp;
     unchar b, t, l, firsttime;
@@ -2405,8 +2110,7 @@ static void gdth_next(int hanum)
     ulong flags = 0;
     int cmd_index;
 
-    TRACE(("gdth_next() hanum %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE(("gdth_next() hanum %d\n", ha->hanum));
     if (!gdth_polling) 
         spin_lock_irqsave(&ha->smp_lock, flags);
 
@@ -2416,14 +2120,14 @@ static void gdth_next(int hanum)
     cmd_index = 0;
 
     for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
+        struct gdth_cmndinfo *nscp_cmndinfo = gdth_cmnd_priv(nscp);
         if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
             pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
-        if (nscp->done != gdth_scsi_done) {
-            b = virt_ctr ?
-                NUMDATA(nscp->device->host)->busnum : nscp->device->channel;
+        if (!nscp_cmndinfo->internal_command) {
+            b = nscp->device->channel;
             t = nscp->device->id;
             l = nscp->device->lun;
-            if (nscp->SCp.this_residual >= DEFAULT_PRI) {
+            if (nscp_cmndinfo->priority >= DEFAULT_PRI) {
                 if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
                     (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock))
                     continue;
@@ -2432,21 +2136,21 @@ static void gdth_next(int hanum)
             b = t = l = 0;
 
         if (firsttime) {
-            if (gdth_test_busy(hanum)) {        /* controller busy ? */
-                TRACE(("gdth_next() controller %d busy !\n",hanum));
+            if (gdth_test_busy(ha)) {        /* controller busy ? */
+                TRACE(("gdth_next() controller %d busy !\n", ha->hanum));
                 if (!gdth_polling) {
                     spin_unlock_irqrestore(&ha->smp_lock, flags);
                     return;
                 }
-                while (gdth_test_busy(hanum))
+                while (gdth_test_busy(ha))
                     gdth_delay(1);
             }   
             firsttime = FALSE;
         }
 
-        if (nscp->done != gdth_scsi_done) {
-        if (nscp->SCp.phase == -1) {
-            nscp->SCp.phase = CACHESERVICE;           /* default: cache svc. */ 
+        if (!nscp_cmndinfo->internal_command) {
+        if (nscp_cmndinfo->phase == -1) {
+            nscp_cmndinfo->phase = CACHESERVICE;           /* default: cache svc. */
             if (nscp->cmnd[0] == TEST_UNIT_READY) {
                 TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", 
                         b, t, l));
@@ -2459,8 +2163,8 @@ static void gdth_next(int hanum)
                 } else if ((ha->scan_mode & 0x0f) == 1) {
                     if (b == 0 && ((t == 0 && l == 1) ||
                          (t == 1 && l == 0))) {
-                        nscp->SCp.sent_command = GDT_SCAN_START;
-                        nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) 
+                        nscp_cmndinfo->OpCode = GDT_SCAN_START;
+                        nscp_cmndinfo->phase = ((ha->scan_mode & 0x10 ? 1:0) << 8)
                             | SCSIRAWSERVICE;
                         ha->scan_mode = 0x12;
                         TRACE2(("Scan mode: 0x%x (SCAN_START)\n", 
@@ -2471,8 +2175,8 @@ static void gdth_next(int hanum)
                     }                   
                 } else if (ha->scan_mode == 0x12) {
                     if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
-                        nscp->SCp.phase = SCSIRAWSERVICE;
-                        nscp->SCp.sent_command = GDT_SCAN_END;
+                        nscp_cmndinfo->phase = SCSIRAWSERVICE;
+                        nscp_cmndinfo->OpCode = GDT_SCAN_END;
                         ha->scan_mode &= 0x10;
                         TRACE2(("Scan mode: 0x%x (SCAN_END)\n", 
                                 ha->scan_mode));
@@ -2483,18 +2187,18 @@ static void gdth_next(int hanum)
                 nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
                 (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
                 /* always GDT_CLUST_INFO! */
-                nscp->SCp.sent_command = GDT_CLUST_INFO;
+                nscp_cmndinfo->OpCode = GDT_CLUST_INFO;
             }
         }
         }
 
-        if (nscp->SCp.sent_command != -1) {
-            if ((nscp->SCp.phase & 0xff) == CACHESERVICE) {
-                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+        if (nscp_cmndinfo->OpCode != -1) {
+            if ((nscp_cmndinfo->phase & 0xff) == CACHESERVICE) {
+                if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
                     this_cmd = FALSE;
                 next_cmd = FALSE;
-            } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
-                if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
+            } else if ((nscp_cmndinfo->phase & 0xff) == SCSIRAWSERVICE) {
+                if (!(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b))))
                     this_cmd = FALSE;
                 next_cmd = FALSE;
             } else {
@@ -2502,18 +2206,18 @@ static void gdth_next(int hanum)
                 nscp->sense_buffer[0] = 0x70;
                 nscp->sense_buffer[2] = NOT_READY;
                 nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-                if (!nscp->SCp.have_data_in)
-                    nscp->SCp.have_data_in++;
+                if (!nscp_cmndinfo->wait_for_completion)
+                    nscp_cmndinfo->wait_for_completion++;
                 else
-                    nscp->scsi_done(nscp);
+                    gdth_scsi_done(nscp);
             }
-        } else if (nscp->done == gdth_scsi_done) {
-            if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
+        } else if (gdth_cmnd_priv(nscp)->internal_command) {
+            if (!(cmd_index=gdth_special_cmd(hanscp)))
                 this_cmd = FALSE;
             next_cmd = FALSE;
         } else if (b != ha->virt_bus) {
             if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
-                !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) 
+                !(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b))))
                 this_cmd = FALSE;
             else 
                 ha->raw[BUS_L2P(ha,b)].io_cnt[t]++;
@@ -2521,10 +2225,10 @@ static void gdth_next(int hanum)
             TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
                     nscp->cmnd[0], b, t, l));
             nscp->result = DID_BAD_TARGET << 16;
-            if (!nscp->SCp.have_data_in)
-                nscp->SCp.have_data_in++;
+            if (!nscp_cmndinfo->wait_for_completion)
+                nscp_cmndinfo->wait_for_completion++;
             else
-                nscp->scsi_done(nscp);
+                gdth_scsi_done(nscp);
         } else {
             switch (nscp->cmnd[0]) {
               case TEST_UNIT_READY:
@@ -2547,12 +2251,12 @@ static void gdth_next(int hanum)
                     nscp->sense_buffer[0] = 0x70;
                     nscp->sense_buffer[2] = UNIT_ATTENTION;
                     nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-                    if (!nscp->SCp.have_data_in)
-                        nscp->SCp.have_data_in++;
+                    if (!nscp_cmndinfo->wait_for_completion)
+                        nscp_cmndinfo->wait_for_completion++;
                     else
-                        nscp->scsi_done(nscp);
-                } else if (gdth_internal_cache_cmd(hanum,nscp))
-                    nscp->scsi_done(nscp);
+                        gdth_scsi_done(nscp);
+                } else if (gdth_internal_cache_cmd(hanscp))
+                    gdth_scsi_done(nscp);
                 break;
 
               case ALLOW_MEDIUM_REMOVAL:
@@ -2563,15 +2267,15 @@ static void gdth_next(int hanum)
                     TRACE(("Prevent r. nonremov. drive->do nothing\n"));
                     nscp->result = DID_OK << 16;
                     nscp->sense_buffer[0] = 0;
-                    if (!nscp->SCp.have_data_in)
-                        nscp->SCp.have_data_in++;
+                    if (!nscp_cmndinfo->wait_for_completion)
+                        nscp_cmndinfo->wait_for_completion++;
                     else
-                        nscp->scsi_done(nscp);
+                        gdth_scsi_done(nscp);
                 } else {
                     nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0;
                     TRACE(("Prevent/allow r. %d rem. drive %d\n",
                            nscp->cmnd[4],nscp->cmnd[3]));
-                    if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
                         this_cmd = FALSE;
                 }
                 break;
@@ -2580,7 +2284,7 @@ static void gdth_next(int hanum)
               case RELEASE:
                 TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ?
                         "RESERVE" : "RELEASE"));
-                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
                     this_cmd = FALSE;
                 break;
                 
@@ -2599,11 +2303,11 @@ static void gdth_next(int hanum)
                     nscp->sense_buffer[0] = 0x70;
                     nscp->sense_buffer[2] = UNIT_ATTENTION;
                     nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-                    if (!nscp->SCp.have_data_in)
-                        nscp->SCp.have_data_in++;
+                    if (!nscp_cmndinfo->wait_for_completion)
+                        nscp_cmndinfo->wait_for_completion++;
                     else
-                        nscp->scsi_done(nscp);
-                } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                        gdth_scsi_done(nscp);
+                } else if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
                     this_cmd = FALSE;
                 break;
 
@@ -2612,12 +2316,12 @@ static void gdth_next(int hanum)
                         nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
                         nscp->cmnd[4],nscp->cmnd[5]));
                 printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n",
-                       hanum, nscp->cmnd[0]);
+                       ha->hanum, nscp->cmnd[0]);
                 nscp->result = DID_ABORT << 16;
-                if (!nscp->SCp.have_data_in)
-                    nscp->SCp.have_data_in++;
+                if (!nscp_cmndinfo->wait_for_completion)
+                    nscp_cmndinfo->wait_for_completion++;
                 else
-                    nscp->scsi_done(nscp);
+                    gdth_scsi_done(nscp);
                 break;
             }
         }
@@ -2633,79 +2337,77 @@ static void gdth_next(int hanum)
     }
 
     if (ha->cmd_cnt > 0) {
-        gdth_release_event(hanum);
+        gdth_release_event(ha);
     }
 
     if (!gdth_polling) 
         spin_unlock_irqrestore(&ha->smp_lock, flags);
 
     if (gdth_polling && ha->cmd_cnt > 0) {
-        if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
+        if (!gdth_wait(ha, cmd_index, POLL_TIMEOUT))
             printk("GDT-HA %d: Command %d timed out !\n",
-                   hanum,cmd_index);
+                   ha->hanum, cmd_index);
     }
 }
-   
-static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
-                                    char *buffer,ushort count)
+
+/*
+ * gdth_copy_internal_data() - copy to/from a buffer onto a scsi_cmnd's
+ * buffers, kmap_atomic() as needed.
+ */
+static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
+                                    char *buffer, ushort count, int to_buffer)
 {
-    ushort cpcount,i;
+    ushort cpcount,i, max_sg = gdth_sg_count(scp);
     ushort cpsum,cpnow;
     struct scatterlist *sl;
-    gdth_ha_str *ha;
     char *address;
 
-    cpcount = count<=(ushort)scp->request_bufflen ? count:(ushort)scp->request_bufflen;
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    cpcount = min_t(ushort, count, gdth_bufflen(scp));
 
-    if (scp->use_sg) {
-        sl = (struct scatterlist *)scp->request_buffer;
-        for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
+    if (cpcount) {
+        cpsum=0;
+        scsi_for_each_sg(scp, sl, max_sg, i) {
             unsigned long flags;
             cpnow = (ushort)sl->length;
             TRACE(("copy_internal() now %d sum %d count %d %d\n",
-                          cpnow,cpsum,cpcount,(ushort)scp->bufflen));
+                          cpnow, cpsum, cpcount, gdth_bufflen(scp)));
             if (cpsum+cpnow > cpcount) 
                 cpnow = cpcount - cpsum;
             cpsum += cpnow;
             if (!sl->page) {
                 printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n",
-                       hanum);
+                       ha->hanum);
                 return;
             }
             local_irq_save(flags);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
             address = kmap_atomic(sl->page, KM_BIO_SRC_IRQ) + sl->offset;
-            memcpy(address,buffer,cpnow);
+            if (to_buffer)
+                memcpy(buffer, address, cpnow);
+            else
+                memcpy(address, buffer, cpnow);
             flush_dcache_page(sl->page);
             kunmap_atomic(address, KM_BIO_SRC_IRQ);
-#else
-            address = kmap_atomic(sl->page, KM_BH_IRQ) + sl->offset;
-            memcpy(address,buffer,cpnow);
-            flush_dcache_page(sl->page);
-            kunmap_atomic(address, KM_BH_IRQ);
-#endif
             local_irq_restore(flags);
             if (cpsum == cpcount)
                 break;
             buffer += cpnow;
         }
-    } else {
-        TRACE(("copy_internal() count %d\n",cpcount));
-        memcpy((char*)scp->request_buffer,buffer,cpcount);
+    } else if (count) {
+        printk("GDT-HA %d: SCSI command with no buffers but data transfer expected!\n",
+               ha->hanum);
+        WARN_ON(1);
     }
 }
 
-static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
+static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
 {
-    register gdth_ha_str *ha;
     unchar t;
     gdth_inq_data inq;
     gdth_rdcap_data rdc;
     gdth_sense_data sd;
     gdth_modep_data mpd;
+    struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     t  = scp->device->id;
     TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
            scp->cmnd[0],t));
@@ -2736,7 +2438,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
         strcpy(inq.vendor,ha->oem_name);
         sprintf(inq.product,"Host Drive  #%02d",t);
         strcpy(inq.revision,"   ");
-        gdth_copy_internal_data(hanum,scp,(char*)&inq,sizeof(gdth_inq_data));
+        gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data), 0);
         break;
 
       case REQUEST_SENSE:
@@ -2746,7 +2448,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
         sd.key       = NO_SENSE;
         sd.info      = 0;
         sd.add_length= 0;
-        gdth_copy_internal_data(hanum,scp,(char*)&sd,sizeof(gdth_sense_data));
+        gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data), 0);
         break;
 
       case MODE_SENSE:
@@ -2758,7 +2460,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
         mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
         mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
         mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
-        gdth_copy_internal_data(hanum,scp,(char*)&mpd,sizeof(gdth_modep_data));
+        gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data), 0);
         break;
 
       case READ_CAPACITY:
@@ -2768,7 +2470,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
         else
             rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
         rdc.block_length  = cpu_to_be32(SECTOR_SIZE);
-        gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+        gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data), 0);
         break;
 
       case SERVICE_ACTION_IN:
@@ -2779,7 +2481,8 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
             TRACE2(("Read capacity (16) hdrive %d\n",t));
             rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
             rdc16.block_length  = cpu_to_be32(SECTOR_SIZE);
-            gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data));
+            gdth_copy_internal_data(ha, scp, (char*)&rdc16,
+                                                 sizeof(gdth_rdcap16_data), 0);
         } else { 
             scp->result = DID_ABORT << 16;
         }
@@ -2790,27 +2493,22 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
         break;
     }
 
-    if (!scp->SCp.have_data_in)
-        scp->SCp.have_data_in++;
+    if (!cmndinfo->wait_for_completion)
+        cmndinfo->wait_for_completion++;
     else 
         return 1;
 
     return 0;
 }
-    
-static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
+
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
 {
-    register gdth_ha_str *ha;
     register gdth_cmd_str *cmdp;
-    struct scatterlist *sl;
+    struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
     ulong32 cnt, blockcnt;
     ulong64 no, blockno;
-    dma_addr_t phys_addr;
     int i, cmd_index, read_write, sgcnt, mode64;
-    struct page *page;
-    ulong offset;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
     TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n",
                  scp->cmnd[0],scp->cmd_len,hdrive));
@@ -2826,18 +2524,18 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
     cmdp->Service = CACHESERVICE;
     cmdp->RequestBuffer = scp;
     /* search free command index */
-    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+    if (!(cmd_index=gdth_get_cmd_index(ha))) {
         TRACE(("GDT: No free command index found\n"));
         return 0;
     }
     /* if it's the first command, set command semaphore */
     if (ha->cmd_cnt == 0)
-        gdth_set_sema0(hanum);
+        gdth_set_sema0(ha);
 
     /* fill command */
     read_write = 0;
-    if (scp->SCp.sent_command != -1) 
-        cmdp->OpCode = scp->SCp.sent_command;   /* special cache cmd. */
+    if (cmndinfo->OpCode != -1)
+        cmdp->OpCode = cmndinfo->OpCode;   /* special cache cmd. */
     else if (scp->cmnd[0] == RESERVE) 
         cmdp->OpCode = GDT_RESERVE_DRV;
     else if (scp->cmnd[0] == RELEASE)
@@ -2898,17 +2596,17 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
             cmdp->u.cache.BlockCnt = blockcnt;
         }
 
-        if (scp->use_sg) {
-            sl = (struct scatterlist *)scp->request_buffer;
-            sgcnt = scp->use_sg;
-            scp->SCp.Status = GDTH_MAP_SG;
-            scp->SCp.Message = (read_write == 1 ? 
+        if (gdth_bufflen(scp)) {
+            cmndinfo->dma_dir = (read_write == 1 ?
                 PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);   
-            sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+            sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+                               cmndinfo->dma_dir);
             if (mode64) {
+                struct scatterlist *sl;
+
                 cmdp->u.cache64.DestAddr= (ulong64)-1;
                 cmdp->u.cache64.sg_canz = sgcnt;
-                for (i=0; i<sgcnt; ++i,++sl) {
+                scsi_for_each_sg(scp, sl, sgcnt, i) {
                     cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl);
 #ifdef GDTH_DMA_STATISTICS
                     if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
@@ -2919,9 +2617,11 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
                     cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl);
                 }
             } else {
+                struct scatterlist *sl;
+
                 cmdp->u.cache.DestAddr= 0xffffffff;
                 cmdp->u.cache.sg_canz = sgcnt;
-                for (i=0; i<sgcnt; ++i,++sl) {
+                scsi_for_each_sg(scp, sl, sgcnt, i) {
                     cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl);
 #ifdef GDTH_DMA_STATISTICS
                     ha->dma32_cnt++;
@@ -2937,38 +2637,6 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
             }
 #endif
 
-        } else if (scp->request_bufflen) {
-            scp->SCp.Status = GDTH_MAP_SINGLE;
-            scp->SCp.Message = (read_write == 1 ? 
-                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-            page = virt_to_page(scp->request_buffer);
-            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
-            phys_addr = pci_map_page(ha->pdev,page,offset,
-                                     scp->request_bufflen,scp->SCp.Message);
-            scp->SCp.dma_handle = phys_addr;
-            if (mode64) {
-                if (ha->cache_feat & SCATTER_GATHER) {
-                    cmdp->u.cache64.DestAddr = (ulong64)-1;
-                    cmdp->u.cache64.sg_canz = 1;
-                    cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr;
-                    cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen;
-                    cmdp->u.cache64.sg_lst[1].sg_len = 0;
-                } else {
-                    cmdp->u.cache64.DestAddr  = phys_addr;
-                    cmdp->u.cache64.sg_canz= 0;
-                }
-            } else {
-                if (ha->cache_feat & SCATTER_GATHER) {
-                    cmdp->u.cache.DestAddr = 0xffffffff;
-                    cmdp->u.cache.sg_canz = 1;
-                    cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr;
-                    cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
-                    cmdp->u.cache.sg_lst[1].sg_len = 0;
-                } else {
-                    cmdp->u.cache.DestAddr  = phys_addr;
-                    cmdp->u.cache.sg_canz= 0;
-                }
-            }
         }
     }
     /* evaluate command size, check space */
@@ -3004,23 +2672,21 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
     }
 
     /* copy command */
-    gdth_copy_command(hanum);
+    gdth_copy_command(ha);
     return cmd_index;
 }
 
-static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
 {
-    register gdth_ha_str *ha;
     register gdth_cmd_str *cmdp;
-    struct scatterlist *sl;
     ushort i;
-    dma_addr_t phys_addr, sense_paddr;
+    dma_addr_t sense_paddr;
     int cmd_index, sgcnt, mode64;
     unchar t,l;
     struct page *page;
     ulong offset;
+    struct gdth_cmndinfo *cmndinfo;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     t = scp->device->id;
     l = scp->device->lun;
     cmdp = ha->pccb;
@@ -3035,26 +2701,27 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
     cmdp->Service = SCSIRAWSERVICE;
     cmdp->RequestBuffer = scp;
     /* search free command index */
-    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+    if (!(cmd_index=gdth_get_cmd_index(ha))) {
         TRACE(("GDT: No free command index found\n"));
         return 0;
     }
     /* if it's the first command, set command semaphore */
     if (ha->cmd_cnt == 0)
-        gdth_set_sema0(hanum);
+        gdth_set_sema0(ha);
 
+    cmndinfo = gdth_cmnd_priv(scp);
     /* fill command */  
-    if (scp->SCp.sent_command != -1) {
-        cmdp->OpCode           = scp->SCp.sent_command; /* special raw cmd. */
+    if (cmndinfo->OpCode != -1) {
+        cmdp->OpCode           = cmndinfo->OpCode; /* special raw cmd. */
         cmdp->BoardNode        = LOCALBOARD;
         if (mode64) {
-            cmdp->u.raw64.direction = (scp->SCp.phase >> 8);
+            cmdp->u.raw64.direction = (cmndinfo->phase >> 8);
             TRACE2(("special raw cmd 0x%x param 0x%x\n", 
                     cmdp->OpCode, cmdp->u.raw64.direction));
             /* evaluate command size */
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst);
         } else {
-            cmdp->u.raw.direction  = (scp->SCp.phase >> 8);
+            cmdp->u.raw.direction  = (cmndinfo->phase >> 8);
             TRACE2(("special raw cmd 0x%x param 0x%x\n", 
                     cmdp->OpCode, cmdp->u.raw.direction));
             /* evaluate command size */
@@ -3066,9 +2733,8 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
         offset = (ulong)scp->sense_buffer & ~PAGE_MASK;
         sense_paddr = pci_map_page(ha->pdev,page,offset,
                                    16,PCI_DMA_FROMDEVICE);
-        *(ulong32 *)&scp->SCp.buffer = (ulong32)sense_paddr;
-        /* high part, if 64bit */
-        *(ulong32 *)&scp->host_scribble = (ulong32)((ulong64)sense_paddr >> 32);
+
+       cmndinfo->sense_paddr  = sense_paddr;
         cmdp->OpCode           = GDT_WRITE;             /* always */
         cmdp->BoardNode        = LOCALBOARD;
         if (mode64) { 
@@ -3080,7 +2746,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
             cmdp->u.raw64.lun        = l;
             cmdp->u.raw64.bus        = b;
             cmdp->u.raw64.priority   = 0;
-            cmdp->u.raw64.sdlen      = scp->request_bufflen;
+            cmdp->u.raw64.sdlen      = gdth_bufflen(scp);
             cmdp->u.raw64.sense_len  = 16;
             cmdp->u.raw64.sense_data = sense_paddr;
             cmdp->u.raw64.direction  = 
@@ -3097,7 +2763,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
             cmdp->u.raw.bus        = b;
             cmdp->u.raw.priority   = 0;
             cmdp->u.raw.link_p     = 0;
-            cmdp->u.raw.sdlen      = scp->request_bufflen;
+            cmdp->u.raw.sdlen      = gdth_bufflen(scp);
             cmdp->u.raw.sense_len  = 16;
             cmdp->u.raw.sense_data = sense_paddr;
             cmdp->u.raw.direction  = 
@@ -3106,16 +2772,16 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
             cmdp->u.raw.sg_ranz    = 0;
         }
 
-        if (scp->use_sg) {
-            sl = (struct scatterlist *)scp->request_buffer;
-            sgcnt = scp->use_sg;
-            scp->SCp.Status = GDTH_MAP_SG;
-            scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
-            sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+        if (gdth_bufflen(scp)) {
+            cmndinfo->dma_dir = PCI_DMA_BIDIRECTIONAL;
+            sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+                               cmndinfo->dma_dir);
             if (mode64) {
+                struct scatterlist *sl;
+
                 cmdp->u.raw64.sdata = (ulong64)-1;
                 cmdp->u.raw64.sg_ranz = sgcnt;
-                for (i=0; i<sgcnt; ++i,++sl) {
+                scsi_for_each_sg(scp, sl, sgcnt, i) {
                     cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl);
 #ifdef GDTH_DMA_STATISTICS
                     if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
@@ -3126,9 +2792,11 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
                     cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl);
                 }
             } else {
+                struct scatterlist *sl;
+
                 cmdp->u.raw.sdata = 0xffffffff;
                 cmdp->u.raw.sg_ranz = sgcnt;
-                for (i=0; i<sgcnt; ++i,++sl) {
+                scsi_for_each_sg(scp, sl, sgcnt, i) {
                     cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl);
 #ifdef GDTH_DMA_STATISTICS
                     ha->dma32_cnt++;
@@ -3144,38 +2812,6 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
             }
 #endif
 
-        } else if (scp->request_bufflen) {
-            scp->SCp.Status = GDTH_MAP_SINGLE;
-            scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
-            page = virt_to_page(scp->request_buffer);
-            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
-            phys_addr = pci_map_page(ha->pdev,page,offset,
-                                     scp->request_bufflen,scp->SCp.Message);
-            scp->SCp.dma_handle = phys_addr;
-
-            if (mode64) {
-                if (ha->raw_feat & SCATTER_GATHER) {
-                    cmdp->u.raw64.sdata  = (ulong64)-1;
-                    cmdp->u.raw64.sg_ranz= 1;
-                    cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr;
-                    cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen;
-                    cmdp->u.raw64.sg_lst[1].sg_len = 0;
-                } else {
-                    cmdp->u.raw64.sdata  = phys_addr;
-                    cmdp->u.raw64.sg_ranz= 0;
-                }
-            } else {
-                if (ha->raw_feat & SCATTER_GATHER) {
-                    cmdp->u.raw.sdata  = 0xffffffff;
-                    cmdp->u.raw.sg_ranz= 1;
-                    cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr;
-                    cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
-                    cmdp->u.raw.sg_lst[1].sg_len = 0;
-                } else {
-                    cmdp->u.raw.sdata  = phys_addr;
-                    cmdp->u.raw.sg_ranz= 0;
-                }
-            }
         }
         if (mode64) {
             TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
@@ -3209,35 +2845,33 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
     }
 
     /* copy command */
-    gdth_copy_command(hanum);
+    gdth_copy_command(ha);
     return cmd_index;
 }
 
-static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp)
+static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
 {
-    register gdth_ha_str *ha;
     register gdth_cmd_str *cmdp;
     int cmd_index;
 
-    ha  = HADATA(gdth_ctr_tab[hanum]);
     cmdp= ha->pccb;
     TRACE2(("gdth_special_cmd(): "));
 
     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
         return 0;
 
-    memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str));
+    gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1);
     cmdp->RequestBuffer = scp;
 
     /* search free command index */
-    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+    if (!(cmd_index=gdth_get_cmd_index(ha))) {
         TRACE(("GDT: No free command index found\n"));
         return 0;
     }
 
     /* if it's the first command, set command semaphore */
     if (ha->cmd_cnt == 0)
-       gdth_set_sema0(hanum);
+       gdth_set_sema0(ha);
 
     /* evaluate command size, check space */
     if (cmdp->OpCode == GDT_IOCTL) {
@@ -3275,7 +2909,7 @@ static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp)
     }
 
     /* copy command */
-    gdth_copy_command(hanum);
+    gdth_copy_command(ha);
     return cmd_index;
 }    
 
@@ -3402,15 +3036,14 @@ static void gdth_clear_events(void)
 
 /* SCSI interface functions */
 
-static irqreturn_t gdth_interrupt(int irq,void *dev_id)
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+                                    int gdth_from_wait, int* pIndex)
 {
-    gdth_ha_str *ha2 = (gdth_ha_str *)dev_id;
-    register gdth_ha_str *ha;
     gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
     gdt6_dpram_str __iomem *dp6_ptr;
     gdt2_dpram_str __iomem *dp2_ptr;
     Scsi_Cmnd *scp;
-    int hanum, rval, i;
+    int rval, i;
     unchar IStatus;
     ushort Service;
     ulong flags = 0;
@@ -3431,17 +3064,15 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
     }
 
     if (!gdth_polling)
-        spin_lock_irqsave(&ha2->smp_lock, flags);
-    wait_index = 0;
+        spin_lock_irqsave(&ha->smp_lock, flags);
 
     /* search controller */
-    if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
+    if (0 == (IStatus = gdth_get_status(ha, irq))) {
         /* spurious interrupt */
         if (!gdth_polling)
-            spin_unlock_irqrestore(&ha2->smp_lock, flags);
-            return IRQ_HANDLED;
+            spin_unlock_irqrestore(&ha->smp_lock, flags);
+        return IRQ_HANDLED;
     }
-    ha = HADATA(gdth_ctr_tab[hanum]);
 
 #ifdef GDTH_STATISTICS
     ++act_ints;
@@ -3482,32 +3113,32 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
             dp2_ptr = ha->brd;
             if (IStatus & 0x80) {                       /* error flag */
                 IStatus &= ~0x80;
-                ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+                ha->status = readw(&dp2_ptr->u.ic.Status);
                 TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
             } else                                      /* no error */
                 ha->status = S_OK;
-            ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
-            ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
-            ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+            ha->info = readl(&dp2_ptr->u.ic.Info[0]);
+            ha->service = readw(&dp2_ptr->u.ic.Service);
+            ha->info2 = readl(&dp2_ptr->u.ic.Info[1]);
 
-            gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
-            gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
-            gdth_writeb(0, &dp2_ptr->io.Sema1);     /* reset status semaphore */
+            writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
+            writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
+            writeb(0, &dp2_ptr->io.Sema1);     /* reset status semaphore */
         } else if (ha->type == GDT_PCI) {
             dp6_ptr = ha->brd;
             if (IStatus & 0x80) {                       /* error flag */
                 IStatus &= ~0x80;
-                ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+                ha->status = readw(&dp6_ptr->u.ic.Status);
                 TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
             } else                                      /* no error */
                 ha->status = S_OK;
-            ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
-            ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
-            ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+            ha->info = readl(&dp6_ptr->u.ic.Info[0]);
+            ha->service = readw(&dp6_ptr->u.ic.Service);
+            ha->info2 = readl(&dp6_ptr->u.ic.Info[1]);
 
-            gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
-            gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
-            gdth_writeb(0, &dp6_ptr->io.Sema1);     /* reset status semaphore */
+            writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
+            writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
+            writeb(0, &dp6_ptr->io.Sema1);     /* reset status semaphore */
         } else if (ha->type == GDT_PCINEW) {
             if (IStatus & 0x80) {                       /* error flag */
                 IStatus &= ~0x80;
@@ -3530,7 +3161,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
                     ha->status = pcs->ext_status & 0xffff;
                 else 
 #endif
-                    ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+                    ha->status = readw(&dp6m_ptr->i960r.status);
                 TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
             } else                                      /* no error */
                 ha->status = S_OK;
@@ -3543,18 +3174,18 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
             } else
 #endif
             {
-                ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
-                ha->service = gdth_readw(&dp6m_ptr->i960r.service);
-                ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+                ha->info = readl(&dp6m_ptr->i960r.info[0]);
+                ha->service = readw(&dp6m_ptr->i960r.service);
+                ha->info2 = readl(&dp6m_ptr->i960r.info[1]);
             }
             /* event string */
             if (IStatus == ASYNCINDEX) {
                 if (ha->service != SCREENSERVICE &&
                     (ha->fw_vers & 0xff) >= 0x1a) {
-                    ha->dvr.severity = gdth_readb
+                    ha->dvr.severity = readb
                         (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity);
                     for (i = 0; i < 256; ++i) {
-                        ha->dvr.event_string[i] = gdth_readb
+                        ha->dvr.event_string[i] = readb
                             (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]);
                         if (ha->dvr.event_string[i] == 0)
                             break;
@@ -3567,13 +3198,13 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
             if (!coalesced)
 #endif                          
             {
-                gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
-                gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+                writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+                writeb(0, &dp6m_ptr->i960r.sema1_reg);
             }
         } else {
             TRACE2(("gdth_interrupt() unknown controller type\n"));
             if (!gdth_polling)
-                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
             return IRQ_HANDLED;
         }
 
@@ -3581,26 +3212,25 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
                IStatus,ha->status,ha->info));
 
         if (gdth_from_wait) {
-            wait_hanum = hanum;
-            wait_index = (int)IStatus;
+            *pIndex = (int)IStatus;
         }
 
         if (IStatus == ASYNCINDEX) {
             TRACE2(("gdth_interrupt() async. event\n"));
-            gdth_async_event(hanum);
+            gdth_async_event(ha);
             if (!gdth_polling)
-                spin_unlock_irqrestore(&ha2->smp_lock, flags);
-            gdth_next(hanum);
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
+            gdth_next(ha);
             return IRQ_HANDLED;
         } 
 
         if (IStatus == SPEZINDEX) {
             TRACE2(("Service unknown or not initialized !\n"));
             ha->dvr.size = sizeof(ha->dvr.eu.driver);
-            ha->dvr.eu.driver.ionode = hanum;
+            ha->dvr.eu.driver.ionode = ha->hanum;
             gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
             if (!gdth_polling)
-                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
             return IRQ_HANDLED;
         }
         scp     = ha->cmd_tab[IStatus-2].cmnd;
@@ -3609,28 +3239,28 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
         if (scp == UNUSED_CMND) {
             TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
             ha->dvr.size = sizeof(ha->dvr.eu.driver);
-            ha->dvr.eu.driver.ionode = hanum;
+            ha->dvr.eu.driver.ionode = ha->hanum;
             ha->dvr.eu.driver.index = IStatus;
             gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
             if (!gdth_polling)
-                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
             return IRQ_HANDLED;
         }
         if (scp == INTERNAL_CMND) {
             TRACE(("gdth_interrupt() answer to internal command\n"));
             if (!gdth_polling)
-                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
             return IRQ_HANDLED;
         }
 
         TRACE(("gdth_interrupt() sync. status\n"));
-        rval = gdth_sync_event(hanum,Service,IStatus,scp);
+        rval = gdth_sync_event(ha,Service,IStatus,scp);
         if (!gdth_polling)
-            spin_unlock_irqrestore(&ha2->smp_lock, flags);
+            spin_unlock_irqrestore(&ha->smp_lock, flags);
         if (rval == 2) {
-            gdth_putq(hanum,scp,scp->SCp.this_residual);
+            gdth_putq(ha, scp, gdth_cmnd_priv(scp)->priority);
         } else if (rval == 1) {
-            scp->scsi_done(scp);
+            gdth_scsi_done(scp);
         }
 
 #ifdef INT_COAL
@@ -3653,23 +3283,30 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
 
     /* coalescing only for new GDT_PCIMPR controllers available */      
     if (ha->type == GDT_PCIMPR && coalesced) {
-        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
-        gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        writeb(0, &dp6m_ptr->i960r.sema1_reg);
     }
 #endif
 
-    gdth_next(hanum);
+    gdth_next(ha);
     return IRQ_HANDLED;
 }
 
-static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
+static irqreturn_t gdth_interrupt(int irq, void *dev_id)
+{
+       gdth_ha_str *ha = (gdth_ha_str *)dev_id;
+
+       return __gdth_interrupt(ha, irq, false, NULL);
+}
+
+static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+                                                              Scsi_Cmnd *scp)
 {
-    register gdth_ha_str *ha;
     gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
     unchar b, t;
+    struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
 
-    ha   = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
     TRACE(("gdth_sync_event() serv %d status %d\n",
            service,ha->status));
@@ -3687,12 +3324,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
             }
 
         if (msg->msg_ext && !msg->msg_answer) {
-            while (gdth_test_busy(hanum))
+            while (gdth_test_busy(ha))
                 gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
             cmdp->RequestBuffer = SCREEN_CMND;
-            gdth_get_cmd_index(hanum);
-            gdth_set_sema0(hanum);
+            gdth_get_cmd_index(ha);
+            gdth_set_sema0(ha);
             cmdp->OpCode        = GDT_READ;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
@@ -3702,8 +3339,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong64);
             ha->cmd_cnt = 0;
-            gdth_copy_command(hanum);
-            gdth_release_event(hanum);
+            gdth_copy_command(ha);
+            gdth_release_event(ha);
             return 0;
         }
 
@@ -3721,12 +3358,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
             }
             msg->msg_ext    = 0;
             msg->msg_answer = 0;
-            while (gdth_test_busy(hanum))
+            while (gdth_test_busy(ha))
                 gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
             cmdp->RequestBuffer = SCREEN_CMND;
-            gdth_get_cmd_index(hanum);
-            gdth_set_sema0(hanum);
+            gdth_get_cmd_index(ha);
+            gdth_set_sema0(ha);
             cmdp->OpCode        = GDT_WRITE;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
@@ -3736,74 +3373,67 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong64);
             ha->cmd_cnt = 0;
-            gdth_copy_command(hanum);
-            gdth_release_event(hanum);
+            gdth_copy_command(ha);
+            gdth_release_event(ha);
             return 0;
         }
         printk("\n");
 
     } else {
-        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        b = scp->device->channel;
         t = scp->device->id;
-        if (scp->SCp.sent_command == -1 && b != ha->virt_bus) {
+        if (cmndinfo->OpCode == -1 && b != ha->virt_bus) {
             ha->raw[BUS_L2P(ha,b)].io_cnt[t]--;
         }
         /* cache or raw service */
         if (ha->status == S_BSY) {
             TRACE2(("Controller busy -> retry !\n"));
-            if (scp->SCp.sent_command == GDT_MOUNT)
-                scp->SCp.sent_command = GDT_CLUST_INFO;
+            if (cmndinfo->OpCode == GDT_MOUNT)
+                cmndinfo->OpCode = GDT_CLUST_INFO;
             /* retry */
             return 2;
         }
-        if (scp->SCp.Status == GDTH_MAP_SG) 
-            pci_unmap_sg(ha->pdev,scp->request_buffer,
-                         scp->use_sg,scp->SCp.Message);
-        else if (scp->SCp.Status == GDTH_MAP_SINGLE) 
-            pci_unmap_page(ha->pdev,scp->SCp.dma_handle,
-                           scp->request_bufflen,scp->SCp.Message);
-        if (scp->SCp.buffer) {
-            dma_addr_t addr;
-            addr = (dma_addr_t)*(ulong32 *)&scp->SCp.buffer;
-            if (scp->host_scribble)
-                addr += (dma_addr_t)
-                    ((ulong64)(*(ulong32 *)&scp->host_scribble) << 32);
-            pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE);
-        }
+        if (gdth_bufflen(scp))
+            pci_unmap_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+                         cmndinfo->dma_dir);
+
+        if (cmndinfo->sense_paddr)
+            pci_unmap_page(ha->pdev, cmndinfo->sense_paddr, 16,
+                                                           PCI_DMA_FROMDEVICE);
 
         if (ha->status == S_OK) {
-            scp->SCp.Status = S_OK;
-            scp->SCp.Message = ha->info;
-            if (scp->SCp.sent_command != -1) {
+            cmndinfo->status = S_OK;
+            cmndinfo->info = ha->info;
+            if (cmndinfo->OpCode != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
-                        scp->SCp.sent_command));
+                        cmndinfo->OpCode));
                 /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
-                if (scp->SCp.sent_command == GDT_CLUST_INFO) {
+                if (cmndinfo->OpCode == GDT_CLUST_INFO) {
                     ha->hdr[t].cluster_type = (unchar)ha->info;
                     if (!(ha->hdr[t].cluster_type & 
                         CLUSTER_MOUNTED)) {
                         /* NOT MOUNTED -> MOUNT */
-                        scp->SCp.sent_command = GDT_MOUNT;
+                        cmndinfo->OpCode = GDT_MOUNT;
                         if (ha->hdr[t].cluster_type & 
                             CLUSTER_RESERVED) {
                             /* cluster drive RESERVED (on the other node) */
-                            scp->SCp.phase = -2;      /* reservation conflict */
+                            cmndinfo->phase = -2;      /* reservation conflict */
                         }
                     } else {
-                        scp->SCp.sent_command = -1;
+                        cmndinfo->OpCode = -1;
                     }
                 } else {
-                    if (scp->SCp.sent_command == GDT_MOUNT) {
+                    if (cmndinfo->OpCode == GDT_MOUNT) {
                         ha->hdr[t].cluster_type |= CLUSTER_MOUNTED;
                         ha->hdr[t].media_changed = TRUE;
-                    } else if (scp->SCp.sent_command == GDT_UNMOUNT) {
+                    } else if (cmndinfo->OpCode == GDT_UNMOUNT) {
                         ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED;
                         ha->hdr[t].media_changed = TRUE;
                     } 
-                    scp->SCp.sent_command = -1;
+                    cmndinfo->OpCode = -1;
                 }
                 /* retry */
-                scp->SCp.this_residual = HIGH_PRI;
+                cmndinfo->priority = HIGH_PRI;
                 return 2;
             } else {
                 /* RESERVE/RELEASE ? */
@@ -3816,17 +3446,17 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
                 scp->sense_buffer[0] = 0;
             }
         } else {
-            scp->SCp.Status = ha->status;
-            scp->SCp.Message = ha->info;
+            cmndinfo->status = ha->status;
+            cmndinfo->info = ha->info;
 
-            if (scp->SCp.sent_command != -1) {
+            if (cmndinfo->OpCode != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
-                        scp->SCp.sent_command, ha->status));
-                if (scp->SCp.sent_command == GDT_SCAN_START ||
-                    scp->SCp.sent_command == GDT_SCAN_END) {
-                    scp->SCp.sent_command = -1;
+                        cmndinfo->OpCode, ha->status));
+                if (cmndinfo->OpCode == GDT_SCAN_START ||
+                    cmndinfo->OpCode == GDT_SCAN_END) {
+                    cmndinfo->OpCode = -1;
                     /* retry */
-                    scp->SCp.this_residual = HIGH_PRI;
+                    cmndinfo->priority = HIGH_PRI;
                     return 2;
                 }
                 memset((char*)scp->sense_buffer,0,16);
@@ -3848,9 +3478,9 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
                     scp->sense_buffer[2] = NOT_READY;
                     scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
                 }
-                if (scp->done != gdth_scsi_done) {
+                if (!cmndinfo->internal_command) {
                     ha->dvr.size = sizeof(ha->dvr.eu.sync);
-                    ha->dvr.eu.sync.ionode  = hanum;
+                    ha->dvr.eu.sync.ionode  = ha->hanum;
                     ha->dvr.eu.sync.service = service;
                     ha->dvr.eu.sync.status  = ha->status;
                     ha->dvr.eu.sync.info    = ha->info;
@@ -3869,8 +3499,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
                 }
             }
         }
-        if (!scp->SCp.have_data_in)
-            scp->SCp.have_data_in++;
+        if (!cmndinfo->wait_for_completion)
+            cmndinfo->wait_for_completion++;
         else 
             return 1;
     }
@@ -4034,25 +3664,23 @@ static char *async_cache_tab[] = {
 };
 
 
-static int gdth_async_event(int hanum)
+static int gdth_async_event(gdth_ha_str *ha)
 {
-    gdth_ha_str *ha;
     gdth_cmd_str *cmdp;
     int cmd_index;
 
-    ha  = HADATA(gdth_ctr_tab[hanum]);
     cmdp= ha->pccb;
     TRACE2(("gdth_async_event() ha %d serv %d\n",
-            hanum,ha->service));
+            ha->hanum, ha->service));
 
     if (ha->service == SCREENSERVICE) {
         if (ha->status == MSG_REQUEST) {
-            while (gdth_test_busy(hanum))
+            while (gdth_test_busy(ha))
                 gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
             cmdp->RequestBuffer = SCREEN_CMND;
-            cmd_index = gdth_get_cmd_index(hanum);
-            gdth_set_sema0(hanum);
+            cmd_index = gdth_get_cmd_index(ha);
+            gdth_set_sema0(ha);
             cmdp->OpCode        = GDT_READ;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
@@ -4062,7 +3690,7 @@ static int gdth_async_event(int hanum)
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong64);
             ha->cmd_cnt = 0;
-            gdth_copy_command(hanum);
+            gdth_copy_command(ha);
             if (ha->type == GDT_EISA)
                 printk("[EISA slot %d] ",(ushort)ha->brd_phys);
             else if (ha->type == GDT_ISA)
@@ -4070,19 +3698,19 @@ static int gdth_async_event(int hanum)
             else 
                 printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
                        (ushort)((ha->brd_phys>>3)&0x1f));
-            gdth_release_event(hanum);
+            gdth_release_event(ha);
         }
 
     } else {
         if (ha->type == GDT_PCIMPR && 
             (ha->fw_vers & 0xff) >= 0x1a) {
             ha->dvr.size = 0;
-            ha->dvr.eu.async.ionode = hanum;
+            ha->dvr.eu.async.ionode = ha->hanum;
             ha->dvr.eu.async.status  = ha->status;
             /* severity and event_string already set! */
         } else {        
             ha->dvr.size = sizeof(ha->dvr.eu.async);
-            ha->dvr.eu.async.ionode   = hanum;
+            ha->dvr.eu.async.ionode   = ha->hanum;
             ha->dvr.eu.async.service = ha->service;
             ha->dvr.eu.async.status  = ha->status;
             ha->dvr.eu.async.info    = ha->info;
@@ -4164,9 +3792,8 @@ static void gdth_timeout(ulong data)
     Scsi_Cmnd *nscp;
     gdth_ha_str *ha;
     ulong flags;
-    int hanum = 0;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    ha = list_first_entry(&gdth_instances, gdth_ha_str, list);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i) 
@@ -4229,8 +3856,6 @@ static void __init internal_setup(char *str,int *ints)
             max_ids = val;
         else if (!strncmp(argv, "rescan:", 7))
             rescan = val;
-        else if (!strncmp(argv, "virt_ctr:", 9))
-            virt_ctr = val;
         else if (!strncmp(argv, "shared_access:", 14))
             shared_access = val;
         else if (!strncmp(argv, "probe_eisa_isa:", 15))
@@ -4277,523 +3902,10 @@ int __init option_setup(char *str)
     return 1;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-static int __init gdth_detect(struct scsi_host_template *shtp)
-#else
-static int __init gdth_detect(Scsi_Host_Template *shtp)
-#endif
+static const char *gdth_ctr_name(gdth_ha_str *ha)
 {
-    struct Scsi_Host *shp;
-    gdth_pci_str pcistr[MAXHA];
-    gdth_ha_str *ha;
-    ulong32 isa_bios;
-    ushort eisa_slot;
-    int i,hanum,cnt,ctr,err;
-    unchar b;
-    
-#ifdef DEBUG_GDTH
-    printk("GDT: This driver contains debugging information !! Trace level = %d\n",
-        DebugState);
-    printk("     Destination of debugging information: ");
-#ifdef __SERIAL__
-#ifdef __COM2__
-    printk("Serial port COM2\n");
-#else
-    printk("Serial port COM1\n");
-#endif
-#else
-    printk("Console\n");
-#endif
-    gdth_delay(3000);
-#endif
-
-    TRACE(("gdth_detect()\n"));
-
-    if (disable) {
-        printk("GDT-HA: Controller driver disabled from command line !\n");
-        return 0;
-    }
-
-    printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n",GDTH_VERSION_STR);
-    /* initializations */
-    gdth_polling = TRUE; b = 0;
-    gdth_clear_events();
-
-    /* As default we do not probe for EISA or ISA controllers */
-    if (probe_eisa_isa) {    
-        /* scanning for controllers, at first: ISA controller */
-        for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
-            dma_addr_t scratch_dma_handle;
-            scratch_dma_handle = 0;
-
-            if (gdth_ctr_count >= MAXHA) 
-                break;
-            if (gdth_search_isa(isa_bios)) {        /* controller found */
-                shp = scsi_register(shtp,sizeof(gdth_ext_str));
-                if (shp == NULL)
-                    continue;  
-
-                ha = HADATA(shp);
-                if (!gdth_init_isa(isa_bios,ha)) {
-                    scsi_unregister(shp);
-                    continue;
-                }
-#ifdef __ia64__
-                break;
-#else
-                /* controller found and initialized */
-                printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
-                       isa_bios,ha->irq,ha->drq);
-
-                if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
-                    printk("GDT-ISA: Unable to allocate IRQ\n");
-                    scsi_unregister(shp);
-                    continue;
-                }
-                if (request_dma(ha->drq,"gdth")) {
-                    printk("GDT-ISA: Unable to allocate DMA channel\n");
-                    free_irq(ha->irq,ha);
-                    scsi_unregister(shp);
-                    continue;
-                }
-                set_dma_mode(ha->drq,DMA_MODE_CASCADE);
-                enable_dma(ha->drq);
-                shp->unchecked_isa_dma = 1;
-                shp->irq = ha->irq;
-                shp->dma_channel = ha->drq;
-                hanum = gdth_ctr_count;         
-                gdth_ctr_tab[gdth_ctr_count++] = shp;
-                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
-                NUMDATA(shp)->hanum = (ushort)hanum;
-                NUMDATA(shp)->busnum= 0;
-
-                ha->pccb = CMDDATA(shp);
-                ha->ccb_phys = 0L;
-                ha->pdev = NULL;
-                ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
-                                                    &scratch_dma_handle);
-                ha->scratch_phys = scratch_dma_handle;
-                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
-                                                &scratch_dma_handle);
-                ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
-                ha->coal_stat = (gdth_coal_status *)
-                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
-                        MAXOFFSETS, &scratch_dma_handle);
-                ha->coal_stat_phys = scratch_dma_handle;
-#endif
-
-                ha->scratch_busy = FALSE;
-                ha->req_first = NULL;
-                ha->tid_cnt = MAX_HDRIVES;
-                if (max_ids > 0 && max_ids < ha->tid_cnt)
-                    ha->tid_cnt = max_ids;
-                for (i=0; i<GDTH_MAXCMDS; ++i)
-                    ha->cmd_tab[i].cmnd = UNUSED_CMND;
-                ha->scan_mode = rescan ? 0x10 : 0;
-
-                if (ha->pscratch == NULL || ha->pmsg == NULL || 
-                    !gdth_search_drives(hanum)) {
-                    printk("GDT-ISA: Error during device scan\n");
-                    --gdth_ctr_count;
-                    --gdth_ctr_vcount;
-
-#ifdef INT_COAL
-                    if (ha->coal_stat)
-                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
-                                            MAXOFFSETS, ha->coal_stat,
-                                            ha->coal_stat_phys);
-#endif
-                    if (ha->pscratch)
-                        pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
-                                            ha->pscratch, ha->scratch_phys);
-                    if (ha->pmsg)
-                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
-                                            ha->pmsg, ha->msg_phys);
-
-                    free_irq(ha->irq,ha);
-                    scsi_unregister(shp);
-                    continue;
-                }
-                if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
-                    hdr_channel = ha->bus_cnt;
-                ha->virt_bus = hdr_channel;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-                shp->highmem_io  = 0;
-#endif
-                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
-                    shp->max_cmd_len = 16;
-
-                shp->max_id      = ha->tid_cnt;
-                shp->max_lun     = MAXLUN;
-                shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-                if (virt_ctr) {
-                    virt_ctr = 1;
-                    /* register addit. SCSI channels as virtual controllers */
-                    for (b = 1; b < ha->bus_cnt + 1; ++b) {
-                        shp = scsi_register(shtp,sizeof(gdth_num_str));
-                        shp->unchecked_isa_dma = 1;
-                        shp->irq = ha->irq;
-                        shp->dma_channel = ha->drq;
-                        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                        NUMDATA(shp)->hanum = (ushort)hanum;
-                        NUMDATA(shp)->busnum = b;
-                    }
-                }  
-
-                spin_lock_init(&ha->smp_lock);
-                gdth_enable_int(hanum);
-#endif /* !__ia64__ */
-            }
-        }
-
-        /* scanning for EISA controllers */
-        for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
-            dma_addr_t scratch_dma_handle;
-            scratch_dma_handle = 0;
-
-            if (gdth_ctr_count >= MAXHA) 
-                break;
-            if (gdth_search_eisa(eisa_slot)) {      /* controller found */
-                shp = scsi_register(shtp,sizeof(gdth_ext_str));
-                if (shp == NULL)
-                    continue;  
-
-                ha = HADATA(shp);
-                if (!gdth_init_eisa(eisa_slot,ha)) {
-                    scsi_unregister(shp);
-                    continue;
-                }
-                /* controller found and initialized */
-                printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
-                       eisa_slot>>12,ha->irq);
-
-                if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
-                    printk("GDT-EISA: Unable to allocate IRQ\n");
-                    scsi_unregister(shp);
-                    continue;
-                }
-                shp->unchecked_isa_dma = 0;
-                shp->irq = ha->irq;
-                shp->dma_channel = 0xff;
-                hanum = gdth_ctr_count;
-                gdth_ctr_tab[gdth_ctr_count++] = shp;
-                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
-                NUMDATA(shp)->hanum = (ushort)hanum;
-                NUMDATA(shp)->busnum= 0;
-                TRACE2(("EISA detect Bus 0: hanum %d\n",
-                        NUMDATA(shp)->hanum));
-
-                ha->pccb = CMDDATA(shp);
-                ha->ccb_phys = 0L; 
-
-                ha->pdev = NULL;
-                ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
-                                                    &scratch_dma_handle);
-                ha->scratch_phys = scratch_dma_handle;
-                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
-                                                &scratch_dma_handle);
-                ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
-                ha->coal_stat = (gdth_coal_status *)
-                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
-                                         MAXOFFSETS, &scratch_dma_handle);
-                ha->coal_stat_phys = scratch_dma_handle;
-#endif
-                ha->ccb_phys = 
-                    pci_map_single(ha->pdev,ha->pccb,
-                                   sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
-                ha->scratch_busy = FALSE;
-                ha->req_first = NULL;
-                ha->tid_cnt = MAX_HDRIVES;
-                if (max_ids > 0 && max_ids < ha->tid_cnt)
-                    ha->tid_cnt = max_ids;
-                for (i=0; i<GDTH_MAXCMDS; ++i)
-                    ha->cmd_tab[i].cmnd = UNUSED_CMND;
-                ha->scan_mode = rescan ? 0x10 : 0;
-
-                if (ha->pscratch == NULL || ha->pmsg == NULL || 
-                    !gdth_search_drives(hanum)) {
-                    printk("GDT-EISA: Error during device scan\n");
-                    --gdth_ctr_count;
-                    --gdth_ctr_vcount;
-#ifdef INT_COAL
-                    if (ha->coal_stat)
-                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
-                                            MAXOFFSETS, ha->coal_stat,
-                                            ha->coal_stat_phys);
-#endif
-                    if (ha->pscratch)
-                        pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
-                                            ha->pscratch, ha->scratch_phys);
-                    if (ha->pmsg)
-                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
-                                            ha->pmsg, ha->msg_phys);
-                    if (ha->ccb_phys)
-                        pci_unmap_single(ha->pdev,ha->ccb_phys,
-                                        sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
-                    free_irq(ha->irq,ha);
-                    scsi_unregister(shp);
-                    continue;
-                }
-                if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
-                    hdr_channel = ha->bus_cnt;
-                ha->virt_bus = hdr_channel;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-                shp->highmem_io  = 0;
-#endif
-                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
-                    shp->max_cmd_len = 16;
-
-                shp->max_id      = ha->tid_cnt;
-                shp->max_lun     = MAXLUN;
-                shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-                if (virt_ctr) {
-                    virt_ctr = 1;
-                    /* register addit. SCSI channels as virtual controllers */
-                    for (b = 1; b < ha->bus_cnt + 1; ++b) {
-                        shp = scsi_register(shtp,sizeof(gdth_num_str));
-                        shp->unchecked_isa_dma = 0;
-                        shp->irq = ha->irq;
-                        shp->dma_channel = 0xff;
-                        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                        NUMDATA(shp)->hanum = (ushort)hanum;
-                        NUMDATA(shp)->busnum = b;
-                    }
-                }  
-
-                spin_lock_init(&ha->smp_lock);
-                gdth_enable_int(hanum);
-            }
-        }
-    }
-
-    /* scanning for PCI controllers */
-    cnt = gdth_search_pci(pcistr);
-    printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt);
-    gdth_sort_pci(pcistr,cnt);
-    for (ctr = 0; ctr < cnt; ++ctr) {
-        dma_addr_t scratch_dma_handle;
-        scratch_dma_handle = 0;
-
-        if (gdth_ctr_count >= MAXHA)
-            break;
-        shp = scsi_register(shtp,sizeof(gdth_ext_str));
-        if (shp == NULL)
-            continue;  
-
-        ha = HADATA(shp);
-        if (!gdth_init_pci(&pcistr[ctr],ha)) {
-            scsi_unregister(shp);
-            continue;
-        }
-        /* controller found and initialized */
-        printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
-               pcistr[ctr].pdev->bus->number,
-              PCI_SLOT(pcistr[ctr].pdev->devfn), ha->irq);
-
-        if (request_irq(ha->irq, gdth_interrupt,
-                        IRQF_DISABLED|IRQF_SHARED, "gdth", ha))
-        {
-            printk("GDT-PCI: Unable to allocate IRQ\n");
-            scsi_unregister(shp);
-            continue;
-        }
-        shp->unchecked_isa_dma = 0;
-        shp->irq = ha->irq;
-        shp->dma_channel = 0xff;
-        hanum = gdth_ctr_count;
-        gdth_ctr_tab[gdth_ctr_count++] = shp;
-        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
-        NUMDATA(shp)->hanum = (ushort)hanum;
-        NUMDATA(shp)->busnum= 0;
-
-        ha->pccb = CMDDATA(shp);
-        ha->ccb_phys = 0L;
-
-        ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
-                                            &scratch_dma_handle);
-        ha->scratch_phys = scratch_dma_handle;
-        ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
-                                        &scratch_dma_handle);
-        ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
-        ha->coal_stat = (gdth_coal_status *)
-            pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
-                                 MAXOFFSETS, &scratch_dma_handle);
-        ha->coal_stat_phys = scratch_dma_handle;
-#endif
-        ha->scratch_busy = FALSE;
-        ha->req_first = NULL;
-        ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
-        if (max_ids > 0 && max_ids < ha->tid_cnt)
-            ha->tid_cnt = max_ids;
-        for (i=0; i<GDTH_MAXCMDS; ++i)
-            ha->cmd_tab[i].cmnd = UNUSED_CMND;
-        ha->scan_mode = rescan ? 0x10 : 0;
-
-        err = FALSE;
-        if (ha->pscratch == NULL || ha->pmsg == NULL || 
-            !gdth_search_drives(hanum)) {
-            err = TRUE;
-        } else {
-            if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
-                hdr_channel = ha->bus_cnt;
-            ha->virt_bus = hdr_channel;
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-            scsi_set_pci_device(shp, pcistr[ctr].pdev);
-#endif
-            if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)||
-                /* 64-bit DMA only supported from FW >= x.43 */
-                (!ha->dma64_support)) {
-                if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
-                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum);
-                    err = TRUE;
-                }
-            } else {
-                shp->max_cmd_len = 16;
-                if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) {
-                    printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum);
-                } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
-                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum);
-                    err = TRUE;
-                }
-            }
-        }
-
-        if (err) {
-            printk("GDT-PCI %d: Error during device scan\n", hanum);
-            --gdth_ctr_count;
-            --gdth_ctr_vcount;
-#ifdef INT_COAL
-            if (ha->coal_stat)
-                pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
-                                    MAXOFFSETS, ha->coal_stat,
-                                    ha->coal_stat_phys);
-#endif
-            if (ha->pscratch)
-                pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
-                                    ha->pscratch, ha->scratch_phys);
-            if (ha->pmsg)
-                pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
-                                    ha->pmsg, ha->msg_phys);
-            free_irq(ha->irq,ha);
-            scsi_unregister(shp);
-            continue;
-        }
-
-        shp->max_id      = ha->tid_cnt;
-        shp->max_lun     = MAXLUN;
-        shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-        if (virt_ctr) {
-            virt_ctr = 1;
-            /* register addit. SCSI channels as virtual controllers */
-            for (b = 1; b < ha->bus_cnt + 1; ++b) {
-                shp = scsi_register(shtp,sizeof(gdth_num_str));
-                shp->unchecked_isa_dma = 0;
-                shp->irq = ha->irq;
-                shp->dma_channel = 0xff;
-                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                NUMDATA(shp)->hanum = (ushort)hanum;
-                NUMDATA(shp)->busnum = b;
-            }
-        }  
-
-        spin_lock_init(&ha->smp_lock);
-        gdth_enable_int(hanum);
-    }
-    
-    TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
-    if (gdth_ctr_count > 0) {
-#ifdef GDTH_STATISTICS
-        TRACE2(("gdth_detect(): Initializing timer !\n"));
-        init_timer(&gdth_timer);
-        gdth_timer.expires = jiffies + HZ;
-        gdth_timer.data = 0L;
-        gdth_timer.function = gdth_timeout;
-        add_timer(&gdth_timer);
-#endif
-        major = register_chrdev(0,"gdth",&gdth_fops);
-        notifier_disabled = 0;
-        register_reboot_notifier(&gdth_notifier);
-    }
-    gdth_polling = FALSE;
-    return gdth_ctr_vcount;
-}
-
-static int gdth_release(struct Scsi_Host *shp)
-{
-    int hanum;
-    gdth_ha_str *ha;
-
-    TRACE2(("gdth_release()\n"));
-    if (NUMDATA(shp)->busnum == 0) {
-        hanum = NUMDATA(shp)->hanum;
-        ha    = HADATA(gdth_ctr_tab[hanum]);
-        if (ha->sdev) {
-            scsi_free_host_dev(ha->sdev);
-            ha->sdev = NULL;
-        }
-        gdth_flush(hanum);
-
-        if (shp->irq) {
-            free_irq(shp->irq,ha);
-        }
-#ifndef __ia64__
-        if (shp->dma_channel != 0xff) {
-            free_dma(shp->dma_channel);
-        }
-#endif
-#ifdef INT_COAL
-        if (ha->coal_stat)
-            pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
-                                MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
-#endif
-        if (ha->pscratch)
-            pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
-                                ha->pscratch, ha->scratch_phys);
-        if (ha->pmsg)
-            pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
-                                ha->pmsg, ha->msg_phys);
-        if (ha->ccb_phys)
-            pci_unmap_single(ha->pdev,ha->ccb_phys,
-                             sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
-        gdth_ctr_released++;
-        TRACE2(("gdth_release(): HA %d of %d\n", 
-                gdth_ctr_released, gdth_ctr_count));
-
-        if (gdth_ctr_released == gdth_ctr_count) {
-#ifdef GDTH_STATISTICS
-            del_timer(&gdth_timer);
-#endif
-            unregister_chrdev(major,"gdth");
-            unregister_reboot_notifier(&gdth_notifier);
-        }
-    }
-
-    scsi_unregister(shp);
-    return 0;
-}
-            
-
-static const char *gdth_ctr_name(int hanum)
-{
-    gdth_ha_str *ha;
-
     TRACE2(("gdth_ctr_name()\n"));
 
-    ha    = HADATA(gdth_ctr_tab[hanum]);
-
     if (ha->type == GDT_EISA) {
         switch (ha->stype) {
           case GDT3_ID:
@@ -4820,29 +3932,23 @@ static const char *gdth_ctr_name(int hanum)
 
 static const char *gdth_info(struct Scsi_Host *shp)
 {
-    int hanum;
-    gdth_ha_str *ha;
+    gdth_ha_str *ha = shost_priv(shp);
 
     TRACE2(("gdth_info()\n"));
-    hanum = NUMDATA(shp)->hanum;
-    ha    = HADATA(gdth_ctr_tab[hanum]);
-
     return ((const char *)ha->binfo.type_string);
 }
 
 static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
 {
-    int i, hanum;
-    gdth_ha_str *ha;
+    gdth_ha_str *ha = shost_priv(scp->device->host);
+    int i;
     ulong flags;
     Scsi_Cmnd *cmnd;
     unchar b;
 
     TRACE2(("gdth_eh_bus_reset()\n"));
 
-    hanum = NUMDATA(scp->device->host)->hanum;
-    b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
-    ha    = HADATA(gdth_ctr_tab[hanum]);
+    b = scp->device->channel;
 
     /* clear command tab */
     spin_lock_irqsave(&ha->smp_lock, flags);
@@ -4859,9 +3965,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
             if (ha->hdr[i].present) {
                 spin_lock_irqsave(&ha->smp_lock, flags);
                 gdth_polling = TRUE;
-                while (gdth_test_busy(hanum))
+                while (gdth_test_busy(ha))
                     gdth_delay(0);
-                if (gdth_internal_cmd(hanum, CACHESERVICE, 
+                if (gdth_internal_cmd(ha, CACHESERVICE,
                                       GDT_CLUST_RESET, i, 0, 0))
                     ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED;
                 gdth_polling = FALSE;
@@ -4874,9 +3980,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
         for (i = 0; i < MAXID; ++i)
             ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0;
         gdth_polling = TRUE;
-        while (gdth_test_busy(hanum))
+        while (gdth_test_busy(ha))
             gdth_delay(0);
-        gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+        gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESET_BUS,
                           BUS_L2P(ha,b), 0, 0);
         gdth_polling = FALSE;
         spin_unlock_irqrestore(&ha->smp_lock, flags);
@@ -4884,30 +3990,18 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
     return SUCCESS;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
-#else
-static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
-#endif
 {
     unchar b, t;
-    int hanum;
-    gdth_ha_str *ha;
+    gdth_ha_str *ha = shost_priv(sdev->host);
     struct scsi_device *sd;
     unsigned capacity;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     sd = sdev;
     capacity = cap;
-#else
-    sd = disk->device;
-    capacity = disk->capacity;
-#endif
-    hanum = NUMDATA(sd->host)->hanum;
-    b = virt_ctr ? NUMDATA(sd->host)->busnum : sd->channel;
+    b = sd->channel;
     t = sd->id;
-    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); 
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", ha->hanum, b, t));
 
     if (b != ha->virt_bus || ha->hdr[t].heads == 0) {
         /* raw device or host drive without mapping information */
@@ -4925,33 +4019,42 @@ static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
 }
 
 
-static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
+static int gdth_queuecommand(struct scsi_cmnd *scp,
+                               void (*done)(struct scsi_cmnd *))
 {
-    int hanum;
-    int priority;
+    gdth_ha_str *ha = shost_priv(scp->device->host);
+    struct gdth_cmndinfo *cmndinfo;
 
     TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0]));
-    
-    scp->scsi_done = (void *)done;
-    scp->SCp.have_data_in = 1;
-    scp->SCp.phase = -1;
-    scp->SCp.sent_command = -1;
-    scp->SCp.Status = GDTH_MAP_NONE;
-    scp->SCp.buffer = (struct scatterlist *)NULL;
-
-    hanum = NUMDATA(scp->device->host)->hanum;
+
+    cmndinfo = gdth_get_cmndinfo(ha);
+    BUG_ON(!cmndinfo);
+
+    scp->scsi_done = done;
+    gdth_update_timeout(scp, scp->timeout_per_command * 6);
+    cmndinfo->priority = DEFAULT_PRI;
+
+    gdth_set_bufflen(scp, scsi_bufflen(scp));
+    gdth_set_sg_count(scp, scsi_sg_count(scp));
+    gdth_set_sglist(scp, scsi_sglist(scp));
+
+    return __gdth_queuecommand(ha, scp, cmndinfo);
+}
+
+static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
+                               struct gdth_cmndinfo *cmndinfo)
+{
+    scp->host_scribble = (unsigned char *)cmndinfo;
+    cmndinfo->wait_for_completion = 1;
+    cmndinfo->phase = -1;
+    cmndinfo->OpCode = -1;
+
 #ifdef GDTH_STATISTICS
     ++act_ios;
 #endif
 
-    priority = DEFAULT_PRI;
-    if (scp->done == gdth_scsi_done)
-        priority = scp->SCp.this_residual;
-    else
-        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
-
-    gdth_putq( hanum, scp, priority );
-    gdth_next( hanum );
+    gdth_putq(ha, scp, cmndinfo->priority);
+    gdth_next(ha);
     return 0;
 }
 
@@ -4959,12 +4062,10 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
 static int gdth_open(struct inode *inode, struct file *filep)
 {
     gdth_ha_str *ha;
-    int i;
 
-    for (i = 0; i < gdth_ctr_count; i++) {
-        ha = HADATA(gdth_ctr_tab[i]);
+    list_for_each_entry(ha, &gdth_instances, list) {
         if (!ha->sdev)
-            ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]);
+            ha->sdev = scsi_get_host_dev(ha->shost);
     }
 
     TRACE(("gdth_open()\n"));
@@ -4983,10 +4084,11 @@ static int ioc_event(void __user *arg)
     gdth_ha_str *ha;
     ulong flags;
 
-    if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)) ||
-        evt.ionode >= gdth_ctr_count)
+    if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)))
+        return -EFAULT;
+    ha = gdth_find_ha(evt.ionode);
+    if (!ha)
         return -EFAULT;
-    ha = HADATA(gdth_ctr_tab[evt.ionode]);
 
     if (evt.erase == 0xff) {
         if (evt.event.event_source == ES_TEST)
@@ -5020,11 +4122,12 @@ static int ioc_lockdrv(void __user *arg)
     ulong flags;
     gdth_ha_str *ha;
 
-    if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)) ||
-        ldrv.ionode >= gdth_ctr_count)
+    if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)))
         return -EFAULT;
-    ha = HADATA(gdth_ctr_tab[ldrv.ionode]);
+    ha = gdth_find_ha(ldrv.ionode);
+    if (!ha)
+        return -EFAULT;
+
     for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) {
         j = ldrv.drives[i];
         if (j >= MAX_HDRIVES || !ha->hdr[j].present)
@@ -5033,14 +4136,14 @@ static int ioc_lockdrv(void __user *arg)
             spin_lock_irqsave(&ha->smp_lock, flags);
             ha->hdr[j].lock = 1;
             spin_unlock_irqrestore(&ha->smp_lock, flags);
-            gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j); 
-            gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j); 
+            gdth_wait_completion(ha, ha->bus_cnt, j);
+            gdth_stop_timeout(ha, ha->bus_cnt, j);
         } else {
             spin_lock_irqsave(&ha->smp_lock, flags);
             ha->hdr[j].lock = 0;
             spin_unlock_irqrestore(&ha->smp_lock, flags);
-            gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j); 
-            gdth_next(ldrv.ionode); 
+            gdth_start_timeout(ha, ha->bus_cnt, j);
+            gdth_next(ha);
         }
     } 
     return 0;
@@ -5050,16 +4153,16 @@ static int ioc_resetdrv(void __user *arg, char *cmnd)
 {
     gdth_ioctl_reset res;
     gdth_cmd_str cmd;
-    int hanum;
     gdth_ha_str *ha;
     int rval;
 
     if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) ||
-        res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES)
+        res.number >= MAX_HDRIVES)
         return -EFAULT;
-    hanum = res.ionode;
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    ha = gdth_find_ha(res.ionode);
+    if (!ha)
+        return -EFAULT;
+
     if (!ha->hdr[res.number].present)
         return 0;
     memset(&cmd, 0, sizeof(gdth_cmd_str));
@@ -5085,22 +4188,21 @@ static int ioc_general(void __user *arg, char *cmnd)
     gdth_ioctl_general gen;
     char *buf = NULL;
     ulong64 paddr; 
-    int hanum;
     gdth_ha_str *ha;
     int rval;
-        
-    if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)) ||
-        gen.ionode >= gdth_ctr_count)
+
+    if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)))
+        return -EFAULT;
+    ha = gdth_find_ha(gen.ionode);
+    if (!ha)
         return -EFAULT;
-    hanum = gen.ionode; 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     if (gen.data_len + gen.sense_len != 0) {
-        if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, 
+        if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len,
                                      FALSE, &paddr)))
             return -EFAULT;
         if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general),  
                            gen.data_len + gen.sense_len)) {
-            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
             return -EFAULT;
         }
 
@@ -5174,7 +4276,7 @@ static int ioc_general(void __user *arg, char *cmnd)
                 gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len;
             }
         } else {
-            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
             return -EFAULT;
         }
     }
@@ -5186,15 +4288,15 @@ static int ioc_general(void __user *arg, char *cmnd)
 
     if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, 
                      gen.data_len + gen.sense_len)) {
-        gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+        gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
         return -EFAULT; 
     } 
     if (copy_to_user(arg, &gen, 
         sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
-        gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+        gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
         return -EFAULT;
     }
-    gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+    gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
     return 0;
 }
  
@@ -5204,7 +4306,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd)
     gdth_cmd_str *cmd;
     gdth_ha_str *ha;
     unchar i;
-    int hanum, rc = -ENOMEM;
+    int rc = -ENOMEM;
     u32 cluster_type = 0;
 
     rsc = kmalloc(sizeof(*rsc), GFP_KERNEL);
@@ -5213,12 +4315,10 @@ static int ioc_hdrlist(void __user *arg, char *cmnd)
         goto free_fail;
 
     if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
-        rsc->ionode >= gdth_ctr_count) {
+        (NULL == (ha = gdth_find_ha(rsc->ionode)))) {
         rc = -EFAULT;
         goto free_fail;
     }
-    hanum = rsc->ionode;
-    ha = HADATA(gdth_ctr_tab[hanum]);
     memset(cmd, 0, sizeof(gdth_cmd_str));
    
     for (i = 0; i < MAX_HDRIVES; ++i) { 
@@ -5259,7 +4359,7 @@ static int ioc_rescan(void __user *arg, char *cmnd)
     gdth_cmd_str *cmd;
     ushort i, status, hdr_cnt;
     ulong32 info;
-    int hanum, cyls, hds, secs;
+    int cyls, hds, secs;
     int rc = -ENOMEM;
     ulong flags;
     gdth_ha_str *ha; 
@@ -5270,12 +4370,10 @@ static int ioc_rescan(void __user *arg, char *cmnd)
         goto free_fail;
 
     if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
-        rsc->ionode >= gdth_ctr_count) {
+        (NULL == (ha = gdth_find_ha(rsc->ionode)))) {
         rc = -EFAULT;
         goto free_fail;
     }
-    hanum = rsc->ionode;
-    ha = HADATA(gdth_ctr_tab[hanum]);
     memset(cmd, 0, sizeof(gdth_cmd_str));
 
     if (rsc->flag == 0) {
@@ -5432,9 +4530,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
         gdth_ioctl_ctrtype ctrt;
         
         if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) ||
-            ctrt.ionode >= gdth_ctr_count)
+            (NULL == (ha = gdth_find_ha(ctrt.ionode))))
             return -EFAULT;
-        ha = HADATA(gdth_ctr_tab[ctrt.ionode]);
+
         if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
             ctrt.type = (unchar)((ha->stype>>20) - 0x10);
         } else {
@@ -5473,10 +4571,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
         unchar i, j;
 
         if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) ||
-            lchn.ionode >= gdth_ctr_count)
+            (NULL == (ha = gdth_find_ha(lchn.ionode))))
             return -EFAULT;
-        ha = HADATA(gdth_ctr_tab[lchn.ionode]);
-        
+
         i = lchn.channel;
         if (i < ha->bus_cnt) {
             if (lchn.lock) {
@@ -5484,16 +4581,16 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
                 ha->raw[i].lock = 1;
                 spin_unlock_irqrestore(&ha->smp_lock, flags);
                 for (j = 0; j < ha->tid_cnt; ++j) {
-                    gdth_wait_completion(lchn.ionode, i, j); 
-                    gdth_stop_timeout(lchn.ionode, i, j); 
+                    gdth_wait_completion(ha, i, j);
+                    gdth_stop_timeout(ha, i, j);
                 }
             } else {
                 spin_lock_irqsave(&ha->smp_lock, flags);
                 ha->raw[i].lock = 0;
                 spin_unlock_irqrestore(&ha->smp_lock, flags);
                 for (j = 0; j < ha->tid_cnt; ++j) {
-                    gdth_start_timeout(lchn.ionode, i, j); 
-                    gdth_next(lchn.ionode); 
+                    gdth_start_timeout(ha, i, j);
+                    gdth_next(ha);
                 }
             }
         } 
@@ -5509,37 +4606,22 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
       case GDTIOCTL_RESET_BUS:
       {
         gdth_ioctl_reset res;
-        int hanum, rval;
+        int rval;
 
         if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) ||
-            res.ionode >= gdth_ctr_count)
+            (NULL == (ha = gdth_find_ha(res.ionode))))
             return -EFAULT;
-        hanum = res.ionode; 
-        ha = HADATA(gdth_ctr_tab[hanum]);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-        scp  = kmalloc(sizeof(*scp), GFP_KERNEL);
+        scp  = kzalloc(sizeof(*scp), GFP_KERNEL);
         if (!scp)
             return -ENOMEM;
-        memset(scp, 0, sizeof(*scp));
         scp->device = ha->sdev;
         scp->cmd_len = 12;
-        scp->use_sg = 0;
-        scp->device->channel = virt_ctr ? 0 : res.number;
+        scp->device->channel = res.number;
         rval = gdth_eh_bus_reset(scp);
         res.status = (rval == SUCCESS ? S_OK : S_GENERR);
         kfree(scp);
-#else
-        scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
-        if (!scp)
-            return -ENOMEM;
-        scp->cmd_len = 12;
-        scp->use_sg = 0;
-        scp->channel = virt_ctr ? 0 : res.number;
-        rval = gdth_eh_bus_reset(scp);
-        res.status = (rval == SUCCESS ? S_OK : S_GENERR);
-        scsi_release_command(scp);
-#endif
+
         if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset)))
             return -EFAULT;
         break;
@@ -5556,16 +4638,14 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
 
 
 /* flush routine */
-static void gdth_flush(int hanum)
+static void gdth_flush(gdth_ha_str *ha)
 {
     int             i;
-    gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
     char            cmnd[MAX_COMMAND_SIZE];   
     memset(cmnd, 0xff, MAX_COMMAND_SIZE);
 
-    TRACE2(("gdth_flush() hanum %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE2(("gdth_flush() hanum %d\n", ha->hanum));
 
     for (i = 0; i < MAX_HDRIVES; ++i) {
         if (ha->hdr[i].present) {
@@ -5581,9 +4661,9 @@ static void gdth_flush(int hanum)
                 gdtcmd.u.cache.BlockNo = 1;
                 gdtcmd.u.cache.sg_canz = 0;
             }
-            TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
+            TRACE2(("gdth_flush(): flush ha %d drive %d\n", ha->hanum, i));
 
-            gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 30, NULL);
+            gdth_execute(ha->shost, &gdtcmd, cmnd, 30, NULL);
         }
     }
 }
@@ -5591,7 +4671,7 @@ static void gdth_flush(int hanum)
 /* shutdown routine */
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
 {
-    int             hanum;
+    gdth_ha_str *ha;
 #ifndef __alpha__
     gdth_cmd_str    gdtcmd;
     char            cmnd[MAX_COMMAND_SIZE];   
@@ -5606,8 +4686,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
 
     notifier_disabled = 1;
     printk("GDT-HA: Flushing all host drives .. ");
-    for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
-        gdth_flush(hanum);
+    list_for_each_entry(ha, &gdth_instances, list) {
+        gdth_flush(ha);
 
 #ifndef __alpha__
         /* controller reset */
@@ -5615,8 +4695,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
-        TRACE2(("gdth_halt(): reset controller %d\n", hanum));
-        gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 10, NULL);
+        TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum));
+        gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL);
 #endif
     }
     printk("Done.\n");
@@ -5627,7 +4707,6 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
     return NOTIFY_OK;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 /* configure lun */
 static int gdth_slave_configure(struct scsi_device *sdev)
 {
@@ -5636,40 +4715,540 @@ static int gdth_slave_configure(struct scsi_device *sdev)
     sdev->skip_ms_page_8 = 1;
     return 0;
 }
-#endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-static struct scsi_host_template driver_template = {
-#else
-static Scsi_Host_Template driver_template = {
-#endif
-        .proc_name              = "gdth", 
-        .proc_info              = gdth_proc_info,
+static struct scsi_host_template gdth_template = {
         .name                   = "GDT SCSI Disk Array Controller",
-        .detect                 = gdth_detect, 
-        .release                = gdth_release,
         .info                   = gdth_info, 
         .queuecommand           = gdth_queuecommand,
         .eh_bus_reset_handler   = gdth_eh_bus_reset,
+        .slave_configure        = gdth_slave_configure,
         .bios_param             = gdth_bios_param,
+        .proc_info              = gdth_proc_info,
+        .proc_name              = "gdth",
         .can_queue              = GDTH_MAXCMDS,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-        .slave_configure        = gdth_slave_configure,
-#endif
         .this_id                = -1,
         .sg_tablesize           = GDTH_MAXSG,
         .cmd_per_lun            = GDTH_MAXC_P_L,
         .unchecked_isa_dma      = 1,
         .use_clustering         = ENABLE_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-        .use_new_eh_code        = 1,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
-        .highmem_io             = 1,
+};
+
+#ifdef CONFIG_ISA
+static int gdth_isa_probe_one(ulong32 isa_bios)
+{
+       struct Scsi_Host *shp;
+       gdth_ha_str *ha;
+       dma_addr_t scratch_dma_handle = 0;
+       int error, i;
+
+       if (!gdth_search_isa(isa_bios))
+               return -ENXIO;
+
+       shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+       if (!shp)
+               return -ENOMEM;
+       ha = shost_priv(shp);
+
+       error = -ENODEV;
+       if (!gdth_init_isa(isa_bios,ha))
+               goto out_host_put;
+
+       /* controller found and initialized */
+       printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
+               isa_bios, ha->irq, ha->drq);
+
+       error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+       if (error) {
+               printk("GDT-ISA: Unable to allocate IRQ\n");
+               goto out_host_put;
+       }
+
+       error = request_dma(ha->drq, "gdth");
+       if (error) {
+               printk("GDT-ISA: Unable to allocate DMA channel\n");
+               goto out_free_irq;
+       }
+
+       set_dma_mode(ha->drq,DMA_MODE_CASCADE);
+       enable_dma(ha->drq);
+       shp->unchecked_isa_dma = 1;
+       shp->irq = ha->irq;
+       shp->dma_channel = ha->drq;
+
+       ha->hanum = gdth_ctr_count++;
+       ha->shost = shp;
+
+       ha->pccb = &ha->cmdext;
+       ha->ccb_phys = 0L;
+       ha->pdev = NULL;
+
+       error = -ENOMEM;
+
+       ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+                                               &scratch_dma_handle);
+       if (!ha->pscratch)
+               goto out_dec_counters;
+       ha->scratch_phys = scratch_dma_handle;
+
+       ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+                                               &scratch_dma_handle);
+       if (!ha->pmsg)
+               goto out_free_pscratch;
+       ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+       ha->coal_stat = pci_alloc_consistent(ha->pdev,
+                               sizeof(gdth_coal_status) * MAXOFFSETS,
+                               &scratch_dma_handle);
+       if (!ha->coal_stat)
+               goto out_free_pmsg;
+       ha->coal_stat_phys = scratch_dma_handle;
 #endif
+
+       ha->scratch_busy = FALSE;
+       ha->req_first = NULL;
+       ha->tid_cnt = MAX_HDRIVES;
+       if (max_ids > 0 && max_ids < ha->tid_cnt)
+               ha->tid_cnt = max_ids;
+       for (i = 0; i < GDTH_MAXCMDS; ++i)
+               ha->cmd_tab[i].cmnd = UNUSED_CMND;
+       ha->scan_mode = rescan ? 0x10 : 0;
+
+       error = -ENODEV;
+       if (!gdth_search_drives(ha)) {
+               printk("GDT-ISA: Error during device scan\n");
+               goto out_free_coal_stat;
+       }
+
+       if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+               hdr_channel = ha->bus_cnt;
+       ha->virt_bus = hdr_channel;
+
+       if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
+               shp->max_cmd_len = 16;
+
+       shp->max_id      = ha->tid_cnt;
+       shp->max_lun     = MAXLUN;
+       shp->max_channel = ha->bus_cnt;
+
+       spin_lock_init(&ha->smp_lock);
+       gdth_enable_int(ha);
+
+       error = scsi_add_host(shp, NULL);
+       if (error)
+               goto out_free_coal_stat;
+       list_add_tail(&ha->list, &gdth_instances);
+       return 0;
+
+ out_free_coal_stat:
+#ifdef INT_COAL
+       pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+                               ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
 #endif
-};
+       pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+                               ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+       pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+                               ha->pscratch, ha->scratch_phys);
+ out_dec_counters:
+       gdth_ctr_count--;
+ out_free_irq:
+       free_irq(ha->irq, ha);
+ out_host_put:
+       scsi_host_put(shp);
+       return error;
+}
+#endif /* CONFIG_ISA */
+
+#ifdef CONFIG_EISA
+static int gdth_eisa_probe_one(ushort eisa_slot)
+{
+       struct Scsi_Host *shp;
+       gdth_ha_str *ha;
+       dma_addr_t scratch_dma_handle = 0;
+       int error, i;
+
+       if (!gdth_search_eisa(eisa_slot))
+               return -ENXIO;
+
+       shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+       if (!shp)
+               return -ENOMEM;
+       ha = shost_priv(shp);
+
+       error = -ENODEV;
+       if (!gdth_init_eisa(eisa_slot,ha))
+               goto out_host_put;
+
+       /* controller found and initialized */
+       printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
+               eisa_slot >> 12, ha->irq);
+
+       error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+       if (error) {
+               printk("GDT-EISA: Unable to allocate IRQ\n");
+               goto out_host_put;
+       }
+
+       shp->unchecked_isa_dma = 0;
+       shp->irq = ha->irq;
+       shp->dma_channel = 0xff;
+
+       ha->hanum = gdth_ctr_count++;
+       ha->shost = shp;
+
+       TRACE2(("EISA detect Bus 0: hanum %d\n", ha->hanum));
+
+       ha->pccb = &ha->cmdext;
+       ha->ccb_phys = 0L;
+
+       error = -ENOMEM;
+
+       ha->pdev = NULL;
+       ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+                                               &scratch_dma_handle);
+       if (!ha->pscratch)
+               goto out_free_irq;
+       ha->scratch_phys = scratch_dma_handle;
+
+       ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+                                               &scratch_dma_handle);
+       if (!ha->pmsg)
+               goto out_free_pscratch;
+       ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+       ha->coal_stat = pci_alloc_consistent(ha->pdev,
+                       sizeof(gdth_coal_status) * MAXOFFSETS,
+                       &scratch_dma_handle);
+       if (!ha->coal_stat)
+               goto out_free_pmsg;
+       ha->coal_stat_phys = scratch_dma_handle;
+#endif
+
+       ha->ccb_phys = pci_map_single(ha->pdev,ha->pccb,
+                       sizeof(gdth_cmd_str), PCI_DMA_BIDIRECTIONAL);
+       if (!ha->ccb_phys)
+               goto out_free_coal_stat;
+
+       ha->scratch_busy = FALSE;
+       ha->req_first = NULL;
+       ha->tid_cnt = MAX_HDRIVES;
+       if (max_ids > 0 && max_ids < ha->tid_cnt)
+               ha->tid_cnt = max_ids;
+       for (i = 0; i < GDTH_MAXCMDS; ++i)
+               ha->cmd_tab[i].cmnd = UNUSED_CMND;
+       ha->scan_mode = rescan ? 0x10 : 0;
+
+       if (!gdth_search_drives(ha)) {
+               printk("GDT-EISA: Error during device scan\n");
+               error = -ENODEV;
+               goto out_free_ccb_phys;
+       }
+
+       if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+               hdr_channel = ha->bus_cnt;
+       ha->virt_bus = hdr_channel;
+
+       if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
+               shp->max_cmd_len = 16;
+
+       shp->max_id      = ha->tid_cnt;
+       shp->max_lun     = MAXLUN;
+       shp->max_channel = ha->bus_cnt;
+
+       spin_lock_init(&ha->smp_lock);
+       gdth_enable_int(ha);
+
+       error = scsi_add_host(shp, NULL);
+       if (error)
+               goto out_free_coal_stat;
+       list_add_tail(&ha->list, &gdth_instances);
+       return 0;
+
+ out_free_ccb_phys:
+       pci_unmap_single(ha->pdev,ha->ccb_phys, sizeof(gdth_cmd_str),
+                       PCI_DMA_BIDIRECTIONAL);
+ out_free_coal_stat:
+#ifdef INT_COAL
+       pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+                               ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
+#endif
+       pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+                               ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+       pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+                               ha->pscratch, ha->scratch_phys);
+ out_free_irq:
+       free_irq(ha->irq, ha);
+       gdth_ctr_count--;
+ out_host_put:
+       scsi_host_put(shp);
+       return error;
+}
+#endif /* CONFIG_EISA */
+
+#ifdef CONFIG_PCI
+static int gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr)
+{
+       struct Scsi_Host *shp;
+       gdth_ha_str *ha;
+       dma_addr_t scratch_dma_handle = 0;
+       int error, i;
+
+       shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+       if (!shp)
+               return -ENOMEM;
+       ha = shost_priv(shp);
+
+       error = -ENODEV;
+       if (!gdth_init_pci(&pcistr[ctr],ha))
+               goto out_host_put;
+
+       /* controller found and initialized */
+       printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+               pcistr[ctr].pdev->bus->number,
+               PCI_SLOT(pcistr[ctr].pdev->devfn),
+               ha->irq);
+
+       error = request_irq(ha->irq, gdth_interrupt,
+                               IRQF_DISABLED|IRQF_SHARED, "gdth", ha);
+       if (error) {
+               printk("GDT-PCI: Unable to allocate IRQ\n");
+               goto out_host_put;
+       }
+
+       shp->unchecked_isa_dma = 0;
+       shp->irq = ha->irq;
+       shp->dma_channel = 0xff;
+
+       ha->hanum = gdth_ctr_count++;
+       ha->shost = shp;
+
+       ha->pccb = &ha->cmdext;
+       ha->ccb_phys = 0L;
+
+       error = -ENOMEM;
+
+       ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+                                               &scratch_dma_handle);
+       if (!ha->pscratch)
+               goto out_free_irq;
+       ha->scratch_phys = scratch_dma_handle;
+
+       ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+                                       &scratch_dma_handle);
+       if (!ha->pmsg)
+               goto out_free_pscratch;
+       ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+       ha->coal_stat = pci_alloc_consistent(ha->pdev,
+                       sizeof(gdth_coal_status) * MAXOFFSETS,
+                       &scratch_dma_handle);
+       if (!ha->coal_stat)
+               goto out_free_pmsg;
+       ha->coal_stat_phys = scratch_dma_handle;
+#endif
+
+       ha->scratch_busy = FALSE;
+       ha->req_first = NULL;
+       ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
+       if (max_ids > 0 && max_ids < ha->tid_cnt)
+               ha->tid_cnt = max_ids;
+       for (i = 0; i < GDTH_MAXCMDS; ++i)
+               ha->cmd_tab[i].cmnd = UNUSED_CMND;
+       ha->scan_mode = rescan ? 0x10 : 0;
+
+       error = -ENODEV;
+       if (!gdth_search_drives(ha)) {
+               printk("GDT-PCI %d: Error during device scan\n", ha->hanum);
+               goto out_free_coal_stat;
+       }
+
+       if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+               hdr_channel = ha->bus_cnt;
+       ha->virt_bus = hdr_channel;
+
+       /* 64-bit DMA only supported from FW >= x.43 */
+       if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) ||
+           !ha->dma64_support) {
+               if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
+                       printk(KERN_WARNING "GDT-PCI %d: "
+                               "Unable to set 32-bit DMA\n", ha->hanum);
+                               goto out_free_coal_stat;
+               }
+       } else {
+               shp->max_cmd_len = 16;
+               if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) {
+                       printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum);
+               } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
+                       printk(KERN_WARNING "GDT-PCI %d: "
+                               "Unable to set 64/32-bit DMA\n", ha->hanum);
+                       goto out_free_coal_stat;
+               }
+       }
+
+       shp->max_id      = ha->tid_cnt;
+       shp->max_lun     = MAXLUN;
+       shp->max_channel = ha->bus_cnt;
+
+       spin_lock_init(&ha->smp_lock);
+       gdth_enable_int(ha);
+
+       error = scsi_add_host(shp, &pcistr[ctr].pdev->dev);
+       if (error)
+               goto out_free_coal_stat;
+       list_add_tail(&ha->list, &gdth_instances);
+       return 0;
+
+ out_free_coal_stat:
+#ifdef INT_COAL
+       pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+                               ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
+#endif
+       pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+                               ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+       pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+                               ha->pscratch, ha->scratch_phys);
+ out_free_irq:
+       free_irq(ha->irq, ha);
+       gdth_ctr_count--;
+ out_host_put:
+       scsi_host_put(shp);
+       return error;
+}
+#endif /* CONFIG_PCI */
+
+static void gdth_remove_one(gdth_ha_str *ha)
+{
+       struct Scsi_Host *shp = ha->shost;
+
+       TRACE2(("gdth_remove_one()\n"));
+
+       scsi_remove_host(shp);
+
+       if (ha->sdev) {
+               scsi_free_host_dev(ha->sdev);
+               ha->sdev = NULL;
+       }
+
+       gdth_flush(ha);
+
+       if (shp->irq)
+               free_irq(shp->irq,ha);
+
+#ifdef CONFIG_ISA
+       if (shp->dma_channel != 0xff)
+               free_dma(shp->dma_channel);
+#endif
+#ifdef INT_COAL
+       if (ha->coal_stat)
+               pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                       MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
+#endif
+       if (ha->pscratch)
+               pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+                       ha->pscratch, ha->scratch_phys);
+       if (ha->pmsg)
+               pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+                       ha->pmsg, ha->msg_phys);
+       if (ha->ccb_phys)
+               pci_unmap_single(ha->pdev,ha->ccb_phys,
+                       sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+
+       scsi_host_put(shp);
+}
+
+static int __init gdth_init(void)
+{
+       if (disable) {
+               printk("GDT-HA: Controller driver disabled from"
+                       " command line !\n");
+               return 0;
+       }
+
+       printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n",
+              GDTH_VERSION_STR);
+
+       /* initializations */
+       gdth_polling = TRUE;
+       gdth_clear_events();
+
+       /* As default we do not probe for EISA or ISA controllers */
+       if (probe_eisa_isa) {
+               /* scanning for controllers, at first: ISA controller */
+#ifdef CONFIG_ISA
+               ulong32 isa_bios;
+               for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL;
+                               isa_bios += 0x8000UL)
+                       gdth_isa_probe_one(isa_bios);
+#endif
+#ifdef CONFIG_EISA
+               {
+                       ushort eisa_slot;
+                       for (eisa_slot = 0x1000; eisa_slot <= 0x8000;
+                                                eisa_slot += 0x1000)
+                               gdth_eisa_probe_one(eisa_slot);
+               }
+#endif
+       }
+
+#ifdef CONFIG_PCI
+       /* scanning for PCI controllers */
+       {
+               gdth_pci_str pcistr[MAXHA];
+               int cnt,ctr;
+
+               cnt = gdth_search_pci(pcistr);
+               printk("GDT-HA: Found %d PCI Storage RAID Controllers\n", cnt);
+               gdth_sort_pci(pcistr,cnt);
+               for (ctr = 0; ctr < cnt; ++ctr)
+                       gdth_pci_probe_one(pcistr, ctr);
+       }
+#endif /* CONFIG_PCI */
+
+       TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count));
+
+       if (list_empty(&gdth_instances))
+               return -ENODEV;
+
+#ifdef GDTH_STATISTICS
+       TRACE2(("gdth_detect(): Initializing timer !\n"));
+       init_timer(&gdth_timer);
+       gdth_timer.expires = jiffies + HZ;
+       gdth_timer.data = 0L;
+       gdth_timer.function = gdth_timeout;
+       add_timer(&gdth_timer);
+#endif
+       major = register_chrdev(0,"gdth", &gdth_fops);
+       notifier_disabled = 0;
+       register_reboot_notifier(&gdth_notifier);
+       gdth_polling = FALSE;
+       return 0;
+}
+
+static void __exit gdth_exit(void)
+{
+       gdth_ha_str *ha;
+
+       list_for_each_entry(ha, &gdth_instances, list)
+               gdth_remove_one(ha);
+
+#ifdef GDTH_STATISTICS
+       del_timer(&gdth_timer);
+#endif
+       unregister_chrdev(major,"gdth");
+       unregister_reboot_notifier(&gdth_notifier);
+}
+
+module_init(gdth_init);
+module_exit(gdth_exit);
 
-#include "scsi_module.c"
 #ifndef MODULE
 __setup("gdth=", option_setup);
 #endif
index 37423300592e68825b38798023fffbaf9d572331..1434c6b0297c6977f17c73166ddcd6b9c48bb7ed 100644 (file)
@@ -13,7 +13,6 @@
  * $Id: gdth.h,v 1.58 2006/01/11 16:14:09 achim Exp $
  */
 
-#include <linux/version.h>
 #include <linux/types.h>
 
 #ifndef TRUE
 #define MAILBOXREG      0x0c90                  /* mailbox reg. (16 bytes) */
 #define EISAREG         0x0cc0                  /* EISA configuration */
 
-/* DMA memory mappings */
-#define GDTH_MAP_NONE   0
-#define GDTH_MAP_SINGLE 1
-#define GDTH_MAP_SG     2
-#define GDTH_MAP_IOCTL  3 
-
 /* other defines */
 #define LINUX_OS        8                       /* used for cache optim. */
-#define SCATTER_GATHER  1                       /* s/g feature */
 #define SECS32          0x1f                    /* round capacity */
 #define BIOS_ID_OFFS    0x10                    /* offset contr-ID in ISABIOS */
 #define LOCALBOARD      0                       /* board node always 0 */
@@ -854,6 +846,9 @@ typedef struct {
 
 /* controller information structure */
 typedef struct {
+    struct Scsi_Host    *shost;
+    struct list_head    list;
+    ushort             hanum;
     ushort              oem_id;                 /* OEM */
     ushort              type;                   /* controller class */
     ulong32             stype;                  /* subtype (PCI: device ID) */
@@ -865,6 +860,7 @@ typedef struct {
     void __iomem        *brd;                   /* DPRAM address */
     ulong32             brd_phys;               /* slot number/BIOS address */
     gdt6c_plx_regs      *plx;                   /* PLX regs (new PCI contr.) */
+    gdth_cmd_str        cmdext;
     gdth_cmd_str        *pccb;                  /* address command structure */
     ulong32             ccb_phys;               /* phys. address */
 #ifdef INT_COAL
@@ -916,6 +912,19 @@ typedef struct {
         Scsi_Cmnd       *cmnd;                  /* pending request */
         ushort          service;                /* service */
     } cmd_tab[GDTH_MAXCMDS];                    /* table of pend. requests */
+    struct gdth_cmndinfo {                      /* per-command private info */
+        int index;
+        int internal_command;                   /* don't call scsi_done */
+        dma_addr_t sense_paddr;                 /* sense dma-addr */
+        unchar priority;
+        int timeout;
+        volatile int wait_for_completion;
+        ushort status;
+        ulong32 info;
+        enum dma_data_direction dma_dir;
+        int phase;                              /* ???? */
+        int OpCode;
+    } cmndinfo[GDTH_MAXCMDS];                   /* index==0 is free */
     unchar              bus_cnt;                /* SCSI bus count */
     unchar              tid_cnt;                /* Target ID count */
     unchar              bus_id[MAXBUS];         /* IOP IDs */
@@ -938,19 +947,10 @@ typedef struct {
     struct scsi_device         *sdev;
 } gdth_ha_str;
 
-/* structure for scsi_register(), SCSI bus != 0 */
-typedef struct {
-    ushort      hanum;
-    ushort      busnum;
-} gdth_num_str;
-
-/* structure for scsi_register() */
-typedef struct {
-    gdth_num_str        numext;                 /* must be the first element */
-    gdth_ha_str         haext;
-    gdth_cmd_str        cmdext;
-} gdth_ext_str;
-
+static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd)
+{
+       return (struct gdth_cmndinfo *)cmd->host_scribble;
+}
 
 /* INQUIRY data format */
 typedef struct {
diff --git a/drivers/scsi/gdth_kcompat.h b/drivers/scsi/gdth_kcompat.h
deleted file mode 100644 (file)
index 2a302ee..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef IRQ_HANDLED
-typedef void irqreturn_t;
-#define IRQ_NONE
-#define IRQ_HANDLED
-#endif
-
-#ifndef MODULE_LICENSE
-#define MODULE_LICENSE(x)
-#endif
-
-#ifndef __iomem
-#define __iomem
-#endif
-
-#ifndef __attribute_used__
-#define __attribute_used__     __devinitdata
-#endif
-
-#ifndef __user
-#define __user
-#endif
-
-#ifndef SERVICE_ACTION_IN
-#define SERVICE_ACTION_IN      0x9e
-#endif
-#ifndef READ_16
-#define READ_16                        0x88
-#endif
-#ifndef WRITE_16
-#define WRITE_16               0x8a
-#endif
index 32982eb75c84195aaa1c222d8cde5734cdcd82bd..de5773443c62802e746cee05f4e34ed8f643f3aa 100644 (file)
@@ -4,62 +4,32 @@
 
 #include <linux/completion.h>
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,   
                    int inout)
 {
-    int hanum,busnum;
+    gdth_ha_str *ha = shost_priv(host);
 
     TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
             length,(int)offset,inout));
 
-    hanum = NUMDATA(host)->hanum;
-    busnum= NUMDATA(host)->busnum;
-
-    if (inout)
-        return(gdth_set_info(buffer,length,host,hanum,busnum));
-    else
-        return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
-}
-#else
-int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,   
-                   int inout)
-{
-    int hanum,busnum,i;
-
-    TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
-            length,(int)offset,inout));
-
-    for (i = 0; i < gdth_ctr_vcount; ++i) {
-        if (gdth_ctr_vtab[i]->host_no == hostno)
-            break;
-    }
-    if (i == gdth_ctr_vcount)
-        return(-EINVAL);
-
-    hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
-    busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
-
     if (inout)
-        return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
+        return(gdth_set_info(buffer,length,host,ha));
     else
-        return(gdth_get_info(buffer,start,offset,length,
-                             gdth_ctr_vtab[i],hanum,busnum));
+        return(gdth_get_info(buffer,start,offset,length,host,ha));
 }
-#endif
 
 static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
-                         int hanum,int busnum)
+                         gdth_ha_str *ha)
 {
     int ret_val = -EINVAL;
 
-    TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
+    TRACE2(("gdth_set_info() ha %d\n",ha->hanum,));
 
     if (length >= 4) {
         if (strncmp(buffer,"gdth",4) == 0) {
             buffer += 5;
             length -= 5;
-            ret_val = gdth_set_asc_info(host, buffer, length, hanum);
+            ret_val = gdth_set_asc_info(host, buffer, length, ha);
         }
     }
 
@@ -67,11 +37,10 @@ static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
 }
          
 static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
-                        int length,int hanum)
+                        int length, gdth_ha_str *ha)
 {
     int orig_length, drive, wb_mode;
     int i, found;
-    gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
     gdth_cpar_str   *pcpar;
     ulong64         paddr;
@@ -80,8 +49,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
     memset(cmnd, 0xff, 12);
     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
 
-    TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum));
     orig_length = length + 5;
     drive = -1;
     wb_mode = 0;
@@ -157,7 +125,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
     }
 
     if (wb_mode) {
-        if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr))
+        if (!gdth_ioctl_alloc(ha, sizeof(gdth_cpar_str), TRUE, &paddr))
             return(-EBUSY);
         pcpar = (gdth_cpar_str *)ha->pscratch;
         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
@@ -171,7 +139,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
 
         gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
 
-        gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
+        gdth_ioctl_free(ha, GDTH_SCRATCH, ha->pscratch, paddr);
         printk("Done.\n");
         return(orig_length);
     }
@@ -181,11 +149,10 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
 }
 
 static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
-                         struct Scsi_Host *host,int hanum,int busnum)
+                         struct Scsi_Host *host, gdth_ha_str *ha)
 {
     int size = 0,len = 0;
     off_t begin = 0,pos = 0;
-    gdth_ha_str *ha;
     int id, i, j, k, sec, flag;
     int no_mdrv = 0, drv_no, is_mirr;
     ulong32 cnt;
@@ -214,8 +181,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
     memset(cmnd, 0xff, 12);
     memset(gdtcmd, 0, sizeof(gdth_cmd_str));
 
-    TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
+    TRACE2(("gdth_get_info() ha %d\n",ha->hanum));
 
     
     /* request is i.e. "cat /proc/scsi/gdth/0" */ 
@@ -245,13 +211,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
     /* controller information */
     size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
     len += size;  pos = begin + len;
-    if (virt_ctr)
-        sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
-    else
-        strcpy(hrec, ha->binfo.type_string);
+    strcpy(hrec, ha->binfo.type_string);
     size = sprintf(buffer+len,
                    " Number:       \t%d         \tName:          \t%s\n",
-                   hanum, hrec);
+                   ha->hanum, hrec);
     len += size;  pos = begin + len;
 
     if (ha->more_proc)
@@ -301,7 +264,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
         len += size;  pos = begin + len;
         flag = FALSE;
             
-        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
         if (!buf) 
             goto stop_output;
         for (i = 0; i < ha->bus_cnt; ++i) {
@@ -404,7 +367,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
                     goto stop_output;
             }
         }
-        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+        gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
 
         if (!flag) {
             size = sprintf(buffer+len, "\n --\n");
@@ -416,7 +379,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
         len += size;  pos = begin + len;
         flag = FALSE;
 
-        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
         if (!buf) 
             goto stop_output;
         for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -510,7 +473,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
             if (pos > offset + length)
                 goto stop_output;
         }       
-        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+        gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
         
         if (!flag) {
             size = sprintf(buffer+len, "\n --\n");
@@ -522,7 +485,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
         len += size;  pos = begin + len;
         flag = FALSE;
 
-        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
         if (!buf) 
             goto stop_output;
         for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -581,7 +544,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
                     goto stop_output;
             }
         }
-        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+        gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
         
         if (!flag) {
             size = sprintf(buffer+len, "\n --\n");
@@ -593,7 +556,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
         len += size;  pos = begin + len;
         flag = FALSE;
 
-        buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
+        buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr);
         if (!buf) 
             goto stop_output;
         for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -626,7 +589,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
                 }
             }
         }
-        gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
+        gdth_ioctl_free(ha, sizeof(gdth_hget_str), buf, paddr);
 
         for (i = 0; i < MAX_HDRIVES; ++i) {
             if (!(ha->hdr[i].present))
@@ -664,7 +627,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
         id = gdth_read_event(ha, id, estr);
         if (estr->event_source == 0)
             break;
-        if (estr->event_data.eu.driver.ionode == hanum &&
+        if (estr->event_data.eu.driver.ionode == ha->hanum &&
             estr->event_source == ES_ASYNC) { 
             gdth_log_event(&estr->event_data, hrec);
             do_gettimeofday(&tv);
@@ -699,17 +662,15 @@ free_fail:
     return rc;
 }
 
-static char *gdth_ioctl_alloc(int hanum, int size, int scratch, 
+static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
                               ulong64 *paddr)
 {
-    gdth_ha_str *ha;
     ulong flags;
     char *ret_val;
 
     if (size == 0)
         return NULL;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
@@ -729,12 +690,10 @@ static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
     return ret_val;
 }
 
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr)
 {
-    gdth_ha_str *ha;
     ulong flags;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     if (buf == ha->pscratch) {
@@ -747,13 +706,11 @@ static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
 }
 
 #ifdef GDTH_IOCTL_PROC
-static int gdth_ioctl_check_bin(int hanum, ushort size)
+static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size)
 {
-    gdth_ha_str *ha;
     ulong flags;
     int ret_val;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     ret_val = FALSE;
@@ -766,27 +723,27 @@ static int gdth_ioctl_check_bin(int hanum, ushort size)
 }
 #endif
 
-static void gdth_wait_completion(int hanum, int busnum, int id)
+static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
 {
-    gdth_ha_str *ha;
     ulong flags;
     int i;
     Scsi_Cmnd *scp;
+    struct gdth_cmndinfo *cmndinfo;
     unchar b, t;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         scp = ha->cmd_tab[i].cmnd;
+        cmndinfo = gdth_cmnd_priv(scp);
 
-        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        b = scp->device->channel;
         t = scp->device->id;
         if (!SPECIAL_SCP(scp) && t == (unchar)id && 
             b == (unchar)busnum) {
-            scp->SCp.have_data_in = 0;
+            cmndinfo->wait_for_completion = 0;
             spin_unlock_irqrestore(&ha->smp_lock, flags);
-            while (!scp->SCp.have_data_in)
+            while (!cmndinfo->wait_for_completion)
                 barrier();
             spin_lock_irqsave(&ha->smp_lock, flags);
         }
@@ -794,55 +751,51 @@ static void gdth_wait_completion(int hanum, int busnum, int id)
     spin_unlock_irqrestore(&ha->smp_lock, flags);
 }
 
-static void gdth_stop_timeout(int hanum, int busnum, int id)
+static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id)
 {
-    gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
     unchar b, t;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-        if (scp->done != gdth_scsi_done) {
-            b = virt_ctr ?
-                NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+        if (!cmndinfo->internal_command) {
+            b = scp->device->channel;
             t = scp->device->id;
             if (t == (unchar)id && b == (unchar)busnum) {
                 TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
-                scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+                cmndinfo->timeout = gdth_update_timeout(scp, 0);
             }
         }
     }
     spin_unlock_irqrestore(&ha->smp_lock, flags);
 }
 
-static void gdth_start_timeout(int hanum, int busnum, int id)
+static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id)
 {
-    gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
     unchar b, t;
 
-    ha = HADATA(gdth_ctr_tab[hanum]);
     spin_lock_irqsave(&ha->smp_lock, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-        if (scp->done != gdth_scsi_done) {
-            b = virt_ctr ?
-                NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+        if (!cmndinfo->internal_command) {
+            b = scp->device->channel;
             t = scp->device->id;
             if (t == (unchar)id && b == (unchar)busnum) {
                 TRACE2(("gdth_start_timeout(): update_timeout()\n"));
-                gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
+                gdth_update_timeout(scp, cmndinfo->timeout);
             }
         }
     }
     spin_unlock_irqrestore(&ha->smp_lock, flags);
 }
 
-static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
 {
     int oldto;
 
index a679eeb6820bddf17ff5a277bf000f82f8d55333..45e6fdacf36e39d06eee15ba10e7c12f396673a5 100644 (file)
@@ -9,20 +9,20 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
                  int timeout, u32 *info);
 
 static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
-                         int hanum,int busnum);
+                         gdth_ha_str *ha);
 static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
-                         struct Scsi_Host *host,int hanum,int busnum);
+                         struct Scsi_Host *host, gdth_ha_str *ha);
 
 static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
-                             int length, int hanum);
+                             int length, gdth_ha_str *ha);
 
-static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
-                              ulong64 *paddr);  
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr);
-static void gdth_wait_completion(int hanum, int busnum, int id);
-static void gdth_stop_timeout(int hanum, int busnum, int id);
-static void gdth_start_timeout(int hanum, int busnum, int id);
-static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
+static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
+                              ulong64 *paddr);
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr);
+static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id);
+static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id);
+static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id);
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout);
 
 #endif
 
index 96bc31266c98a258aefbcbd6ff54fde95f80a560..adc9559cb6f40b20e4666d93550bc0b8b6fc8e83 100644 (file)
@@ -342,6 +342,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        shost->unchecked_isa_dma = sht->unchecked_isa_dma;
        shost->use_clustering = sht->use_clustering;
        shost->ordered_tag = sht->ordered_tag;
+       shost->active_mode = sht->supported_mode;
 
        if (sht->max_host_blocked)
                shost->max_host_blocked = sht->max_host_blocked;
index 0e579ca45814d4a0794f99ba7594dfc315ff88b5..8b384fa7f048c96a92d555e74377ab3d1a4bb22d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * HighPoint RR3xxx controller driver for Linux
- * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver");
 
 static char driver_name[] = "hptiop";
 static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
-static const char driver_ver[] = "v1.0 (060426)";
+static const char driver_ver[] = "v1.2 (070830)";
 
 static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
 static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
@@ -76,7 +76,7 @@ static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec)
 
 static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag)
 {
-       if ((tag & IOPMU_QUEUE_MASK_HOST_BITS) == IOPMU_QUEUE_ADDR_HOST_BIT)
+       if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
                return hptiop_host_request_callback(hba,
                                tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
        else
@@ -323,12 +323,22 @@ static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
        hba->req_list = req;
 }
 
-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag)
+static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
 {
        struct hpt_iop_request_scsi_command *req;
        struct scsi_cmnd *scp;
+       u32 tag;
+
+       if (hba->iopintf_v2) {
+               tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT;
+               req = hba->reqs[tag].req_virt;
+               if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
+                       req->header.result = IOP_RESULT_SUCCESS;
+       } else {
+               tag = _tag;
+               req = hba->reqs[tag].req_virt;
+       }
 
-       req = (struct hpt_iop_request_scsi_command *)hba->reqs[tag].req_virt;
        dprintk("hptiop_host_request_callback: req=%p, type=%d, "
                        "result=%d, context=0x%x tag=%d\n",
                        req, req->header.type, req->header.result,
@@ -497,7 +507,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
                goto cmd_done;
        }
 
-       req = (struct hpt_iop_request_scsi_command *)_req->req_virt;
+       req = _req->req_virt;
 
        /* build S/G table */
        sg_count = hptiop_buildsgl(scp, req->sg_list);
@@ -521,8 +531,19 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
 
        memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
 
-       writel(IOPMU_QUEUE_ADDR_HOST_BIT | _req->req_shifted_phy,
-                       &hba->iop->inbound_queue);
+       if (hba->iopintf_v2) {
+               u32 size_bits;
+               if (req->header.size < 256)
+                       size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
+               else if (req->header.size < 512)
+                       size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
+               else
+                       size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
+                                               IOPMU_QUEUE_ADDR_HOST_BIT;
+               writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue);
+       } else
+               writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
+                                       &hba->iop->inbound_queue);
 
        return 0;
 
@@ -688,6 +709,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
        hba->pcidev = pcidev;
        hba->host = host;
        hba->initialized = 0;
+       hba->iopintf_v2 = 0;
 
        atomic_set(&hba->resetting, 0);
        atomic_set(&hba->reset_count, 0);
@@ -722,8 +744,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
        hba->max_request_size = le32_to_cpu(iop_config.request_size);
        hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count);
        hba->firmware_version = le32_to_cpu(iop_config.firmware_version);
+       hba->interface_version = le32_to_cpu(iop_config.interface_version);
        hba->sdram_size = le32_to_cpu(iop_config.sdram_size);
 
+       if (hba->firmware_version > 0x01020000 ||
+                       hba->interface_version > 0x01020000)
+               hba->iopintf_v2 = 1;
+
        host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9;
        host->max_id = le32_to_cpu(iop_config.max_devices);
        host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count);
@@ -731,8 +758,15 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
        host->cmd_per_lun = le32_to_cpu(iop_config.max_requests);
        host->max_cmd_len = 16;
 
-       set_config.vbus_id = cpu_to_le32(host->host_no);
+       req_size = sizeof(struct hpt_iop_request_scsi_command)
+               + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
+       if ((req_size & 0x1f) != 0)
+               req_size = (req_size + 0x1f) & ~0x1f;
+
+       memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config));
        set_config.iop_id = cpu_to_le32(host->host_no);
+       set_config.vbus_id = cpu_to_le16(host->host_no);
+       set_config.max_host_request_size = cpu_to_le16(req_size);
 
        if (iop_set_config(hba, &set_config)) {
                printk(KERN_ERR "scsi%d: set config failed\n",
@@ -750,10 +784,6 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
        }
 
        /* Allocate request mem */
-       req_size = sizeof(struct hpt_iop_request_scsi_command)
-               + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
-       if ((req_size& 0x1f) != 0)
-               req_size = (req_size + 0x1f) & ~0x1f;
 
        dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
 
@@ -879,8 +909,10 @@ static void hptiop_remove(struct pci_dev *pcidev)
 }
 
 static struct pci_device_id hptiop_id_table[] = {
-       { PCI_DEVICE(0x1103, 0x3220) },
-       { PCI_DEVICE(0x1103, 0x3320) },
+       { PCI_VDEVICE(TTI, 0x3220) },
+       { PCI_VDEVICE(TTI, 0x3320) },
+       { PCI_VDEVICE(TTI, 0x3520) },
+       { PCI_VDEVICE(TTI, 0x4320) },
        {},
 };
 
@@ -910,3 +942,4 @@ module_init(hptiop_module_init);
 module_exit(hptiop_module_exit);
 
 MODULE_LICENSE("GPL");
+
index f04f7e81d1ae8e52d9ab5b00837c2d3fd92b02d2..2a5e46e001cba5ebd2357354b26d5352887ea3da 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * HighPoint RR3xxx controller driver for Linux
- * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #ifndef _HPTIOP_H_
 #define _HPTIOP_H_
 
-/*
- * logical device type.
- * Identify array (logical device) and physical device.
- */
-#define LDT_ARRAY   1
-#define LDT_DEVICE  2
-
-/*
- * Array types
- */
-#define AT_UNKNOWN  0
-#define AT_RAID0    1
-#define AT_RAID1    2
-#define AT_RAID5    3
-#define AT_RAID6    4
-#define AT_JBOD     7
-
-#define MAX_NAME_LENGTH     36
-#define MAX_ARRAYNAME_LEN   16
-
-#define MAX_ARRAY_MEMBERS_V1 8
-#define MAX_ARRAY_MEMBERS_V2 16
-
-/* keep definition for source code compatiblity */
-#define MAX_ARRAY_MEMBERS MAX_ARRAY_MEMBERS_V1
-
-/*
- * array flags
- */
-#define ARRAY_FLAG_DISABLED         0x00000001 /* The array is disabled */
-#define ARRAY_FLAG_NEEDBUILDING     0x00000002 /* need to be rebuilt */
-#define ARRAY_FLAG_REBUILDING       0x00000004 /* in rebuilding process */
-#define ARRAY_FLAG_BROKEN           0x00000008 /* broken but still working */
-#define ARRAY_FLAG_BOOTDISK         0x00000010 /* has a active partition */
-#define ARRAY_FLAG_BOOTMARK         0x00000040 /* array has boot mark set */
-#define ARRAY_FLAG_NEED_AUTOREBUILD 0x00000080 /* auto-rebuild should start */
-#define ARRAY_FLAG_VERIFYING        0x00000100 /* is being verified */
-#define ARRAY_FLAG_INITIALIZING     0x00000200 /* is being initialized */
-#define ARRAY_FLAG_TRANSFORMING     0x00000400 /* tranform in progress */
-#define ARRAY_FLAG_NEEDTRANSFORM    0x00000800 /* array need tranform */
-#define ARRAY_FLAG_NEEDINITIALIZING 0x00001000 /* initialization not done */
-#define ARRAY_FLAG_BROKEN_REDUNDANT 0x00002000 /* broken but redundant */
-
-/*
- * device flags
- */
-#define DEVICE_FLAG_DISABLED        0x00000001 /* device is disabled */
-#define DEVICE_FLAG_UNINITIALIZED   0x00010000 /* device is not initialized */
-#define DEVICE_FLAG_LEGACY          0x00020000 /* lagacy drive */
-#define DEVICE_FLAG_IS_SPARE        0x80000000 /* is a spare disk */
-
-/*
- * ioctl codes
- */
-#define HPT_CTL_CODE(x) (x+0xFF00)
-#define HPT_CTL_CODE_LINUX_TO_IOP(x) ((x)-0xff00)
-
-#define HPT_IOCTL_GET_CONTROLLER_INFO       HPT_CTL_CODE(2)
-#define HPT_IOCTL_GET_CHANNEL_INFO          HPT_CTL_CODE(3)
-#define HPT_IOCTL_GET_LOGICAL_DEVICES       HPT_CTL_CODE(4)
-#define HPT_IOCTL_GET_DRIVER_CAPABILITIES   HPT_CTL_CODE(19)
-#define HPT_IOCTL_GET_DEVICE_INFO_V3        HPT_CTL_CODE(46)
-#define HPT_IOCTL_GET_CONTROLLER_INFO_V2    HPT_CTL_CODE(47)
-
-/*
- * Controller information.
- */
-struct hpt_controller_info {
-       u8      chip_type;                    /* chip type */
-       u8      interrupt_level;              /* IRQ level */
-       u8      num_buses;                    /* bus count */
-       u8      chip_flags;
-
-       u8      product_id[MAX_NAME_LENGTH];/* product name */
-       u8      vendor_id[MAX_NAME_LENGTH]; /* vendor name */
-}
-__attribute__((packed));
-
-/*
- * Channel information.
- */
-struct hpt_channel_info {
-       __le32  io_port;         /* IDE Base Port Address */
-       __le32  control_port;    /* IDE Control Port Address */
-       __le32  devices[2];      /* device connected to this channel */
-}
-__attribute__((packed));
-
-/*
- * Array information.
- */
-struct hpt_array_info_v3 {
-       u8      name[MAX_ARRAYNAME_LEN]; /* array name */
-       u8      description[64];         /* array description */
-       u8      create_manager[16];      /* who created it */
-       __le32  create_time;             /* when created it */
-
-       u8      array_type;              /* array type */
-       u8      block_size_shift;        /* stripe size */
-       u8      ndisk;                   /* Number of ID in Members[] */
-       u8      reserved;
-
-       __le32  flags;                   /* working flags, see ARRAY_FLAG_XXX */
-       __le32  members[MAX_ARRAY_MEMBERS_V2];  /* member array/disks */
-
-       __le32  rebuilding_progress;
-       __le64  rebuilt_sectors; /* rebuilding point (LBA) for single member */
-
-       __le32  transform_source;
-       __le32  transform_target;    /* destination device ID */
-       __le32  transforming_progress;
-       __le32  signature;              /* persistent identification*/
-       __le16  critical_members;       /* bit mask of critical members */
-       __le16  reserve2;
-       __le32  reserve;
-}
-__attribute__((packed));
-
-/*
- * physical device information.
- */
-#define MAX_PARENTS_PER_DISK    8
-
-struct hpt_device_info_v2 {
-       u8   ctlr_id;             /* controller id */
-       u8   path_id;             /* bus */
-       u8   target_id;           /* id */
-       u8   device_mode_setting; /* Current Data Transfer mode: 0-4 PIO0-4 */
-                                 /* 5-7 MW DMA0-2, 8-13 UDMA0-5 */
-       u8   device_type;         /* device type */
-       u8   usable_mode;         /* highest usable mode */
-
-#ifdef __BIG_ENDIAN_BITFIELD
-       u8   NCQ_enabled: 1;
-       u8   NCQ_supported: 1;
-       u8   TCQ_enabled: 1;
-       u8   TCQ_supported: 1;
-       u8   write_cache_enabled: 1;
-       u8   write_cache_supported: 1;
-       u8   read_ahead_enabled: 1;
-       u8   read_ahead_supported: 1;
-       u8   reserved6: 6;
-       u8   spin_up_mode: 2;
-#else
-       u8   read_ahead_supported: 1;
-       u8   read_ahead_enabled: 1;
-       u8   write_cache_supported: 1;
-       u8   write_cache_enabled: 1;
-       u8   TCQ_supported: 1;
-       u8   TCQ_enabled: 1;
-       u8   NCQ_supported: 1;
-       u8   NCQ_enabled: 1;
-       u8   spin_up_mode: 2;
-       u8   reserved6: 6;
-#endif
-
-       __le32  flags;         /* working flags, see DEVICE_FLAG_XXX */
-       u8      ident[150];    /* (partitial) Identify Data of this device */
-
-       __le64  total_free;
-       __le64  max_free;
-       __le64  bad_sectors;
-       __le32  parent_arrays[MAX_PARENTS_PER_DISK];
-}
-__attribute__((packed));
-
-/*
- * Logical device information.
- */
-#define INVALID_TARGET_ID   0xFF
-#define INVALID_BUS_ID      0xFF
-
-struct hpt_logical_device_info_v3 {
-       u8       type;                   /* LDT_ARRAY or LDT_DEVICE */
-       u8       cache_policy;           /* refer to CACHE_POLICY_xxx */
-       u8       vbus_id;                /* vbus sequence in vbus_list */
-       u8       target_id;              /* OS target id. 0xFF is invalid */
-                                        /* OS name: DISK $VBusId_$TargetId */
-       __le64   capacity;               /* array capacity */
-       __le32   parent_array;           /* don't use this field for physical
-                                           device. use ParentArrays field in
-                                           hpt_device_info_v2 */
-       /* reserved statistic fields */
-       __le32   stat1;
-       __le32   stat2;
-       __le32   stat3;
-       __le32   stat4;
-
-       union {
-               struct hpt_array_info_v3 array;
-               struct hpt_device_info_v2 device;
-       } __attribute__((packed)) u;
-
-}
-__attribute__((packed));
-
-/*
- * ioctl structure
- */
-#define HPT_IOCTL_MAGIC   0xA1B2C3D4
-
-struct hpt_ioctl_u {
-       u32   magic;            /* used to check if it's a valid ioctl packet */
-       u32   ioctl_code;       /* operation control code */
-       void __user *inbuf;     /* input data buffer */
-       u32   inbuf_size;       /* size of input data buffer */
-       void __user *outbuf;    /* output data buffer */
-       u32   outbuf_size;      /* size of output data buffer */
-       void __user *bytes_returned;   /* count of bytes returned */
-}
-__attribute__((packed));
-
-
 struct hpt_iopmu
 {
        __le32 resrved0[4];
@@ -252,6 +39,8 @@ struct hpt_iopmu
 #define IOPMU_QUEUE_EMPTY            0xffffffff
 #define IOPMU_QUEUE_MASK_HOST_BITS   0xf0000000
 #define IOPMU_QUEUE_ADDR_HOST_BIT    0x80000000
+#define IOPMU_QUEUE_REQUEST_SIZE_BIT    0x40000000
+#define IOPMU_QUEUE_REQUEST_RESULT_BIT   0x40000000
 
 #define IOPMU_OUTBOUND_INT_MSG0      1
 #define IOPMU_OUTBOUND_INT_MSG1      2
@@ -336,7 +125,8 @@ struct hpt_iop_request_set_config
 {
        struct hpt_iop_request_header header;
        __le32 iop_id;
-       __le32 vbus_id;
+       __le16 vbus_id;
+       __le16 max_host_request_size;
        __le32 reserve[6];
 };
 
@@ -412,9 +202,8 @@ struct hptiop_hba {
        struct Scsi_Host * host;
        struct pci_dev * pcidev;
 
-       struct list_head link;
-
        /* IOP config info */
+       u32     interface_version;
        u32     firmware_version;
        u32     sdram_size;
        u32     max_devices;
@@ -423,8 +212,10 @@ struct hptiop_hba {
        u32     max_sg_descriptors;
 
        u32     req_size; /* host-allocated request buffer size */
-       int     initialized;
-       int     msg_done;
+
+       int     iopintf_v2: 1;
+       int     initialized: 1;
+       int     msg_done: 1;
 
        struct hptiop_request * req_list;
        struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
index 4275d1b04ced7f24b6c89d54b6a403e7cff9357a..1a924e9b02718f405dac5e9be65a13979b4a502a 100644 (file)
@@ -460,13 +460,6 @@ module_param(boot_options, charp, 0);
 module_param_array(io_port, int, NULL, 0);
 module_param_array(scsi_id, int, NULL, 0);
 
-#if 0 /* FIXME: No longer exist? --RR */
-MODULE_PARM(display, "1i");
-MODULE_PARM(adisplay, "1i");
-MODULE_PARM(normal, "1i");
-MODULE_PARM(ansi, "1i");
-#endif
-
 MODULE_LICENSE("GPL");
 #endif
 /*counter of concurrent disk read/writes, to turn on/off disk led */
@@ -1693,6 +1686,7 @@ static int __devexit ibmmca_remove(struct device *dev)
        scsi_remove_host(shpnt);
        release_region(shpnt->io_port, shpnt->n_io_port);
        free_irq(shpnt->irq, dev);
+       scsi_host_put(shpnt);
        return 0;
 }
 
index f67d9efc7a99abe8c4c5e8a16ab09e0acf866610..6ac0633d5452af8c36a0683653485980335950e3 100644 (file)
@@ -1,9 +1,7 @@
 obj-$(CONFIG_SCSI_IBMVSCSI)    += ibmvscsic.o
 
 ibmvscsic-y                    += ibmvscsi.o
-ifndef CONFIG_PPC_PSERIES
 ibmvscsic-$(CONFIG_PPC_ISERIES)        += iseries_vscsi.o 
-endif
 ibmvscsic-$(CONFIG_PPC_PSERIES)        += rpa_vscsi.o 
 
 obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvstgt.o
index 5ecc63d1b43602e10f9a64ecad246dbcd1403c52..cda0cc3d182fde457f4b15259d8a10eb476489af 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <asm/firmware.h>
 #include <asm/vio.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_srp.h>
 #include "ibmvscsi.h"
 
 /* The values below are somewhat arbitrary default values, but 
@@ -87,8 +89,12 @@ static int max_channel = 3;
 static int init_timeout = 5;
 static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
 
+static struct scsi_transport_template *ibmvscsi_transport_template;
+
 #define IBMVSCSI_VERSION "1.5.8"
 
+static struct ibmvscsi_ops *ibmvscsi_ops;
+
 MODULE_DESCRIPTION("IBM Virtual SCSI");
 MODULE_AUTHOR("Dave Boutcher");
 MODULE_LICENSE("GPL");
@@ -506,8 +512,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
        atomic_set(&hostdata->request_limit, 0);
 
        purge_requests(hostdata, DID_ERROR);
-       if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
-           (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
+       if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
+           (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) ||
            (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
                atomic_set(&hostdata->request_limit, -1);
                dev_err(hostdata->dev, "error after reset\n");
@@ -612,7 +618,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
        }
 
        if ((rc =
-            ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+            ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
                list_del(&evt_struct->list);
                del_timer(&evt_struct->timer);
 
@@ -1211,8 +1217,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                case 0x01:      /* Initialization message */
                        dev_info(hostdata->dev, "partner initialized\n");
                        /* Send back a response */
-                       if ((rc = ibmvscsi_send_crq(hostdata,
-                                                   0xC002000000000000LL, 0)) == 0) {
+                       if ((rc = ibmvscsi_ops->send_crq(hostdata,
+                                                        0xC002000000000000LL, 0)) == 0) {
                                /* Now login */
                                send_srp_login(hostdata);
                        } else {
@@ -1237,10 +1243,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                        /* We need to re-setup the interpartition connection */
                        dev_info(hostdata->dev, "Re-enabling adapter!\n");
                        purge_requests(hostdata, DID_REQUEUE);
-                       if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
-                                                       hostdata)) ||
-                           (ibmvscsi_send_crq(hostdata,
-                                              0xC001000000000000LL, 0))) {
+                       if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
+                                                             hostdata)) ||
+                           (ibmvscsi_ops->send_crq(hostdata,
+                                                   0xC001000000000000LL, 0))) {
                                        atomic_set(&hostdata->request_limit,
                                                   -1);
                                        dev_err(hostdata->dev, "error after enable\n");
@@ -1250,10 +1256,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                                crq->format);
 
                        purge_requests(hostdata, DID_ERROR);
-                       if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
-                                                       hostdata)) ||
-                           (ibmvscsi_send_crq(hostdata,
-                                              0xC001000000000000LL, 0))) {
+                       if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
+                                                          hostdata)) ||
+                           (ibmvscsi_ops->send_crq(hostdata,
+                                                   0xC001000000000000LL, 0))) {
                                        atomic_set(&hostdata->request_limit,
                                                   -1);
                                        dev_err(hostdata->dev, "error after reset\n");
@@ -1553,6 +1559,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        struct ibmvscsi_host_data *hostdata;
        struct Scsi_Host *host;
        struct device *dev = &vdev->dev;
+       struct srp_rport_identifiers ids;
+       struct srp_rport *rport;
        unsigned long wait_switch = 0;
        int rc;
 
@@ -1565,6 +1573,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
                goto scsi_host_alloc_failed;
        }
 
+       host->transportt = ibmvscsi_transport_template;
        hostdata = shost_priv(host);
        memset(hostdata, 0x00, sizeof(*hostdata));
        INIT_LIST_HEAD(&hostdata->sent);
@@ -1573,7 +1582,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        atomic_set(&hostdata->request_limit, -1);
        hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
 
-       rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
+       rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
        if (rc != 0 && rc != H_RESOURCE) {
                dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
                goto init_crq_failed;
@@ -1590,11 +1599,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        if (scsi_add_host(hostdata->host, hostdata->dev))
                goto add_host_failed;
 
+       /* we don't have a proper target_port_id so let's use the fake one */
+       memcpy(ids.port_id, hostdata->madapter_info.partition_name,
+              sizeof(ids.port_id));
+       ids.roles = SRP_RPORT_ROLE_TARGET;
+       rport = srp_rport_add(host, &ids);
+       if (IS_ERR(rport))
+               goto add_srp_port_failed;
+
        /* Try to send an initialization message.  Note that this is allowed
         * to fail if the other end is not acive.  In that case we don't
         * want to scan
         */
-       if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
+       if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
            || rc == H_RESOURCE) {
                /*
                 * Wait around max init_timeout secs for the adapter to finish
@@ -1617,10 +1634,12 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        vdev->dev.driver_data = hostdata;
        return 0;
 
+      add_srp_port_failed:
+       scsi_remove_host(hostdata->host);
       add_host_failed:
        release_event_pool(&hostdata->pool, hostdata);
       init_pool_failed:
-       ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests);
+       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
       init_crq_failed:
        scsi_host_put(host);
       scsi_host_alloc_failed:
@@ -1631,9 +1650,10 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
 {
        struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
        release_event_pool(&hostdata->pool, hostdata);
-       ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
-                                  max_requests);
-       
+       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
+                                       max_requests);
+
+       srp_remove_host(hostdata->host);
        scsi_remove_host(hostdata->host);
        scsi_host_put(hostdata->host);
 
@@ -1660,14 +1680,35 @@ static struct vio_driver ibmvscsi_driver = {
        }
 };
 
+static struct srp_function_template ibmvscsi_transport_functions = {
+};
+
 int __init ibmvscsi_module_init(void)
 {
-       return vio_register_driver(&ibmvscsi_driver);
+       int ret;
+
+       if (firmware_has_feature(FW_FEATURE_ISERIES))
+               ibmvscsi_ops = &iseriesvscsi_ops;
+       else if (firmware_has_feature(FW_FEATURE_VIO))
+               ibmvscsi_ops = &rpavscsi_ops;
+       else
+               return -ENODEV;
+
+       ibmvscsi_transport_template =
+               srp_attach_transport(&ibmvscsi_transport_functions);
+       if (!ibmvscsi_transport_template)
+               return -ENOMEM;
+
+       ret = vio_register_driver(&ibmvscsi_driver);
+       if (ret)
+               srp_release_transport(ibmvscsi_transport_template);
+       return ret;
 }
 
 void __exit ibmvscsi_module_exit(void)
 {
        vio_unregister_driver(&ibmvscsi_driver);
+       srp_release_transport(ibmvscsi_transport_template);
 }
 
 module_init(ibmvscsi_module_init);
index b19c2e26c2a541853ab01bccb803146fb78d3db5..46e850e302c7918306d96218ff606229ae230183 100644 (file)
@@ -98,21 +98,25 @@ struct ibmvscsi_host_data {
 };
 
 /* routines for managing a command/response queue */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
-                           struct ibmvscsi_host_data *hostdata,
-                           int max_requests);
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata,
-                               int max_requests);
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
-                             struct ibmvscsi_host_data *hostdata);
-
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata);
-
 void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                         struct ibmvscsi_host_data *hostdata);
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
-                     u64 word1, u64 word2);
+
+struct ibmvscsi_ops {
+       int (*init_crq_queue)(struct crq_queue *queue,
+                             struct ibmvscsi_host_data *hostdata,
+                             int max_requests);
+       void (*release_crq_queue)(struct crq_queue *queue,
+                                 struct ibmvscsi_host_data *hostdata,
+                                 int max_requests);
+       int (*reset_crq_queue)(struct crq_queue *queue,
+                              struct ibmvscsi_host_data *hostdata);
+       int (*reenable_crq_queue)(struct crq_queue *queue,
+                                 struct ibmvscsi_host_data *hostdata);
+       int (*send_crq)(struct ibmvscsi_host_data *hostdata,
+                      u64 word1, u64 word2);
+};
+
+extern struct ibmvscsi_ops iseriesvscsi_ops;
+extern struct ibmvscsi_ops rpavscsi_ops;
 
 #endif                         /* IBMVSCSI_H */
index 8ba7dd09d01d53e4cfc9bee44e94892f1b116243..82bcab688b44895fa0a17389100c65af7d95cf1c 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_srp.h>
 #include <scsi/scsi_tgt.h>
 #include <scsi/libsrp.h>
 #include <asm/hvcall.h>
@@ -68,9 +69,12 @@ struct vio_port {
        unsigned long liobn;
        unsigned long riobn;
        struct srp_target *target;
+
+       struct srp_rport *rport;
 };
 
 static struct workqueue_struct *vtgtd;
+static struct scsi_transport_template *ibmvstgt_transport_template;
 
 /*
  * These are fixed for the system and come from the Open Firmware device tree.
@@ -188,6 +192,7 @@ static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
 static void handle_cmd_queue(struct srp_target *target)
 {
        struct Scsi_Host *shost = target->shost;
+       struct srp_rport *rport = target_to_port(target)->rport;
        struct iu_entry *iue;
        struct srp_cmd *cmd;
        unsigned long flags;
@@ -200,7 +205,8 @@ retry:
                if (!test_and_set_bit(V_FLYING, &iue->flags)) {
                        spin_unlock_irqrestore(&target->lock, flags);
                        cmd = iue->sbuf->buf;
-                       err = srp_cmd_queue(shost, cmd, iue, 0);
+                       err = srp_cmd_queue(shost, cmd, iue,
+                                           (unsigned long)rport, 0);
                        if (err) {
                                eprintk("cannot queue cmd %p %d\n", cmd, err);
                                srp_iu_put(iue);
@@ -359,6 +365,16 @@ static void process_login(struct iu_entry *iue)
        union viosrp_iu *iu = vio_iu(iue);
        struct srp_login_rsp *rsp = &iu->srp.login_rsp;
        uint64_t tag = iu->srp.rsp.tag;
+       struct Scsi_Host *shost = iue->target->shost;
+       struct srp_target *target = host_to_srp_target(shost);
+       struct vio_port *vport = target_to_port(target);
+       struct srp_rport_identifiers ids;
+
+       memset(&ids, 0, sizeof(ids));
+       sprintf(ids.port_id, "%x", vport->dma_dev->unit_address);
+       ids.roles = SRP_RPORT_ROLE_INITIATOR;
+       if (!vport->rport)
+               vport->rport = srp_rport_add(shost, &ids);
 
        /* TODO handle case that requested size is wrong and
         * buffer format is wrong
@@ -412,7 +428,9 @@ static int process_tsk_mgmt(struct iu_entry *iue)
                fn = 0;
        }
        if (fn)
-               scsi_tgt_tsk_mgmt_request(iue->target->shost, fn,
+               scsi_tgt_tsk_mgmt_request(iue->target->shost,
+                                         (unsigned long)iue->target->shost,
+                                         fn,
                                          iu->srp.tsk_mgmt.task_tag,
                                          (struct scsi_lun *) &iu->srp.tsk_mgmt.lun,
                                          iue);
@@ -721,7 +739,8 @@ static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc)
        return 0;
 }
 
-static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
+static int ibmvstgt_tsk_mgmt_response(struct Scsi_Host *shost,
+                                     u64 itn_id, u64 mid, int result)
 {
        struct iu_entry *iue = (struct iu_entry *) ((void *) mid);
        union viosrp_iu *iu = vio_iu(iue);
@@ -747,6 +766,20 @@ static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
        return 0;
 }
 
+static int ibmvstgt_it_nexus_response(struct Scsi_Host *shost, u64 itn_id,
+                                     int result)
+{
+       struct srp_target *target = host_to_srp_target(shost);
+       struct vio_port *vport = target_to_port(target);
+
+       if (result) {
+               eprintk("%p %d\n", shost, result);
+               srp_rport_del(vport->rport);
+               vport->rport = NULL;
+       }
+       return 0;
+}
+
 static ssize_t system_id_show(struct class_device *cdev, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
@@ -785,9 +818,9 @@ static struct scsi_host_template ibmvstgt_sht = {
        .max_sectors            = DEFAULT_MAX_SECTORS,
        .transfer_response      = ibmvstgt_cmd_done,
        .eh_abort_handler       = ibmvstgt_eh_abort_handler,
-       .tsk_mgmt_response      = ibmvstgt_tsk_mgmt_response,
        .shost_attrs            = ibmvstgt_attrs,
        .proc_name              = TGT_NAME,
+       .supported_mode         = MODE_TARGET,
 };
 
 static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
@@ -804,6 +837,7 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
        shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target));
        if (!shost)
                goto free_vport;
+       shost->transportt = ibmvstgt_transport_template;
        err = scsi_tgt_alloc_queue(shost);
        if (err)
                goto put_host;
@@ -837,8 +871,8 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
        err = scsi_add_host(shost, target->dev);
        if (err)
                goto destroy_queue;
-       return 0;
 
+       return 0;
 destroy_queue:
        crq_queue_destroy(target);
 free_srp_target:
@@ -857,6 +891,7 @@ static int ibmvstgt_remove(struct vio_dev *dev)
        struct vio_port *vport = target->ldata;
 
        crq_queue_destroy(target);
+       srp_remove_host(shost);
        scsi_remove_host(shost);
        scsi_tgt_free_queue(shost);
        srp_target_free(target);
@@ -909,15 +944,25 @@ static int get_system_info(void)
        return 0;
 }
 
+static struct srp_function_template ibmvstgt_transport_functions = {
+       .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
+       .it_nexus_response = ibmvstgt_it_nexus_response,
+};
+
 static int ibmvstgt_init(void)
 {
        int err = -ENOMEM;
 
        printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
 
+       ibmvstgt_transport_template =
+               srp_attach_transport(&ibmvstgt_transport_functions);
+       if (!ibmvstgt_transport_template)
+               return err;
+
        vtgtd = create_workqueue("ibmvtgtd");
        if (!vtgtd)
-               return err;
+               goto release_transport;
 
        err = get_system_info();
        if (err)
@@ -928,9 +973,10 @@ static int ibmvstgt_init(void)
                goto destroy_wq;
 
        return 0;
-
 destroy_wq:
        destroy_workqueue(vtgtd);
+release_transport:
+       srp_release_transport(ibmvstgt_transport_template);
        return err;
 }
 
@@ -940,6 +986,7 @@ static void ibmvstgt_exit(void)
 
        destroy_workqueue(vtgtd);
        vio_unregister_driver(&ibmvstgt_driver);
+       srp_release_transport(ibmvstgt_transport_template);
 }
 
 MODULE_DESCRIPTION("IBM Virtual SCSI Target");
index 6aeb5f003c3c912a0e53099d7d86c126f2ed505e..0775fdee5fa80cc4f9609167c8fc2e1769596d30 100644 (file)
@@ -53,7 +53,7 @@ struct srp_lp_event {
 /** 
  * standard interface for handling logical partition events.
  */
-static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
+static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt)
 {
        struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
 
@@ -74,9 +74,9 @@ static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
 /* ------------------------------------------------------------
  * Routines for driver initialization
  */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
-                           struct ibmvscsi_host_data *hostdata,
-                           int max_requests)
+static int iseriesvscsi_init_crq_queue(struct crq_queue *queue,
+                                      struct ibmvscsi_host_data *hostdata,
+                                      int max_requests)
 {
        int rc;
 
@@ -88,7 +88,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
                goto viopath_open_failed;
        }
 
-       rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event);
+       rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event);
        if (rc < 0) {
                printk("vio_setHandler failed with rc %d in open_event_path\n",
                       rc);
@@ -102,9 +102,9 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        return -1;
 }
 
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata,
-                               int max_requests)
+static void iseriesvscsi_release_crq_queue(struct crq_queue *queue,
+                                          struct ibmvscsi_host_data *hostdata,
+                                          int max_requests)
 {
        vio_clearHandler(viomajorsubtype_scsi);
        viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
@@ -117,8 +117,8 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue,
  *
  * no-op for iSeries
  */
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
-                             struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue,
+                                       struct ibmvscsi_host_data *hostdata)
 {
        return 0;
 }
@@ -130,19 +130,20 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
  *
  * no-op for iSeries
  */
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue,
+                                          struct ibmvscsi_host_data *hostdata)
 {
        return 0;
 }
 
 /**
- * ibmvscsi_send_crq: - Send a CRQ
+ * iseriesvscsi_send_crq: - Send a CRQ
  * @hostdata:  the adapter
  * @word1:     the first 64 bits of the data
  * @word2:     the second 64 bits of the data
  */
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+                                u64 word1, u64 word2)
 {
        single_host_data = hostdata;
        return HvCallEvent_signalLpEventFast(viopath_hostLp,
@@ -156,3 +157,11 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
                                             VIOVERSION << 16, word1, word2, 0,
                                             0);
 }
+
+struct ibmvscsi_ops iseriesvscsi_ops = {
+       .init_crq_queue = iseriesvscsi_init_crq_queue,
+       .release_crq_queue = iseriesvscsi_release_crq_queue,
+       .reset_crq_queue = iseriesvscsi_reset_crq_queue,
+       .reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
+       .send_crq = iseriesvscsi_send_crq,
+};
index 9c14e789df5f875ad006ce179299a8fe864ace7c..182146100dc12220ee20e55d44cb8e0d3a7bf618 100644 (file)
@@ -42,14 +42,14 @@ static unsigned int partition_number = -1;
  * Routines for managing the command/response queue
  */
 /**
- * ibmvscsi_handle_event: - Interrupt handler for crq events
+ * rpavscsi_handle_event: - Interrupt handler for crq events
  * @irq:       number of irq to handle, not used
  * @dev_instance: ibmvscsi_host_data of host that received interrupt
  *
  * Disables interrupts and schedules srp_task
  * Always returns IRQ_HANDLED
  */
-static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
+static irqreturn_t rpavscsi_handle_event(int irq, void *dev_instance)
 {
        struct ibmvscsi_host_data *hostdata =
            (struct ibmvscsi_host_data *)dev_instance;
@@ -66,9 +66,9 @@ static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
  * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
  * the crq with the hypervisor.
  */
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
-                               struct ibmvscsi_host_data *hostdata,
-                               int max_requests)
+static void rpavscsi_release_crq_queue(struct crq_queue *queue,
+                                      struct ibmvscsi_host_data *hostdata,
+                                      int max_requests)
 {
        long rc;
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -108,12 +108,13 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
 }
 
 /**
- * ibmvscsi_send_crq: - Send a CRQ
+ * rpavscsi_send_crq: - Send a CRQ
  * @hostdata:  the adapter
  * @word1:     the first 64 bits of the data
  * @word2:     the second 64 bits of the data
  */
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int rpavscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+                            u64 word1, u64 word2)
 {
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
 
@@ -121,10 +122,10 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
 }
 
 /**
- * ibmvscsi_task: - Process srps asynchronously
+ * rpavscsi_task: - Process srps asynchronously
  * @data:      ibmvscsi_host_data of host
  */
-static void ibmvscsi_task(void *data)
+static void rpavscsi_task(void *data)
 {
        struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -189,6 +190,42 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
        hostdata->madapter_info.os_type = 2;
 }
 
+/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue:     crq_queue to initialize and register
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ */
+static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
+                                   struct ibmvscsi_host_data *hostdata)
+{
+       int rc;
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+       /* Close the CRQ */
+       do {
+               rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+       } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
+
+       /* Clean out the queue */
+       memset(queue->msgs, 0x00, PAGE_SIZE);
+       queue->cur = 0;
+
+       set_adapter_info(hostdata);
+
+       /* And re-open it again */
+       rc = plpar_hcall_norets(H_REG_CRQ,
+                               vdev->unit_address,
+                               queue->msg_token, PAGE_SIZE);
+       if (rc == 2) {
+               /* Adapter is good, but other end is not ready */
+               dev_warn(hostdata->dev, "Partner adapter not ready\n");
+       } else if (rc != 0) {
+               dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
+       }
+       return rc;
+}
+
 /**
  * initialize_crq_queue: - Initializes and registers CRQ with hypervisor
  * @queue:     crq_queue to initialize and register
@@ -198,9 +235,9 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
  * the crq with the hypervisor.
  * Returns zero on success.
  */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
-                           struct ibmvscsi_host_data *hostdata,
-                           int max_requests)
+static int rpavscsi_init_crq_queue(struct crq_queue *queue,
+                                  struct ibmvscsi_host_data *hostdata,
+                                  int max_requests)
 {
        int rc;
        int retrc;
@@ -227,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
                                queue->msg_token, PAGE_SIZE);
        if (rc == H_RESOURCE)
                /* maybe kexecing and resource is busy. try a reset */
-               rc = ibmvscsi_reset_crq_queue(queue,
+               rc = rpavscsi_reset_crq_queue(queue,
                                              hostdata);
 
        if (rc == 2) {
@@ -240,7 +277,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        }
 
        if (request_irq(vdev->irq,
-                       ibmvscsi_handle_event,
+                       rpavscsi_handle_event,
                        0, "ibmvscsi", (void *)hostdata) != 0) {
                dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
                        vdev->irq);
@@ -256,7 +293,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        queue->cur = 0;
        spin_lock_init(&queue->lock);
 
-       tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
+       tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task,
                     (unsigned long)hostdata);
 
        return retrc;
@@ -281,8 +318,8 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
  * @hostdata:  ibmvscsi_host_data of host
  *
  */
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
-                                struct ibmvscsi_host_data *hostdata)
+static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
+                                      struct ibmvscsi_host_data *hostdata)
 {
        int rc;
        struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -297,38 +334,10 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
        return rc;
 }
 
-/**
- * reset_crq_queue: - resets a crq after a failure
- * @queue:     crq_queue to initialize and register
- * @hostdata:  ibmvscsi_host_data of host
- *
- */
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
-                             struct ibmvscsi_host_data *hostdata)
-{
-       int rc;
-       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
-
-       /* Close the CRQ */
-       do {
-               rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
-       } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
-
-       /* Clean out the queue */
-       memset(queue->msgs, 0x00, PAGE_SIZE);
-       queue->cur = 0;
-
-       set_adapter_info(hostdata);
-
-       /* And re-open it again */
-       rc = plpar_hcall_norets(H_REG_CRQ,
-                               vdev->unit_address,
-                               queue->msg_token, PAGE_SIZE);
-       if (rc == 2) {
-               /* Adapter is good, but other end is not ready */
-               dev_warn(hostdata->dev, "Partner adapter not ready\n");
-       } else if (rc != 0) {
-               dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
-       }
-       return rc;
-}
+struct ibmvscsi_ops rpavscsi_ops = {
+       .init_crq_queue = rpavscsi_init_crq_queue,
+       .release_crq_queue = rpavscsi_release_crq_queue,
+       .reset_crq_queue = rpavscsi_reset_crq_queue,
+       .reenable_crq_queue = rpavscsi_reenable_crq_queue,
+       .send_crq = rpavscsi_send_crq,
+};
index 1cc01acc28089060b6aa39f677e630b06c3a83f9..d81bb076a15a887b062f8325061cb2f9d46b6430 100644 (file)
@@ -82,14 +82,12 @@ typedef struct idescsi_pc_s {
  */
 #define PC_DMA_IN_PROGRESS             0       /* 1 while DMA in progress */
 #define PC_WRITING                     1       /* Data direction */
-#define PC_TRANSFORM                   2       /* transform SCSI commands */
 #define PC_TIMEDOUT                    3       /* command timed out */
 #define PC_DMA_OK                      4       /* Use DMA */
 
 /*
  *     SCSI command transformation layer
  */
-#define IDESCSI_TRANSFORM              0       /* Enable/Disable transformation */
 #define IDESCSI_SG_TRANSFORM           1       /* /dev/sg transformation */
 
 /*
@@ -175,7 +173,8 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne
        char *buf;
 
        while (bcount) {
-               if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+               if (pc->sg - scsi_sglist(pc->scsi_cmd) >
+                                                scsi_sg_count(pc->scsi_cmd)) {
                        printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
                        idescsi_discard_data (drive, bcount);
                        return;
@@ -210,7 +209,8 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
        char *buf;
 
        while (bcount) {
-               if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+               if (pc->sg - scsi_sglist(pc->scsi_cmd) >
+                                                scsi_sg_count(pc->scsi_cmd)) {
                        printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
                        idescsi_output_zeros (drive, bcount);
                        return;
@@ -239,77 +239,6 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
        }
 }
 
-/*
- *     Most of the SCSI commands are supported directly by ATAPI devices.
- *     idescsi_transform_pc handles the few exceptions.
- */
-static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
-{
-       u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
-       char *atapi_buf;
-
-       if (!test_bit(PC_TRANSFORM, &pc->flags))
-               return;
-       if (drive->media == ide_cdrom || drive->media == ide_optical) {
-               if (c[0] == READ_6 || c[0] == WRITE_6) {
-                       c[8] = c[4];            c[5] = c[3];            c[4] = c[2];
-                       c[3] = c[1] & 0x1f;     c[2] = 0;               c[1] &= 0xe0;
-                       c[0] += (READ_10 - READ_6);
-               }
-               if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
-                       unsigned short new_len;
-                       if (!scsi_buf)
-                               return;
-                       if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
-                               return;
-                       memset(atapi_buf, 0, pc->buffer_size + 4);
-                       memset (c, 0, 12);
-                       c[0] = sc[0] | 0x40;
-                       c[1] = sc[1];
-                       c[2] = sc[2];
-                       new_len = sc[4] + 4;
-                       c[8] = new_len;
-                       c[7] = new_len >> 8;
-                       c[9] = sc[5];
-                       if (c[0] == MODE_SELECT_10) {
-                               atapi_buf[1] = scsi_buf[0];     /* Mode data length */
-                               atapi_buf[2] = scsi_buf[1];     /* Medium type */
-                               atapi_buf[3] = scsi_buf[2];     /* Device specific parameter */
-                               atapi_buf[7] = scsi_buf[3];     /* Block descriptor length */
-                               memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
-                       }
-                       pc->buffer = atapi_buf;
-                       pc->request_transfer += 4;
-                       pc->buffer_size += 4;
-               }
-       }
-}
-
-static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
-{
-       u8 *atapi_buf = pc->buffer;
-       u8 *sc = pc->scsi_cmd->cmnd;
-       u8 *scsi_buf = pc->scsi_cmd->request_buffer;
-
-       if (!test_bit(PC_TRANSFORM, &pc->flags))
-               return;
-       if (drive->media == ide_cdrom || drive->media == ide_optical) {
-               if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
-                       scsi_buf[0] = atapi_buf[1];             /* Mode data length */
-                       scsi_buf[1] = atapi_buf[2];             /* Medium type */
-                       scsi_buf[2] = atapi_buf[3];             /* Device specific parameter */
-                       scsi_buf[3] = atapi_buf[7];             /* Block descriptor length */
-                       memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
-               }
-               if (pc->c[0] == INQUIRY) {
-                       scsi_buf[2] |= 2;                       /* ansi_revision */
-                       scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */
-               }
-       }
-       if (atapi_buf && atapi_buf != scsi_buf)
-               kfree(atapi_buf);
-}
-
 static void hexdump(u8 *x, int len)
 {
        int i;
@@ -393,7 +322,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
        idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
        int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
        struct Scsi_Host *host;
-       u8 *scsi_buf;
        int errors = rq->errors;
        unsigned long flags;
 
@@ -434,15 +362,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
                pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
        } else {
                pc->scsi_cmd->result = DID_OK << 16;
-               idescsi_transform_pc2 (drive, pc);
-               if (log) {
-                       printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
-                       if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
-                               printk(", rst = ");
-                               scsi_buf = pc->scsi_cmd->request_buffer;
-                               hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen));
-                       } else printk("\n");
-               }
        }
        host = pc->scsi_cmd->device->host;
        spin_lock_irqsave(host->host_lock, flags);
@@ -637,19 +556,14 @@ static int idescsi_map_sg(ide_drive_t *drive, idescsi_pc_t *pc)
                return 1;
 
        sg = hwif->sg_table;
-       scsi_sg = pc->scsi_cmd->request_buffer;
-       segments = pc->scsi_cmd->use_sg;
+       scsi_sg = scsi_sglist(pc->scsi_cmd);
+       segments = scsi_sg_count(pc->scsi_cmd);
 
        if (segments > hwif->sg_max_nents)
                return 1;
 
-       if (!segments) {
-               hwif->sg_nents = 1;
-               sg_init_one(sg, pc->scsi_cmd->request_buffer, pc->request_transfer);
-       } else {
-               hwif->sg_nents = segments;
-               memcpy(sg, scsi_sg, sizeof(*sg) * segments);
-       }
+       hwif->sg_nents = segments;
+       memcpy(sg, scsi_sg, sizeof(*sg) * segments);
 
        return 0;
 }
@@ -744,7 +658,6 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
 {
        if (drive->id && (drive->id->config & 0x0060) == 0x20)
                set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
-       set_bit(IDESCSI_TRANSFORM, &scsi->transform);
        clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 #if IDESCSI_DEBUG_LOG
        set_bit(IDESCSI_LOG_CMD, &scsi->log);
@@ -758,6 +671,7 @@ static void ide_scsi_remove(ide_drive_t *drive)
        struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
        struct gendisk *g = scsi->disk;
 
+       scsi_remove_host(scsihost);
        ide_proc_unregister_driver(drive, scsi->driver);
 
        ide_unregister_region(g);
@@ -766,7 +680,6 @@ static void ide_scsi_remove(ide_drive_t *drive)
        g->private_data = NULL;
        put_disk(g);
 
-       scsi_remove_host(scsihost);
        ide_scsi_put(scsi);
 }
 
@@ -838,6 +751,8 @@ static struct block_device_operations idescsi_ops = {
 static int idescsi_slave_configure(struct scsi_device * sdp)
 {
        /* Configure detected device */
+       sdp->use_10_for_rw = 1;
+       sdp->use_10_for_ms = 1;
        scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun);
        return 0;
 }
@@ -862,24 +777,6 @@ static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg)
        return -EINVAL;
 }
 
-static inline int should_transform(ide_drive_t *drive, struct scsi_cmnd *cmd)
-{
-       idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
-       /* this was a layering violation and we can't support it
-          anymore, sorry. */
-#if 0
-       struct gendisk *disk = cmd->request->rq_disk;
-
-       if (disk) {
-               struct struct scsi_device_Template **p = disk->private_data;
-               if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0)
-                       return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
-       }
-#endif
-       return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
-}
-
 static int idescsi_queue (struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *))
 {
@@ -905,23 +802,14 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
        pc->flags = 0;
        pc->rq = rq;
        memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
-       if (cmd->use_sg) {
-               pc->buffer = NULL;
-               pc->sg = cmd->request_buffer;
-       } else {
-               pc->buffer = cmd->request_buffer;
-               pc->sg = NULL;
-       }
+       pc->buffer = NULL;
+       pc->sg = scsi_sglist(cmd);
        pc->b_count = 0;
-       pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
+       pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd);
        pc->scsi_cmd = cmd;
        pc->done = done;
        pc->timeout = jiffies + cmd->timeout_per_command;
 
-       if (should_transform(drive, cmd))
-               set_bit(PC_TRANSFORM, &pc->flags);
-       idescsi_transform_pc1 (drive, pc);
-
        if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
                printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
                hexdump(cmd->cmnd, cmd->cmd_len);
index 005d2b05f32d2fbbec6dc50b54f0cff850cd2808..74cdc1f0a78f976bbf2d64397566430caba7ca32 100644 (file)
@@ -740,10 +740,6 @@ static void imm_interrupt(struct work_struct *work)
        struct Scsi_Host *host = cmd->device->host;
        unsigned long flags;
 
-       if (!cmd) {
-               printk("IMM: bug in imm_interrupt\n");
-               return;
-       }
        if (imm_engine(dev, cmd)) {
                schedule_delayed_work(&dev->imm_tq, 1);
                return;
index 312190a6938903ddb1e7206a8ce4af7eefa2444a..ab7cbf3449ce07639880a8b55daadad03a751c4f 100644 (file)
@@ -343,7 +343,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
        instance = cmd->device->host;
        hostdata = (struct IN2000_hostdata *) instance->hostdata;
 
-       DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->pid))
+       DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->serial_number))
 
 /* Set up a few fields in the Scsi_Cmnd structure for our own use:
  *  - host_scribble is the pointer to the next cmd in the input queue
@@ -427,7 +427,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 
        in2000_execute(cmd->device->host);
 
-       DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+       DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number))
            return 0;
 }
 
@@ -703,7 +703,7 @@ static void in2000_execute(struct Scsi_Host *instance)
         * to search the input_Q again...
         */
 
-       DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+       DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number))
 
 }
 
@@ -1147,7 +1147,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
        case CSR_XFER_DONE | PHS_COMMAND:
        case CSR_UNEXP | PHS_COMMAND:
        case CSR_SRV_REQ | PHS_COMMAND:
-               DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+               DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))
                    transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
                hostdata->state = S_CONNECTED;
                break;
@@ -1189,7 +1189,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
                switch (msg) {
 
                case COMMAND_COMPLETE:
-                       DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+                       DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))
                            write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
                        hostdata->state = S_PRE_CMP_DISC;
                        break;
@@ -1327,7 +1327,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
 
                write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
                if (phs == 0x60) {
-                       DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+                       DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number))
                            cmd->SCp.Message = COMMAND_COMPLETE;
                        lun = read_3393(hostdata, WD_TARGET_LUN);
                        DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
@@ -1348,7 +1348,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
 
                        in2000_execute(instance);
                } else {
-                       printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->pid);
+                       printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->serial_number);
                }
                break;
 
@@ -1415,7 +1415,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
                        spin_unlock_irqrestore(instance->host_lock, flags);
                        return IRQ_HANDLED;
                }
-               DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+               DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number))
                    hostdata->connected = NULL;
                hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
                hostdata->state = S_UNCONNECTED;
@@ -1440,7 +1440,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
  */
 
                write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
-               DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+               DB(DB_INTR, printk("DISC-%ld", cmd->serial_number))
                    if (cmd == NULL) {
                        printk(" - Already disconnected! ");
                        hostdata->state = S_UNCONNECTED;
@@ -1573,7 +1573,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
                } else
                        hostdata->state = S_CONNECTED;
 
-               DB(DB_INTR, printk("-%ld", cmd->pid))
+               DB(DB_INTR, printk("-%ld", cmd->serial_number))
                    break;
 
        default:
@@ -1702,7 +1702,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
                                prev->host_scribble = cmd->host_scribble;
                        cmd->host_scribble = NULL;
                        cmd->result = DID_ABORT << 16;
-                       printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid);
+                       printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number);
                        cmd->scsi_done(cmd);
                        return SUCCESS;
                }
@@ -1723,7 +1723,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
 
        if (hostdata->connected == cmd) {
 
-               printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->pid);
+               printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number);
 
                printk("sending wd33c93 ABORT command - ");
                write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
@@ -2268,7 +2268,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
                strcat(bp, "\nconnected:     ");
                if (hd->connected) {
                        cmd = (Scsi_Cmnd *) hd->connected;
-                       sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+                       sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
                        strcat(bp, tbuf);
                }
        }
@@ -2276,7 +2276,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
                strcat(bp, "\ninput_Q:       ");
                cmd = (Scsi_Cmnd *) hd->input_Q;
                while (cmd) {
-                       sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+                       sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
                        strcat(bp, tbuf);
                        cmd = (Scsi_Cmnd *) cmd->host_scribble;
                }
@@ -2285,7 +2285,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
                strcat(bp, "\ndisconnected_Q:");
                cmd = (Scsi_Cmnd *) hd->disconnected_Q;
                while (cmd) {
-                       sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+                       sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
                        strcat(bp, tbuf);
                        cmd = (Scsi_Cmnd *) cmd->host_scribble;
                }
index 492a51bd6aa899bb8d64a5cf60ab304913d8d7c2..2ed099e2c20d50ae6d91dacd3832c57f61de6c24 100644 (file)
@@ -204,8 +204,8 @@ module_param(ips, charp, 0);
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "7.12"
-#define IPS_VERSION_LOW         ".05 "
+#define IPS_VERSION_HIGH        IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING
+#define IPS_VERSION_LOW         "." IPS_VER_BUILD_STRING " "
 
 #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
 #warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
@@ -656,6 +656,8 @@ ips_release(struct Scsi_Host *sh)
 
        METHOD_TRACE("ips_release", 1);
 
+       scsi_remove_host(sh);
+
        for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
 
        if (i == IPS_MAX_ADAPTERS) {
@@ -707,7 +709,6 @@ ips_release(struct Scsi_Host *sh)
        /* free IRQ */
        free_irq(ha->irq, ha);
 
-       scsi_remove_host(sh);
        scsi_host_put(sh);
 
        ips_released_controllers++;
@@ -6946,7 +6947,7 @@ module_exit(ips_module_exit);
 static int __devinit
 ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
 {
-       int index;
+       int uninitialized_var(index);
        int rc;
 
        METHOD_TRACE("ips_insert_device", 1);
index 24123d537c5859be2b76e58bcbb2f18037a2dc0a..3bcbd9ff056b07f124608ac8fbd979cdecb0175a 100644 (file)
@@ -1172,12 +1172,13 @@ typedef struct {
 *************************************************************************/
 
 #define IPS_VER_MAJOR 7
-#define IPS_VER_MAJOR_STRING "7"
+#define IPS_VER_MAJOR_STRING __stringify(IPS_VER_MAJOR)
 #define IPS_VER_MINOR 12
-#define IPS_VER_MINOR_STRING "12"
-#define IPS_VER_BUILD 02
-#define IPS_VER_BUILD_STRING "02"
-#define IPS_VER_STRING "7.12.02"
+#define IPS_VER_MINOR_STRING __stringify(IPS_VER_MINOR)
+#define IPS_VER_BUILD 05
+#define IPS_VER_BUILD_STRING __stringify(IPS_VER_BUILD)
+#define IPS_VER_STRING IPS_VER_MAJOR_STRING "." \
+               IPS_VER_MINOR_STRING "." IPS_VER_BUILD_STRING
 #define IPS_RELEASE_ID 0x00020000
 #define IPS_BUILD_IDENT 761
 #define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
index 732446e63963557dab5136c10c361acbc1a18a9a..2ad0a27dbaabf534718c67c7e9ef8ed5b93f70bb 100644 (file)
@@ -392,7 +392,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
 }
 
 int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
-                 u64 addr)
+                 u64 itn_id, u64 addr)
 {
        enum dma_data_direction dir;
        struct scsi_cmnd *sc;
@@ -428,7 +428,8 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
        sc->request_bufflen = len;
        sc->request_buffer = (void *) (unsigned long) addr;
        sc->tag = tag;
-       err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag);
+       err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun,
+                                    cmd->tag);
        if (err)
                scsi_host_put_command(shost, sc);
 
index 2e3c01bebed6801541ffab6c63c9c0a2f0f50d13..149fdd25f8e83d982c1db15f6d103798a6e1b1c8 100644 (file)
@@ -43,7 +43,6 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
-#include "lpfc_vport.h"
 #include "lpfc_debugfs.h"
 
 #ifdef CONFIG_LPFC_DEBUG_FS
@@ -902,7 +901,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                }
        }
 
-       vport->disc_trc = kmalloc(
+       vport->disc_trc = kmzlloc(
                (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
                GFP_KERNEL);
 
@@ -913,8 +912,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                goto debug_failed;
        }
        atomic_set(&vport->disc_trc_cnt, 0);
-       memset(vport->disc_trc, 0,
-               (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc));
 
        snprintf(name, sizeof(name), "discovery_trace");
        vport->debug_disc_trc =
index 414350ab584e4f755f7c2ff0d5264f7170d94839..ecebdfa0047007fd4385427eea0805522101093a 100644 (file)
@@ -43,7 +43,6 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
-#include "lpfc_vport.h"
 
 static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
 static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
@@ -1266,11 +1265,10 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
        uint32_t *HashWorking;
        uint32_t *pwwnn = (uint32_t *) phba->wwnn;
 
-       HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL);
+       HashWorking = kcalloc(80, sizeof(uint32_t), GFP_KERNEL);
        if (!HashWorking)
                return;
 
-       memset(HashWorking, 0, (80 * sizeof(uint32_t)));
        HashWorking[0] = HashWorking[78] = *pwwnn++;
        HashWorking[1] = HashWorking[79] = *pwwnn;
 
index 17d7dc05149b29a232680a85906b292d848c84a3..cd674938ccd53ab2c5f7ebe7a7e563930f6dcd68 100644 (file)
@@ -202,10 +202,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
        dma_addr_t pdma_phys;
        uint16_t iotag;
 
-       psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+       psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
        if (!psb)
                return NULL;
-       memset(psb, 0, sizeof (struct lpfc_scsi_buf));
 
        /*
         * Get memory from the pci pool to map the virt space to pci bus space
index ce5ff2bccba68198f0a3570029bb8a4cdec6441e..e5337ad4121efd36f9d6493dc6ea011cd9404b6c 100644 (file)
@@ -675,7 +675,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
        uint32_t hbqno;
 
        hbqno = tag >> 16;
-       if (hbqno > LPFC_MAX_HBQS)
+       if (hbqno >= LPFC_MAX_HBQS)
                return NULL;
 
        list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
index da56163c30a8f6404b02c16743595561a7b2a692..e7e11f282c8f4357d419e8508746871cdda1a492 100644 (file)
@@ -4416,8 +4416,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
        scmd = &adapter->int_scmd;
        memset(scmd, 0, sizeof(Scsi_Cmnd));
 
-       sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
-       memset(sdev, 0, sizeof(struct scsi_device));
+       sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
        scmd->device = sdev;
 
        scmd->device->host = adapter->host;
index 1bdddad48571d812895ae6824689ab7fa25bc4dc..b264b499d982203e00134e19f1aa80c41014c750 100644 (file)
@@ -48,13 +48,12 @@ mvme16x_probe(struct device *dev)
                goto out;
        }
 
-       hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
        if (hostdata == NULL) {
                printk(KERN_ERR "mvme16x-scsi: "
                                "Failed to allocate host data\n");
                goto out;
        }
-       memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
        /* Fill in the required pieces of hostdata */
        hostdata->base = (void __iomem *)0xfff47000UL;
index 030ba49f33ff3f4a338da8331456f47a0a9ebcff..016c462bc771a80fddce05894445fc1cdb7dd384 100644 (file)
@@ -8143,12 +8143,7 @@ static int ncr53c8xx_abort(struct scsi_cmnd *cmd)
        unsigned long flags;
        struct scsi_cmnd *done_list;
 
-#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
-       printk("ncr53c8xx_abort: pid=%lu serial_number=%ld\n",
-               cmd->pid, cmd->serial_number);
-#else
-       printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
-#endif
+       printk("ncr53c8xx_abort: command pid %lu\n", cmd->serial_number);
 
        NCR_LOCK_NCB(np, flags);
 
@@ -8528,18 +8523,15 @@ struct Scsi_Host * __init ncr_attach(struct scsi_host_template *tpnt,
 }
 
 
-int ncr53c8xx_release(struct Scsi_Host *host)
+void ncr53c8xx_release(struct Scsi_Host *host)
 {
-       struct host_data *host_data;
+       struct host_data *host_data = shost_priv(host);
 #ifdef DEBUG_NCR53C8XX
        printk("ncr53c8xx: release\n");
 #endif
-       if (!host)
-               return 1;
-       host_data = (struct host_data *)host->hostdata;
-       if (host_data && host_data->ncb)
+       if (host_data->ncb)
                ncr_detach(host_data->ncb);
-       return 1;
+       scsi_host_put(host);
 }
 
 static void ncr53c8xx_set_period(struct scsi_target *starget, int period)
index b39357d9af8d1bcb82ab063e39784d2ef84bfe18..0e008dacf679c0df060c9af4c50efb7272a2e2ea 100644 (file)
@@ -1321,7 +1321,7 @@ struct ncr_device {
 };
 
 extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device);
-extern int ncr53c8xx_release(struct Scsi_Host *host);
+extern void ncr53c8xx_release(struct Scsi_Host *host);
 irqreturn_t ncr53c8xx_intr(int irq, void *dev_id);
 extern int ncr53c8xx_init(void);
 extern void ncr53c8xx_exit(void);
index 08060fb478b621e453bae3e46e7ca8611d185b93..331b789937c4e0a700e4d1406f8e6a708e9a3e03 100644 (file)
@@ -3298,7 +3298,7 @@ static ssize_t osst_write(struct file * filp, const char __user * buf, size_t co
        char                * name = tape_name(STp);
 
 
-       if (down_interruptible(&STp->lock))
+       if (mutex_lock_interruptible(&STp->lock))
                return (-ERESTARTSYS);
 
        /*
@@ -3600,7 +3600,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
 out:
        if (SRpnt != NULL) osst_release_request(SRpnt);
 
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
 
        return retval;
 }
@@ -3619,7 +3619,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
        char                * name  = tape_name(STp);
 
 
-       if (down_interruptible(&STp->lock))
+       if (mutex_lock_interruptible(&STp->lock))
                return (-ERESTARTSYS);
 
        /*
@@ -3785,7 +3785,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
 out:
        if (SRpnt != NULL) osst_release_request(SRpnt);
 
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
 
        return retval;
 }
@@ -4852,7 +4852,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
        char                * name  = tape_name(STp);
        void        __user  * p     = (void __user *)arg;
 
-       if (down_interruptible(&STp->lock))
+       if (mutex_lock_interruptible(&STp->lock))
                return -ERESTARTSYS;
 
 #if DEBUG
@@ -5163,14 +5163,14 @@ static int osst_ioctl(struct inode * inode,struct file * file,
        }
        if (SRpnt) osst_release_request(SRpnt);
 
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
 
        return scsi_ioctl(STp->device, cmd_in, p);
 
 out:
        if (SRpnt) osst_release_request(SRpnt);
 
-       up(&STp->lock);
+       mutex_unlock(&STp->lock);
 
        return retval;
 }
@@ -5778,13 +5778,12 @@ static int osst_probe(struct device *dev)
        dev_num = i;
 
        /* allocate a struct osst_tape for this device */
-       tpnt = kmalloc(sizeof(struct osst_tape), GFP_ATOMIC);
-       if (tpnt == NULL) {
+       tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
+       if (!tpnt) {
                write_unlock(&os_scsi_tapes_lock);
                printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
                goto out_put_disk;
        }
-       memset(tpnt, 0, sizeof(struct osst_tape));
 
        /* allocate a buffer for this device */
        i = SDp->host->sg_tablesize;
@@ -5866,7 +5865,7 @@ static int osst_probe(struct device *dev)
        tpnt->modes[2].defined = 1;
        tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
 
-       init_MUTEX(&tpnt->lock);
+       mutex_init(&tpnt->lock);
        osst_nr_dev++;
        write_unlock(&os_scsi_tapes_lock);
 
index 2cc7b5a1606a089b0346d0e8d53a914929bdde8e..5aa22740b5dfaebcb3d0f812c318620177cc14de 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <asm/byteorder.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 
 /*     FIXME - rename and use the following two types or delete them!
  *              and the types really should go to st.h anyway...
@@ -532,7 +533,7 @@ struct osst_tape {
   struct scsi_driver *driver;
   unsigned capacity;
   struct scsi_device *device;
-  struct semaphore lock;       /* for serialization */
+  struct mutex lock;           /* for serialization */
   struct completion wait;      /* for SCSI commands */
   struct osst_buffer * buffer;
 
index 445cfbbca9b3c9faa1a85dab07d01d5b1a10f0dd..a45d89b14147576fac94963774c4ec1241f15183 100644 (file)
@@ -25,8 +25,6 @@
 
 ***********************************************************************/
 
-/* $Id: nsp_cs.c,v 1.23 2003/08/18 11:09:19 elca Exp $ */
-
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -59,7 +57,7 @@
 #include "nsp_cs.h"
 
 MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
-MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.23 $");
+MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
 MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
 #ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
@@ -83,10 +81,6 @@ static struct scsi_host_template nsp_driver_template = {
        .proc_name               = "nsp_cs",
        .proc_info               = nsp_proc_info,
        .name                    = "WorkBit NinjaSCSI-3/32Bi(16bit)",
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-       .detect                  = nsp_detect_old,
-       .release                 = nsp_release_old,
-#endif
        .info                    = nsp_info,
        .queuecommand            = nsp_queuecommand,
 /*     .eh_abort_handler        = nsp_eh_abort,*/
@@ -97,9 +91,6 @@ static struct scsi_host_template nsp_driver_template = {
        .sg_tablesize            = SG_ALL,
        .cmd_per_lun             = 1,
        .use_clustering          = DISABLE_CLUSTERING,
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
-       .use_new_eh_code         = 1,
-#endif
 };
 
 static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
@@ -1313,11 +1304,7 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
        nsp_hw_data *data_b = &nsp_data_base, *data;
 
        nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
        host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
-#else
-       host = scsi_register(sht, sizeof(nsp_hw_data));
-#endif
        if (host == NULL) {
                nsp_dbg(NSP_DEBUG_INIT, "host failed");
                return NULL;
@@ -1354,37 +1341,6 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
        return host; /* detect done. */
 }
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int nsp_detect_old(struct scsi_host_template *sht)
-{
-       if (nsp_detect(sht) == NULL) {
-               return 0;
-       } else {
-               //MOD_INC_USE_COUNT;
-               return 1;
-       }
-}
-
-
-static int nsp_release_old(struct Scsi_Host *shpnt)
-{
-       //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
-
-       /* PCMCIA Card Service dose same things below. */
-       /* So we do nothing.                           */
-       //if (shpnt->irq) {
-       //      free_irq(shpnt->irq, data->ScsiInfo);
-       //}
-       //if (shpnt->io_port) {
-       //      release_region(shpnt->io_port, shpnt->n_io_port);
-       //}
-
-       //MOD_DEC_USE_COUNT;
-
-       return 0;
-}
-#endif
-
 /*----------------------------------------------------------------*/
 /* return info string                                            */
 /*----------------------------------------------------------------*/
@@ -1403,19 +1359,9 @@ static const char *nsp_info(struct Scsi_Host *shpnt)
                        nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length,  length - (pos - buffer));\
                } \
        } while(0)
-static int
-nsp_proc_info(
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
-       struct Scsi_Host *host,
-#endif
-       char  *buffer,
-       char **start,
-       off_t  offset,
-       int    length,
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
-       int    hostno,
-#endif
-       int    inout)
+
+static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+                        off_t offset, int length, int inout)
 {
        int id;
        char *pos = buffer;
@@ -1423,24 +1369,13 @@ nsp_proc_info(
        int speed;
        unsigned long flags;
        nsp_hw_data *data;
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
-       struct Scsi_Host *host;
-#else
        int hostno;
-#endif
+
        if (inout) {
                return -EINVAL;
        }
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
        hostno = host->host_no;
-#else
-       /* search this HBA host */
-       host = scsi_host_hn_get(hostno);
-       if (host == NULL) {
-               return -ESRCH;
-       }
-#endif
        data = (nsp_hw_data *)host->hostdata;
 
 
@@ -1675,10 +1610,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
        cistpl_cftable_entry_t dflt = { 0 };
        struct Scsi_Host *host;
        nsp_hw_data      *data = &nsp_data_base;
-#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
-       struct scsi_device       *dev;
-       dev_node_t      **tail, *node;
-#endif
 
        nsp_dbg(NSP_DEBUG_INIT, "in");
 
@@ -1811,17 +1742,7 @@ static int nsp_cs_config(struct pcmcia_device *link)
                goto cs_failed;
        }
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
        host = nsp_detect(&nsp_driver_template);
-#else
-       scsi_register_host(&nsp_driver_template);
-       for (host = scsi_host_get_next(NULL); host != NULL;
-            host = scsi_host_get_next(host)) {
-               if (host->hostt == &nsp_driver_template) {
-                       break;
-               }
-       }
-#endif
 
        if (host == NULL) {
                nsp_dbg(NSP_DEBUG_INIT, "detect failed");
@@ -1829,7 +1750,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
        }
 
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
        ret = scsi_add_host (host, NULL);
        if (ret)
                goto cs_failed;
@@ -1840,52 +1760,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
        link->dev_node  = &info->node;
        info->host = host;
 
-#else
-       nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO");
-       tail = &link->dev_node;
-       info->ndev = 0;
-
-       nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
-
-       for (dev = host->host_queue; dev != NULL; dev = dev->next) {
-               unsigned long id;
-               id = (dev->id & 0x0f) + ((dev->lun & 0x0f) << 4) +
-                       ((dev->channel & 0x0f) << 8) +
-                       ((dev->host->host_no & 0x0f) << 12);
-               node = &info->node[info->ndev];
-               node->minor = 0;
-               switch (dev->type) {
-               case TYPE_TAPE:
-                       node->major = SCSI_TAPE_MAJOR;
-                       snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id);
-                       break;
-               case TYPE_DISK:
-               case TYPE_MOD:
-                       node->major = SCSI_DISK0_MAJOR;
-                       snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id);
-                       break;
-               case TYPE_ROM:
-               case TYPE_WORM:
-                       node->major = SCSI_CDROM_MAJOR;
-                       snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id);
-                       break;
-               default:
-                       node->major = SCSI_GENERIC_MAJOR;
-                       snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id);
-                       break;
-               }
-               *tail = node; tail = &node->next;
-               info->ndev++;
-               info->host = dev->host;
-       }
-
-       *tail = NULL;
-       if (info->ndev == 0) {
-               nsp_msg(KERN_INFO, "no SCSI devices found");
-       }
-       nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
-#endif
-
        /* Finally, report what we've done */
        printk(KERN_INFO "nsp_cs: index 0x%02x: ",
               link->conf.ConfigIndex);
@@ -1938,13 +1812,9 @@ static void nsp_cs_release(struct pcmcia_device *link)
        nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
 
        /* Unlink the device chain */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
        if (info->host != NULL) {
                scsi_remove_host(info->host);
        }
-#else
-       scsi_unregister_host(&nsp_driver_template);
-#endif
        link->dev_node = NULL;
 
        if (link->win) {
@@ -1954,11 +1824,9 @@ static void nsp_cs_release(struct pcmcia_device *link)
        }
        pcmcia_disable_device(link);
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
        if (info->host != NULL) {
                scsi_host_put(info->host);
        }
-#endif
 } /* nsp_cs_release */
 
 static int nsp_cs_suspend(struct pcmcia_device *link)
@@ -2005,7 +1873,6 @@ static int nsp_cs_resume(struct pcmcia_device *link)
 /*======================================================================*
  *     module entry point
  *====================================================================*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
 static struct pcmcia_device_id nsp_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16       ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
        PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
@@ -2029,28 +1896,12 @@ static struct pcmcia_driver nsp_driver = {
        .suspend        = nsp_cs_suspend,
        .resume         = nsp_cs_resume,
 };
-#endif
 
 static int __init nsp_cs_init(void)
 {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
        nsp_msg(KERN_INFO, "loading...");
 
        return pcmcia_register_driver(&nsp_driver);
-#else
-       servinfo_t serv;
-
-       nsp_msg(KERN_INFO, "loading...");
-       pcmcia_get_card_services_info(&serv);
-       if (serv.Revision != CS_RELEASE_CODE) {
-               nsp_msg(KERN_DEBUG, "Card Services release does not match!");
-               return -EINVAL;
-       }
-       register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
-
-       nsp_dbg(NSP_DEBUG_INIT, "out");
-       return 0;
-#endif
 }
 
 static void __exit nsp_cs_exit(void)
index 9102cbdf13594321724195fba9f80b907b4d9ca0..b7f0fa24641396ca147a6ba894045adaa13e5327 100644 (file)
@@ -10,8 +10,6 @@
 
 =========================================================*/
 
-/* $Id: nsp_cs.h,v 1.19 2003/08/18 11:09:19 elca Exp $ */
-
 #ifndef  __nsp_cs__
 #define  __nsp_cs__
 
 typedef struct scsi_info_t {
        struct pcmcia_device    *p_dev;
        struct Scsi_Host      *host;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
        dev_node_t             node;
-#else
-       int                    ndev;
-       dev_node_t             node[8];
-       struct bus_operations *bus;
-#endif
        int                    stop;
 } scsi_info_t;
 
index d953d43fe2e6146e62ab43ee392d3a3c0df0c2af..0363c1cd68c1faa310ec06f64f16fc6e41a8004f 100644 (file)
@@ -111,13 +111,12 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
 #endif
                        return 0;
        }
-       fcs = kmalloc(sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
+       fcs = kcalloc(fcscount, sizeof (struct ctrl_inquiry), GFP_DMA);
        if (!fcs) {
                printk ("PLUTO: Not enough memory to probe\n");
                return 0;
        }
        
-       memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount);
        memset (&dev, 0, sizeof(dev));
        atomic_set (&fcss, fcscount);
        
@@ -161,7 +160,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
        
                SCpnt->request->cmd_flags &= ~REQ_STARTED;
                
-               SCpnt->done = pluto_detect_done;
                SCpnt->request_bufflen = 256;
                SCpnt->request_buffer = fcs[i].inquiry;
                PLD(("set up %d %08lx\n", i, (long)SCpnt))
@@ -196,7 +194,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
                SCpnt = &(fcs[i].cmd);
                
                /* Let FC mid-level free allocated resources */
-               SCpnt->done (SCpnt);
+               pluto_detect_scsi_done(SCpnt);
                
                if (!SCpnt->result) {
                        struct pluto_inquiry *inq;
@@ -211,7 +209,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
                                char *p;
                                long *ages;
                                
-                               ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL);
+                               ages = kcalloc((inq->channels + 1) * inq->targets, sizeof(long), GFP_KERNEL);
                                if (!ages) continue;
                                
                                host = scsi_register (tpnt, sizeof (struct pluto));
@@ -238,7 +236,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
                                fc->channels = inq->channels + 1;
                                fc->targets = inq->targets;
                                fc->ages = ages;
-                               memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long));
                                
                                pluto->fc = fc;
                                memcpy (pluto->rev_str, inq->revision, 4);
@@ -260,7 +257,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
                } else
                        fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
        }
-       kfree((char *)fcs);
+       kfree(fcs);
        if (nplutos)
                printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos);
        return nplutos;
index b50f1e14f2a5618dab46e1a600a43d85fdc02ab3..0f43d1d046d950af370e5fc902fdbee37d4edd4a 100644 (file)
@@ -100,16 +100,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
        struct scatterlist *sgpnt;
        unsigned int buflen;
 
-       buflen = cmd->request_bufflen;
+       buflen = scsi_bufflen(cmd);
        if (!buflen)
                return 0;
 
-       if (!cmd->request_buffer)
+       if (!scsi_sglist(cmd))
                return -1;
 
-       sgpnt = cmd->request_buffer;
        active = 1;
-       for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+       req_len = act_len = 0;
+       scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
                if (active) {
                        kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
                        len = sgpnt->length;
@@ -124,7 +124,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
                }
                req_len += sgpnt->length;
        }
-       cmd->resid = req_len - act_len;
+       scsi_set_resid(cmd, req_len - act_len);
        return 0;
 }
 
@@ -138,15 +138,15 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
        struct scatterlist *sgpnt;
        unsigned int buflen;
 
-       buflen = cmd->request_bufflen;
+       buflen = scsi_bufflen(cmd);
        if (!buflen)
                return 0;
 
-       if (!cmd->request_buffer)
+       if (!scsi_sglist(cmd))
                return -1;
 
-       sgpnt = cmd->request_buffer;
-       for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+       req_len = fin = 0;
+       scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
                kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
                len = sgpnt->length;
                if ((req_len + len) > buflen) {
@@ -177,12 +177,12 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev,
        memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
        atapi_cmnd.pktlen = 12;
        atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
-       atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+       atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd);
        atapi_cmnd.buffer = dev->bounce_lpar;
 
        switch (cmd->sc_data_direction) {
        case DMA_FROM_DEVICE:
-               if (cmd->request_bufflen >= CD_FRAMESIZE)
+               if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
                        atapi_cmnd.proto = DMA_PROTO;
                else
                        atapi_cmnd.proto = PIO_DATA_IN_PROTO;
@@ -190,7 +190,7 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev,
                break;
 
        case DMA_TO_DEVICE:
-               if (cmd->request_bufflen >= CD_FRAMESIZE)
+               if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
                        atapi_cmnd.proto = DMA_PROTO;
                else
                        atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
index 54d8bdf86852b7541542298b05ce1f20b0c55c9e..fba8aa8a81b58c8f689d136cd65435d5873f5192 100644 (file)
@@ -4086,7 +4086,7 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd)
           } */
        printk("  tag=%d, transfersize=0x%x \n",
               cmd->tag, cmd->transfersize);
-       printk("  Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd));
+       printk("  Pid=%li, SP=0x%p\n", cmd->serial_number, CMD_SP(cmd));
        printk(" underflow size = 0x%x, direction=0x%x\n",
               cmd->underflow, cmd->sc_data_direction);
 }
index 0f2a9f5d801c77efb918dd140c3941051e7f41c4..05fa7796a559d325a1c44f7eb04e6b3da08f5a8b 100644 (file)
@@ -18,7 +18,7 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
                           struct bin_attribute *bin_attr,
                           char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        char *rbuf = (char *)ha->fw_dump;
 
@@ -39,7 +39,7 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
                            struct bin_attribute *bin_attr,
                            char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        int reading;
 
@@ -89,7 +89,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
                         struct bin_attribute *bin_attr,
                         char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        int             size = ha->nvram_size;
        char            *nvram_cache = ha->nvram;
@@ -112,7 +112,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
                          struct bin_attribute *bin_attr,
                          char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        unsigned long   flags;
        uint16_t        cnt;
@@ -146,7 +146,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
        /* Write NVRAM. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
        ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
-       ha->isp_ops->read_nvram(ha, (uint8_t *)&ha->nvram, ha->nvram_base,
+       ha->isp_ops->read_nvram(ha, (uint8_t *)ha->nvram, ha->nvram_base,
            count);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -170,15 +170,15 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj,
                          struct bin_attribute *bin_attr,
                          char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
 
        if (ha->optrom_state != QLA_SREADING)
                return 0;
-       if (off > ha->optrom_size)
+       if (off > ha->optrom_region_size)
                return 0;
-       if (off + count > ha->optrom_size)
-               count = ha->optrom_size - off;
+       if (off + count > ha->optrom_region_size)
+               count = ha->optrom_region_size - off;
 
        memcpy(buf, &ha->optrom_buffer[off], count);
 
@@ -190,15 +190,15 @@ qla2x00_sysfs_write_optrom(struct kobject *kobj,
                           struct bin_attribute *bin_attr,
                           char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
 
        if (ha->optrom_state != QLA_SWRITING)
                return -EINVAL;
-       if (off > ha->optrom_size)
+       if (off > ha->optrom_region_size)
                return -ERANGE;
-       if (off + count > ha->optrom_size)
-               count = ha->optrom_size - off;
+       if (off + count > ha->optrom_region_size)
+               count = ha->optrom_region_size - off;
 
        memcpy(&ha->optrom_buffer[off], buf, count);
 
@@ -220,14 +220,18 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
                               struct bin_attribute *bin_attr,
                               char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
-       int val;
+       uint32_t start = 0;
+       uint32_t size = ha->optrom_size;
+       int val, valid;
 
        if (off)
                return 0;
 
-       if (sscanf(buf, "%d", &val) != 1)
+       if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1)
+               return -EINVAL;
+       if (start > ha->optrom_size)
                return -EINVAL;
 
        switch (val) {
@@ -237,6 +241,11 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
                        break;
 
                ha->optrom_state = QLA_SWAITING;
+
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "Freeing flash region allocation -- 0x%x bytes.\n",
+                   ha->optrom_region_size));
+
                vfree(ha->optrom_buffer);
                ha->optrom_buffer = NULL;
                break;
@@ -244,44 +253,107 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
                if (ha->optrom_state != QLA_SWAITING)
                        break;
 
+               if (start & 0xfff) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Invalid start region 0x%x/0x%x.\n", start, size);
+                       return -EINVAL;
+               }
+
+               ha->optrom_region_start = start;
+               ha->optrom_region_size = start + size > ha->optrom_size ?
+                   ha->optrom_size - start : size;
+
                ha->optrom_state = QLA_SREADING;
-               ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
+               ha->optrom_buffer = vmalloc(ha->optrom_region_size);
                if (ha->optrom_buffer == NULL) {
                        qla_printk(KERN_WARNING, ha,
                            "Unable to allocate memory for optrom retrieval "
-                           "(%x).\n", ha->optrom_size);
+                           "(%x).\n", ha->optrom_region_size);
 
                        ha->optrom_state = QLA_SWAITING;
                        return count;
                }
 
-               memset(ha->optrom_buffer, 0, ha->optrom_size);
-               ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0,
-                   ha->optrom_size);
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "Reading flash region -- 0x%x/0x%x.\n",
+                   ha->optrom_region_start, ha->optrom_region_size));
+
+               memset(ha->optrom_buffer, 0, ha->optrom_region_size);
+               ha->isp_ops->read_optrom(ha, ha->optrom_buffer,
+                   ha->optrom_region_start, ha->optrom_region_size);
                break;
        case 2:
                if (ha->optrom_state != QLA_SWAITING)
                        break;
 
+               /*
+                * We need to be more restrictive on which FLASH regions are
+                * allowed to be updated via user-space.  Regions accessible
+                * via this method include:
+                *
+                * ISP21xx/ISP22xx/ISP23xx type boards:
+                *
+                *      0x000000 -> 0x020000 -- Boot code.
+                *
+                * ISP2322/ISP24xx type boards:
+                *
+                *      0x000000 -> 0x07ffff -- Boot code.
+                *      0x080000 -> 0x0fffff -- Firmware.
+                *
+                * ISP25xx type boards:
+                *
+                *      0x000000 -> 0x07ffff -- Boot code.
+                *      0x080000 -> 0x0fffff -- Firmware.
+                *      0x120000 -> 0x12ffff -- VPD and HBA parameters.
+                */
+               valid = 0;
+               if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
+                       valid = 1;
+               else if (start == (FA_BOOT_CODE_ADDR*4) ||
+                   start == (FA_RISC_CODE_ADDR*4))
+                       valid = 1;
+               else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4))
+                   valid = 1;
+               if (!valid) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Invalid start region 0x%x/0x%x.\n", start, size);
+                       return -EINVAL;
+               }
+
+               ha->optrom_region_start = start;
+               ha->optrom_region_size = start + size > ha->optrom_size ?
+                   ha->optrom_size - start : size;
+
                ha->optrom_state = QLA_SWRITING;
-               ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
+               ha->optrom_buffer = vmalloc(ha->optrom_region_size);
                if (ha->optrom_buffer == NULL) {
                        qla_printk(KERN_WARNING, ha,
                            "Unable to allocate memory for optrom update "
-                           "(%x).\n", ha->optrom_size);
+                           "(%x).\n", ha->optrom_region_size);
 
                        ha->optrom_state = QLA_SWAITING;
                        return count;
                }
-               memset(ha->optrom_buffer, 0, ha->optrom_size);
+
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "Staging flash region write -- 0x%x/0x%x.\n",
+                   ha->optrom_region_start, ha->optrom_region_size));
+
+               memset(ha->optrom_buffer, 0, ha->optrom_region_size);
                break;
        case 3:
                if (ha->optrom_state != QLA_SWRITING)
                        break;
 
-               ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0,
-                   ha->optrom_size);
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "Writing flash region -- 0x%x/0x%x.\n",
+                   ha->optrom_region_start, ha->optrom_region_size));
+
+               ha->isp_ops->write_optrom(ha, ha->optrom_buffer,
+                   ha->optrom_region_start, ha->optrom_region_size);
                break;
+       default:
+               count = -EINVAL;
        }
        return count;
 }
@@ -300,7 +372,7 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
                       struct bin_attribute *bin_attr,
                       char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        int           size = ha->vpd_size;
        char          *vpd_cache = ha->vpd;
@@ -323,7 +395,7 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj,
                        struct bin_attribute *bin_attr,
                        char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        unsigned long flags;
 
@@ -354,7 +426,7 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj,
                       struct bin_attribute *bin_attr,
                       char *buf, loff_t off, size_t count)
 {
-       struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+       struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        uint16_t iter, addr, offset;
        int rval;
@@ -459,7 +531,7 @@ qla2x00_drvr_version_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_fw_version_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        char fw_str[30];
 
        return snprintf(buf, PAGE_SIZE, "%s\n",
@@ -469,7 +541,7 @@ qla2x00_fw_version_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_serial_num_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        uint32_t sn;
 
        sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
@@ -480,14 +552,14 @@ qla2x00_serial_num_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_isp_name_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        return snprintf(buf, PAGE_SIZE, "ISP%04X\n", ha->pdev->device);
 }
 
 static ssize_t
 qla2x00_isp_id_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
            ha->product_id[0], ha->product_id[1], ha->product_id[2],
            ha->product_id[3]);
@@ -496,14 +568,14 @@ qla2x00_isp_id_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_model_name_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
 }
 
 static ssize_t
 qla2x00_model_desc_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        return snprintf(buf, PAGE_SIZE, "%s\n",
            ha->model_desc ? ha->model_desc: "");
 }
@@ -511,7 +583,7 @@ qla2x00_model_desc_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_pci_info_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        char pci_info[30];
 
        return snprintf(buf, PAGE_SIZE, "%s\n",
@@ -521,7 +593,7 @@ qla2x00_pci_info_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_state_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        int len = 0;
 
        if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
@@ -559,7 +631,7 @@ qla2x00_state_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_zio_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        int len = 0;
 
        switch (ha->zio_mode) {
@@ -576,7 +648,7 @@ qla2x00_zio_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        int val = 0;
        uint16_t zio_mode;
 
@@ -602,7 +674,7 @@ qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
 static ssize_t
 qla2x00_zio_timer_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
 
        return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100);
 }
@@ -611,7 +683,7 @@ static ssize_t
 qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
     size_t count)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        int val = 0;
        uint16_t zio_timer;
 
@@ -629,7 +701,7 @@ qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
 static ssize_t
 qla2x00_beacon_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        int len = 0;
 
        if (ha->beacon_blink_led)
@@ -643,7 +715,7 @@ static ssize_t
 qla2x00_beacon_store(struct class_device *cdev, const char *buf,
     size_t count)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
        int val = 0;
        int rval;
 
@@ -673,7 +745,7 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf,
 static ssize_t
 qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
 
        return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
            ha->bios_revision[0]);
@@ -682,7 +754,7 @@ qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
 
        return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
            ha->efi_revision[0]);
@@ -691,7 +763,7 @@ qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
 
        return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
            ha->fcode_revision[0]);
@@ -700,7 +772,7 @@ qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
 static ssize_t
 qla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf)
 {
-       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
 
        return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
            ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
@@ -757,7 +829,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
 static void
 qla2x00_get_host_port_id(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        fc_host_port_id(shost) = ha->d_id.b.domain << 16 |
            ha->d_id.b.area << 8 | ha->d_id.b.al_pa;
@@ -766,7 +838,7 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost)
 static void
 qla2x00_get_host_speed(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
        uint32_t speed = 0;
 
        switch (ha->link_data_rate) {
@@ -786,7 +858,7 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
 static void
 qla2x00_get_host_port_type(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
        uint32_t port_type = FC_PORTTYPE_UNKNOWN;
 
        switch (ha->current_topology) {
@@ -810,7 +882,7 @@ static void
 qla2x00_get_starget_node_name(struct scsi_target *starget)
 {
        struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
-       scsi_qla_host_t *ha = to_qla_host(host);
+       scsi_qla_host_t *ha = shost_priv(host);
        fc_port_t *fcport;
        u64 node_name = 0;
 
@@ -828,7 +900,7 @@ static void
 qla2x00_get_starget_port_name(struct scsi_target *starget)
 {
        struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
-       scsi_qla_host_t *ha = to_qla_host(host);
+       scsi_qla_host_t *ha = shost_priv(host);
        fc_port_t *fcport;
        u64 port_name = 0;
 
@@ -846,7 +918,7 @@ static void
 qla2x00_get_starget_port_id(struct scsi_target *starget)
 {
        struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
-       scsi_qla_host_t *ha = to_qla_host(host);
+       scsi_qla_host_t *ha = shost_priv(host);
        fc_port_t *fcport;
        uint32_t port_id = ~0U;
 
@@ -865,7 +937,7 @@ static void
 qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
 {
        struct Scsi_Host *host = rport_to_shost(rport);
-       scsi_qla_host_t *ha = to_qla_host(host);
+       scsi_qla_host_t *ha = shost_priv(host);
 
        rport->dev_loss_tmo = ha->port_down_retry_count + 5;
 }
@@ -874,7 +946,7 @@ static void
 qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
 {
        struct Scsi_Host *host = rport_to_shost(rport);
-       scsi_qla_host_t *ha = to_qla_host(host);
+       scsi_qla_host_t *ha = shost_priv(host);
 
        if (timeout)
                ha->port_down_retry_count = timeout;
@@ -887,7 +959,7 @@ qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
 static int
 qla2x00_issue_lip(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
        return 0;
@@ -896,7 +968,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
 static struct fc_host_statistics *
 qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
        int rval;
        uint16_t mb_stat[1];
        link_stat_t stat_buf;
@@ -934,7 +1006,7 @@ done:
 static void
 qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
 }
@@ -942,7 +1014,7 @@ qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
 static void
 qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
 }
@@ -950,7 +1022,7 @@ qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
 static void
 qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
        u64 node_name;
 
        if (ha->device_flags & SWITCH_FOUND)
@@ -964,7 +1036,7 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
 static void
 qla2x00_get_host_port_state(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = to_qla_host(shost);
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        if (!ha->flags.online)
                fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
@@ -978,7 +1050,7 @@ static int
 qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 {
        int     ret = 0;
-       scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
        scsi_qla_host_t *vha;
 
        ret = qla24xx_vport_create_req_sanity_check(fc_vport);
@@ -1047,7 +1119,7 @@ vport_create_failed_2:
 int
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 {
-       scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
        scsi_qla_host_t *vha = fc_vport->dd_data;
 
        qla24xx_disable_vp(vha);
@@ -1178,6 +1250,6 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
        fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
        fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
        fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
-       fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC;
+       fc_host_max_npiv_vports(ha->host) = ha->max_npiv_vports;;
        fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
 }
index c6680348b64847be9c18290181fbe01acc45d3bf..eaa04dabcdf6b4fd331f6572e46691a727fe8fd4 100644 (file)
@@ -38,7 +38,7 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
 }
 
 static int
-qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
+qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
     uint32_t cram_size, uint32_t *ext_mem, void **nxt)
 {
        int rval;
@@ -152,6 +152,103 @@ qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
        return rval;
 }
 
+static uint32_t *
+qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
+    uint32_t count, uint32_t *buf)
+{
+       uint32_t __iomem *dmp_reg;
+
+       WRT_REG_DWORD(&reg->iobase_addr, iobase);
+       dmp_reg = &reg->iobase_window;
+       while (count--)
+               *buf++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+       return buf;
+}
+
+static inline int
+qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
+{
+       int rval = QLA_SUCCESS;
+       uint32_t cnt;
+
+       if (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE)
+               return rval;
+
+       WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+       for (cnt = 30000; (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt)
+                       udelay(100);
+               else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+
+       return rval;
+}
+
+static int
+qla24xx_soft_reset(scsi_qla_host_t *ha)
+{
+       int rval = QLA_SUCCESS;
+       uint32_t cnt;
+       uint16_t mb0, wd;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       /* Reset RISC. */
+       WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+       for (cnt = 0; cnt < 30000; cnt++) {
+               if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
+                       break;
+
+               udelay(10);
+       }
+
+       WRT_REG_DWORD(&reg->ctrl_status,
+           CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+       pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
+
+       udelay(100);
+       /* Wait for firmware to complete NVRAM accesses. */
+       mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+       for (cnt = 10000 ; cnt && mb0; cnt--) {
+               udelay(5);
+               mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+               barrier();
+       }
+
+       /* Wait for soft-reset to complete. */
+       for (cnt = 0; cnt < 30000; cnt++) {
+               if ((RD_REG_DWORD(&reg->ctrl_status) &
+                   CSRX_ISP_SOFT_RESET) == 0)
+                       break;
+
+               udelay(10);
+       }
+       WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
+       RD_REG_DWORD(&reg->hccr);             /* PCI Posting. */
+
+       for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt)
+                       udelay(100);
+               else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+
+       return rval;
+}
+
+static inline void
+qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
+    uint16_t *buf)
+{
+       uint16_t __iomem *dmp_reg = &reg->u.isp2300.fb_cmd;
+
+       while (count--)
+               *buf++ = htons(RD_REG_WORD(dmp_reg++));
+}
+
 /**
  * qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
  * @ha: HA context
@@ -214,88 +311,61 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        }
 
        if (rval == QLA_SUCCESS) {
-               dmp_reg = (uint16_t __iomem *)(reg + 0);
+               dmp_reg = &reg->flash_address;
                for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
                        fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
 
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+               dmp_reg = &reg->u.isp2300.req_q_in;
                for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
                        fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
 
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40);
+               dmp_reg = &reg->u.isp2300.mailbox0;
                for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
                        fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
 
                WRT_REG_WORD(&reg->ctrl_status, 0x40);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++)
-                       fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 32, fw->resp_dma_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x50);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
-                       fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 48, fw->dma_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x00);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+               dmp_reg = &reg->risc_hw;
                for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
                        fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
 
                WRT_REG_WORD(&reg->pcr, 0x2000);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
-                       fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2200);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
-                       fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2400);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
-                       fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2600);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
-                       fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2800);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
-                       fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2A00);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
-                       fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2C00);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
-                       fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2E00);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
-                       fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x10);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
-                       fw->frame_buf_hdw_reg[cnt] =
-                           htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 64, fw->frame_buf_hdw_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x20);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
-                       fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x30);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
-                       fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
 
                /* Reset RISC. */
                WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -567,83 +637,59 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
                        rval = QLA_FUNCTION_TIMEOUT;
        }
        if (rval == QLA_SUCCESS) {
-               dmp_reg = (uint16_t __iomem *)(reg + 0);
+               dmp_reg = &reg->flash_address;
                for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
                        fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
 
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+               dmp_reg = &reg->u.isp2100.mailbox0;
                for (cnt = 0; cnt < ha->mbx_count; cnt++) {
-                       if (cnt == 8) {
-                               dmp_reg = (uint16_t __iomem *)
-                                       ((uint8_t __iomem *)reg + 0xe0);
-                       }
+                       if (cnt == 8)
+                               dmp_reg = &reg->u_end.isp2200.mailbox8;
+
                        fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
                }
 
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20);
+               dmp_reg = &reg->u.isp2100.unused_2[0];
                for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
                        fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
 
                WRT_REG_WORD(&reg->ctrl_status, 0x00);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+               dmp_reg = &reg->risc_hw;
                for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
                        fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
 
                WRT_REG_WORD(&reg->pcr, 0x2000);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
-                       fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2100);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
-                       fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2200);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
-                       fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2300);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
-                       fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2400);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
-                       fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2500);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
-                       fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2600);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
-                       fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
 
                WRT_REG_WORD(&reg->pcr, 0x2700);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
-                       fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x10);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
-                       fw->frame_buf_hdw_reg[cnt] =
-                           htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 16, fw->frame_buf_hdw_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x20);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
-                       fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
 
                WRT_REG_WORD(&reg->ctrl_status, 0x30);
-               dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
-               for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
-                       fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+               qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
 
                /* Reset the ISP. */
                WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -750,7 +796,6 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        int             rval;
        uint32_t        cnt;
        uint32_t        risc_address;
-       uint16_t        mb0, wd;
 
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
        uint32_t __iomem *dmp_reg;
@@ -782,547 +827,198 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        fw = &ha->fw_dump->isp.isp24;
        qla2xxx_prep_dump(ha, ha->fw_dump);
 
-       rval = QLA_SUCCESS;
        fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
 
        /* Pause RISC. */
-       if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
-               WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
-                   HCCRX_CLR_HOST_INT);
-               RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
-               WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
-               for (cnt = 30000;
-                   (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
-                   rval == QLA_SUCCESS; cnt--) {
-                       if (cnt)
-                               udelay(100);
-                       else
-                               rval = QLA_FUNCTION_TIMEOUT;
-               }
-       }
-
-       if (rval == QLA_SUCCESS) {
-               /* Host interface registers. */
-               dmp_reg = (uint32_t __iomem *)(reg + 0);
-               for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
-                       fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Disable interrupts. */
-               WRT_REG_DWORD(&reg->ictrl, 0);
-               RD_REG_DWORD(&reg->ictrl);
-
-               /* Shadow registers. */
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
-               RD_REG_DWORD(&reg->iobase_addr);
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
-               fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
-               fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
-               fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
-               fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
-               fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
-               fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
-               fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               /* Mailbox registers. */
-               mbx_reg = &reg->mailbox0;
-               for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
-                       fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
-
-               /* Transfer sequence registers. */
-               iter_reg = fw->xseq_gp_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
-                       fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
-                       fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Receive sequence registers. */
-               iter_reg = fw->rseq_gp_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
-                       fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
-                       fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
-                       fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Command DMA registers. */
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
-                       fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Queues. */
-               iter_reg = fw->req0_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 8; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               dmp_reg = &reg->iobase_q;
-               for (cnt = 0; cnt < 7; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->resp0_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 8; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               dmp_reg = &reg->iobase_q;
-               for (cnt = 0; cnt < 7; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->req1_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 8; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               dmp_reg = &reg->iobase_q;
-               for (cnt = 0; cnt < 7; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Transmit DMA registers. */
-               iter_reg = fw->xmt0_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt1_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt2_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt3_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt4_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
-                       fw->xmt_data_dma_reg[cnt] =
-                           htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Receive DMA registers. */
-               iter_reg = fw->rcvt0_data_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->rcvt1_data_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* RISC registers. */
-               iter_reg = fw->risc_gp_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Local memory controller registers. */
-               iter_reg = fw->lmc_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Fibre Protocol Module registers. */
-               iter_reg = fw->fpm_hdw_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Frame Buffer registers. */
-               iter_reg = fw->fb_hdw_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Reset RISC. */
-               WRT_REG_DWORD(&reg->ctrl_status,
-                   CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
-               for (cnt = 0; cnt < 30000; cnt++) {
-                       if ((RD_REG_DWORD(&reg->ctrl_status) &
-                           CSRX_DMA_ACTIVE) == 0)
-                               break;
-
-                       udelay(10);
-               }
-
-               WRT_REG_DWORD(&reg->ctrl_status,
-                   CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
-               pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
-
-               udelay(100);
-               /* Wait for firmware to complete NVRAM accesses. */
-               mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
-               for (cnt = 10000 ; cnt && mb0; cnt--) {
-                       udelay(5);
-                       mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
-                       barrier();
-               }
-
-               /* Wait for soft-reset to complete. */
-               for (cnt = 0; cnt < 30000; cnt++) {
-                       if ((RD_REG_DWORD(&reg->ctrl_status) &
-                           CSRX_ISP_SOFT_RESET) == 0)
-                               break;
-
-                       udelay(10);
-               }
-               WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
-               RD_REG_DWORD(&reg->hccr);             /* PCI Posting. */
-       }
-
-       for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
-           rval == QLA_SUCCESS; cnt--) {
-               if (cnt)
-                       udelay(100);
-               else
-                       rval = QLA_FUNCTION_TIMEOUT;
-       }
-
-       if (rval == QLA_SUCCESS)
-               rval = qla2xxx_dump_memory(ha, fw->code_ram,
-                   sizeof(fw->code_ram), fw->ext_mem, &nxt);
-
-       if (rval == QLA_SUCCESS) {
-               nxt = qla2xxx_copy_queues(ha, nxt);
-               if (ha->eft)
-                       memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
-       }
-
+       rval = qla24xx_pause_risc(reg);
+       if (rval != QLA_SUCCESS)
+               goto qla24xx_fw_dump_failed_0;
+
+       /* Host interface registers. */
+       dmp_reg = &reg->flash_addr;
+       for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+               fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+       /* Disable interrupts. */
+       WRT_REG_DWORD(&reg->ictrl, 0);
+       RD_REG_DWORD(&reg->ictrl);
+
+       /* Shadow registers. */
+       WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+       RD_REG_DWORD(&reg->iobase_addr);
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+       fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+       fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+       fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+       fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+       fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+       fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+       fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       /* Mailbox registers. */
+       mbx_reg = &reg->mailbox0;
+       for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+               fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+       /* Transfer sequence registers. */
+       iter_reg = fw->xseq_gp_reg;
+       iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+       qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+       qla24xx_read_window(reg, 0xBFE0, 16, fw->xseq_0_reg);
+       qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+       /* Receive sequence registers. */
+       iter_reg = fw->rseq_gp_reg;
+       iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+       qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+       qla24xx_read_window(reg, 0xFFD0, 16, fw->rseq_0_reg);
+       qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+       qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+
+       /* Command DMA registers. */
+       qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);
+
+       /* Queues. */
+       iter_reg = fw->req0_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+       dmp_reg = &reg->iobase_q;
+       for (cnt = 0; cnt < 7; cnt++)
+               *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+       iter_reg = fw->resp0_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+       dmp_reg = &reg->iobase_q;
+       for (cnt = 0; cnt < 7; cnt++)
+               *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+       iter_reg = fw->req1_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+       dmp_reg = &reg->iobase_q;
+       for (cnt = 0; cnt < 7; cnt++)
+               *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+       /* Transmit DMA registers. */
+       iter_reg = fw->xmt0_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+       iter_reg = fw->xmt1_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+       iter_reg = fw->xmt2_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+       iter_reg = fw->xmt3_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+       iter_reg = fw->xmt4_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+       qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+       /* Receive DMA registers. */
+       iter_reg = fw->rcvt0_data_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+       iter_reg = fw->rcvt1_data_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+       /* RISC registers. */
+       iter_reg = fw->risc_gp_reg;
+       iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+       qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+       /* Local memory controller registers. */
+       iter_reg = fw->lmc_reg;
+       iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+       qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+
+       /* Fibre Protocol Module registers. */
+       iter_reg = fw->fpm_hdw_reg;
+       iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+       qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+
+       /* Frame Buffer registers. */
+       iter_reg = fw->fb_hdw_reg;
+       iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+       qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+
+       rval = qla24xx_soft_reset(ha);
+       if (rval != QLA_SUCCESS)
+               goto qla24xx_fw_dump_failed_0;
+
+       rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+           fw->ext_mem, &nxt);
+       if (rval != QLA_SUCCESS)
+               goto qla24xx_fw_dump_failed_0;
+
+       nxt = qla2xxx_copy_queues(ha, nxt);
+       if (ha->eft)
+               memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+
+qla24xx_fw_dump_failed_0:
        if (rval != QLA_SUCCESS) {
                qla_printk(KERN_WARNING, ha,
                    "Failed to dump firmware (%x)!!!\n", rval);
@@ -1346,7 +1042,6 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        int             rval;
        uint32_t        cnt;
        uint32_t        risc_address;
-       uint16_t        mb0, wd;
 
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
        uint32_t __iomem *dmp_reg;
@@ -1377,655 +1072,260 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        }
        fw = &ha->fw_dump->isp.isp25;
        qla2xxx_prep_dump(ha, ha->fw_dump);
+       ha->fw_dump->version = __constant_htonl(2);
 
-       rval = QLA_SUCCESS;
        fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
 
        /* Pause RISC. */
-       if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
-               WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
-                   HCCRX_CLR_HOST_INT);
-               RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
-               WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
-               for (cnt = 30000;
-                   (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
-                   rval == QLA_SUCCESS; cnt--) {
-                       if (cnt)
-                               udelay(100);
-                       else
-                               rval = QLA_FUNCTION_TIMEOUT;
-               }
-       }
-
-       if (rval == QLA_SUCCESS) {
-               /* Host interface registers. */
-               dmp_reg = (uint32_t __iomem *)(reg + 0);
-               for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
-                       fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Disable interrupts. */
-               WRT_REG_DWORD(&reg->ictrl, 0);
-               RD_REG_DWORD(&reg->ictrl);
-
-               /* Shadow registers. */
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
-               RD_REG_DWORD(&reg->iobase_addr);
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
-               fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
-               fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
-               fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
-               fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
-               fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
-               fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
-               fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
-               fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
-               fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
-               fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
-               fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
-               /* RISC I/O register. */
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
-               RD_REG_DWORD(&reg->iobase_addr);
-               fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
-
-               /* Mailbox registers. */
-               mbx_reg = &reg->mailbox0;
-               for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
-                       fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
-
-               /* Transfer sequence registers. */
-               iter_reg = fw->xseq_gp_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xseq_0_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBFC0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBFD0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
-                       fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Receive sequence registers. */
-               iter_reg = fw->rseq_gp_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->rseq_0_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFFC0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
-                       fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
-                       fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Auxiliary sequence registers. */
-               iter_reg = fw->aseq_gp_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB000);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB010);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB020);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB030);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB040);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB050);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB060);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB070);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->aseq_0_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB0C0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB0D0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB0E0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->aseq_1_reg) / 4; cnt++)
-                       fw->aseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0xB0F0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->aseq_2_reg) / 4; cnt++)
-                       fw->aseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Command DMA registers. */
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
-                       fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Queues. */
-               iter_reg = fw->req0_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 8; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               dmp_reg = &reg->iobase_q;
-               for (cnt = 0; cnt < 7; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->resp0_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 8; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               dmp_reg = &reg->iobase_q;
-               for (cnt = 0; cnt < 7; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->req1_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 8; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               dmp_reg = &reg->iobase_q;
-               for (cnt = 0; cnt < 7; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Transmit DMA registers. */
-               iter_reg = fw->xmt0_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt1_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt2_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt3_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->xmt4_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
-                       fw->xmt_data_dma_reg[cnt] =
-                           htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Receive DMA registers. */
-               iter_reg = fw->rcvt0_data_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               iter_reg = fw->rcvt1_data_dma_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* RISC registers. */
-               iter_reg = fw->risc_gp_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Local memory controller registers. */
-               iter_reg = fw->lmc_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x3070);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Fibre Protocol Module registers. */
-               iter_reg = fw->fpm_hdw_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Frame Buffer registers. */
-               iter_reg = fw->fb_hdw_reg;
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               WRT_REG_DWORD(&reg->iobase_addr, 0x6F00);
-               dmp_reg = &reg->iobase_window;
-               for (cnt = 0; cnt < 16; cnt++)
-                       *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
-               /* Reset RISC. */
-               WRT_REG_DWORD(&reg->ctrl_status,
-                   CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
-               for (cnt = 0; cnt < 30000; cnt++) {
-                       if ((RD_REG_DWORD(&reg->ctrl_status) &
-                           CSRX_DMA_ACTIVE) == 0)
-                               break;
-
-                       udelay(10);
-               }
-
-               WRT_REG_DWORD(&reg->ctrl_status,
-                   CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
-               pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
-
-               udelay(100);
-               /* Wait for firmware to complete NVRAM accesses. */
-               mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
-               for (cnt = 10000 ; cnt && mb0; cnt--) {
-                       udelay(5);
-                       mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
-                       barrier();
-               }
-
-               /* Wait for soft-reset to complete. */
-               for (cnt = 0; cnt < 30000; cnt++) {
-                       if ((RD_REG_DWORD(&reg->ctrl_status) &
-                           CSRX_ISP_SOFT_RESET) == 0)
-                               break;
-
-                       udelay(10);
-               }
-               WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
-               RD_REG_DWORD(&reg->hccr);             /* PCI Posting. */
-       }
-
-       for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
-           rval == QLA_SUCCESS; cnt--) {
-               if (cnt)
-                       udelay(100);
-               else
-                       rval = QLA_FUNCTION_TIMEOUT;
-       }
-
-       if (rval == QLA_SUCCESS)
-               rval = qla2xxx_dump_memory(ha, fw->code_ram,
-                   sizeof(fw->code_ram), fw->ext_mem, &nxt);
-
-       if (rval == QLA_SUCCESS) {
-               nxt = qla2xxx_copy_queues(ha, nxt);
-               if (ha->eft)
-                       memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
-       }
-
+       rval = qla24xx_pause_risc(reg);
+       if (rval != QLA_SUCCESS)
+               goto qla25xx_fw_dump_failed_0;
+
+       /* Host/Risc registers. */
+       iter_reg = fw->host_risc_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7010, 16, iter_reg);
+
+       /* PCIe registers. */
+       WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+       RD_REG_DWORD(&reg->iobase_addr);
+       WRT_REG_DWORD(&reg->iobase_window, 0x01);
+       dmp_reg = &reg->iobase_c4;
+       fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
+       fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+       fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
+       fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
+       WRT_REG_DWORD(&reg->iobase_window, 0x00);
+       RD_REG_DWORD(&reg->iobase_window);
+
+       /* Host interface registers. */
+       dmp_reg = &reg->flash_addr;
+       for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+               fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+       /* Disable interrupts. */
+       WRT_REG_DWORD(&reg->ictrl, 0);
+       RD_REG_DWORD(&reg->ictrl);
+
+       /* Shadow registers. */
+       WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+       RD_REG_DWORD(&reg->iobase_addr);
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+       fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+       fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+       fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+       fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+       fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+       fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+       fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+       fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+       fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+       fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+       fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+       /* RISC I/O register. */
+       WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+       fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+       /* Mailbox registers. */
+       mbx_reg = &reg->mailbox0;
+       for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+               fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+       /* Transfer sequence registers. */
+       iter_reg = fw->xseq_gp_reg;
+       iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+       qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+       iter_reg = fw->xseq_0_reg;
+       iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg);
+       qla24xx_read_window(reg, 0xBFE0, 16, iter_reg);
+
+       qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+       /* Receive sequence registers. */
+       iter_reg = fw->rseq_gp_reg;
+       iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+       qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+       iter_reg = fw->rseq_0_reg;
+       iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg);
+       qla24xx_read_window(reg, 0xFFD0, 16, iter_reg);
+
+       qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+       qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+
+       /* Auxiliary sequence registers. */
+       iter_reg = fw->aseq_gp_reg;
+       iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg);
+       qla24xx_read_window(reg, 0xB070, 16, iter_reg);
+
+       iter_reg = fw->aseq_0_reg;
+       iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg);
+       qla24xx_read_window(reg, 0xB0D0, 16, iter_reg);
+
+       qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg);
+       qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg);
+
+       /* Command DMA registers. */
+       qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);
+
+       /* Queues. */
+       iter_reg = fw->req0_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+       dmp_reg = &reg->iobase_q;
+       for (cnt = 0; cnt < 7; cnt++)
+               *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+       iter_reg = fw->resp0_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+       dmp_reg = &reg->iobase_q;
+       for (cnt = 0; cnt < 7; cnt++)
+               *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+       iter_reg = fw->req1_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+       dmp_reg = &reg->iobase_q;
+       for (cnt = 0; cnt < 7; cnt++)
+               *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+       /* Transmit DMA registers. */
+       iter_reg = fw->xmt0_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+       iter_reg = fw->xmt1_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+       iter_reg = fw->xmt2_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+       iter_reg = fw->xmt3_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+       iter_reg = fw->xmt4_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+       qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+       /* Receive DMA registers. */
+       iter_reg = fw->rcvt0_data_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+       iter_reg = fw->rcvt1_data_dma_reg;
+       iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+       qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+       /* RISC registers. */
+       iter_reg = fw->risc_gp_reg;
+       iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+       qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+       /* Local memory controller registers. */
+       iter_reg = fw->lmc_reg;
+       iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+       qla24xx_read_window(reg, 0x3070, 16, iter_reg);
+
+       /* Fibre Protocol Module registers. */
+       iter_reg = fw->fpm_hdw_reg;
+       iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+       qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+
+       /* Frame Buffer registers. */
+       iter_reg = fw->fb_hdw_reg;
+       iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+       iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+       qla24xx_read_window(reg, 0x6F00, 16, iter_reg);
+
+       rval = qla24xx_soft_reset(ha);
+       if (rval != QLA_SUCCESS)
+               goto qla25xx_fw_dump_failed_0;
+
+       rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+           fw->ext_mem, &nxt);
+       if (rval != QLA_SUCCESS)
+               goto qla25xx_fw_dump_failed_0;
+
+       nxt = qla2xxx_copy_queues(ha, nxt);
+       if (ha->eft)
+               memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+
+qla25xx_fw_dump_failed_0:
        if (rval != QLA_SUCCESS) {
                qla_printk(KERN_WARNING, ha,
                    "Failed to dump firmware (%x)!!!\n", rval);
@@ -2102,7 +1402,7 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
        struct scsi_qla_host *ha;
        srb_t *sp;
 
-       ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
+       ha = shost_priv(cmd->device->host);
 
        sp = (srb_t *) cmd->SCp.ptr;
        printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
index cca4b0d8253eae3c164f73adb57dc8ec68ce20bb..a50ecf0b7c8452b144b1459d247897a9bfef6b4f 100644 (file)
@@ -215,6 +215,8 @@ struct qla24xx_fw_dump {
 
 struct qla25xx_fw_dump {
        uint32_t host_status;
+       uint32_t host_risc_reg[32];
+       uint32_t pcie_regs[4];
        uint32_t host_reg[32];
        uint32_t shadow_reg[11];
        uint32_t risc_io_reg;
index c1964866a4234338e52fa47b68895f77bf25fd79..1900fbf6cd74ddfbc7eb7a9ef7e6c233d8686012 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
 #include <linux/firmware.h>
+#include <linux/aer.h>
 #include <asm/semaphore.h>
 
 #include <scsi/scsi.h>
  * SCSI Request Block
  */
 typedef struct srb {
-       struct list_head list;
-
        struct scsi_qla_host *ha;       /* HA the SP is queued on */
        struct fc_port *fcport;
 
@@ -316,7 +315,9 @@ struct device_reg_2xxx {
        } u;
 
        uint16_t fpm_diag_config;
-       uint16_t unused_5[0x6];         /* Gap */
+       uint16_t unused_5[0x4];         /* Gap */
+       uint16_t risc_hw;
+       uint16_t unused_5_1;            /* Gap */
        uint16_t pcr;                   /* Processor Control Register. */
        uint16_t unused_6[0x5];         /* Gap */
        uint16_t mctr;                  /* Memory Configuration and Timing. */
@@ -1702,7 +1703,7 @@ struct ct_fdmi_hba_attributes {
 /*
  * Port attribute types.
  */
-#define FDMI_PORT_ATTR_COUNT           5
+#define FDMI_PORT_ATTR_COUNT           6
 #define FDMI_PORT_FC4_TYPES            1
 #define FDMI_PORT_SUPPORT_SPEED                2
 #define FDMI_PORT_CURRENT_SPEED                3
@@ -2476,6 +2477,8 @@ typedef struct scsi_qla_host {
 #define QLA_SWAITING   0
 #define QLA_SREADING   1
 #define QLA_SWRITING   2
+       uint32_t        optrom_region_start;
+       uint32_t        optrom_region_size;
 
         /* PCI expansion ROM image information. */
 #define ROM_CODE_TYPE_BIOS     0
@@ -2529,7 +2532,7 @@ typedef struct scsi_qla_host {
 #define VP_ERR_FAB_NORESOURCES 3
 #define VP_ERR_FAB_LOGOUT      4
 #define VP_ERR_ADAP_NORESOURCES        5
-       int             max_npiv_vports;        /* 63 or 125 per topoloty */
+       uint16_t        max_npiv_vports;        /* 63 or 125 per topoloty */
        int             cur_vport_count;
 } scsi_qla_host_t;
 
@@ -2542,8 +2545,6 @@ typedef struct scsi_qla_host {
         test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \
         atomic_read(&ha->loop_state) == LOOP_DOWN)
 
-#define to_qla_host(x)         ((scsi_qla_host_t *) (x)->hostdata)
-
 #define qla_printk(level, ha, format, arg...) \
        dev_printk(level , &((ha)->pdev->dev) , format , ## arg)
 
index 99fe49618d6134c5342478755e701ac4d6f32b76..25364b1aaf12327daf2dac3e1ea34ce8286f147d 100644 (file)
@@ -779,6 +779,8 @@ struct device_reg_24xx {
 #define FA_NVRAM_VPD_SIZE      0x200
 #define FA_NVRAM_VPD0_ADDR     0x00
 #define FA_NVRAM_VPD1_ADDR     0x100
+
+#define FA_BOOT_CODE_ADDR      0x00000
                                        /*
                                         * RISC code begins at offset 512KB
                                         * within flash. Consisting of two
@@ -940,7 +942,9 @@ struct device_reg_24xx {
        uint16_t mailbox31;
 
        uint32_t iobase_window;
-       uint32_t unused_4[8];           /* Gap. */
+       uint32_t iobase_c4;
+       uint32_t iobase_c8;
+       uint32_t unused_4_1[6];         /* Gap. */
        uint32_t iobase_q;
        uint32_t unused_5[2];           /* Gap. */
        uint32_t iobase_select;
index aa1e41152283dee8992c3df86391c187b9c087e8..09cb2a9080597afc6d28bb051b8f626fdd9985d1 100644 (file)
@@ -133,6 +133,9 @@ int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
 extern int
 qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
 
+extern int
+qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
+
 extern int
 qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
 
@@ -212,8 +215,8 @@ extern int
 qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
 
 extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
-    uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
+    uint16_t *, uint16_t *, uint16_t *);
 
 extern int
 qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -302,6 +305,8 @@ extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
     uint32_t, uint32_t);
 extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
     uint32_t, uint32_t);
+extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+    uint32_t, uint32_t);
 
 extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
 extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
index a7e23583f89959d1c8150381573bb11a02d30d41..eb0784c9ff83af88fa9c291eaed5281041cb541b 100644 (file)
@@ -1517,7 +1517,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
 
        /* Attributes */
        ct_req->req.rpa.attrs.count =
-           __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
+           __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT - 1);
        entries = ct_req->req.rpa.port_name;
 
        /* FC4 types. */
@@ -1600,7 +1600,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
        /* OS device name. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
        eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME);
-       sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no);
+       strcpy(eiter->a.os_dev_name, QLA2XXX_DRIVER_NAME);
        alen = strlen(eiter->a.os_dev_name);
        alen += (alen & 3) ? (4 - (alen & 3)) : 4;
        eiter->len = cpu_to_be16(4 + alen);
@@ -1611,6 +1611,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
 
        /* Hostname. */
        if (strlen(fc_host_system_hostname(ha->host))) {
+               ct_req->req.rpa.attrs.count =
+                   __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
                eiter = (struct ct_fdmi_port_attr *) (entries + size);
                eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
                snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
index 1a058ec9bd0c6ced39b11be2a2fe17ced35ce83b..191dafd89be080763c520bfef2b41e62bba8d0f7 100644 (file)
@@ -849,7 +849,8 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha)
                return;
 
        /* Retrieve IOCB counts available to the firmware. */
-       rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt);
+       rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt,
+           &ha->max_npiv_vports);
        if (rval)
                return;
        /* No point in continuing if current settings are sufficient. */
@@ -916,9 +917,15 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
                                    &ha->fw_attributes, &ha->fw_memory_size);
                                qla2x00_resize_request_q(ha);
                                ha->flags.npiv_supported = 0;
-                               if (IS_QLA24XX(ha) &&
-                                   (ha->fw_attributes & BIT_2))
+                               if ((IS_QLA24XX(ha) || IS_QLA25XX(ha)) &&
+                                   (ha->fw_attributes & BIT_2)) {
                                        ha->flags.npiv_supported = 1;
+                                       if ((!ha->max_npiv_vports) ||
+                                           ((ha->max_npiv_vports + 1) %
+                                           MAX_MULTI_ID_FABRIC))
+                                               ha->max_npiv_vports =
+                                                   MAX_NUM_VPORT_FABRIC;
+                               }
 
                                if (ql2xallocfwdump)
                                        qla2x00_alloc_fw_dump(ha);
@@ -1155,8 +1162,7 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
 
        DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
 
-       mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
-       ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+       mid_init_cb->count = ha->max_npiv_vports;
 
        rval = qla2x00_init_firmware(ha, ha->init_cb_size);
        if (rval) {
@@ -1786,12 +1792,11 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
 {
        fc_port_t *fcport;
 
-       fcport = kmalloc(sizeof(fc_port_t), flags);
-       if (fcport == NULL)
-               return (fcport);
+       fcport = kzalloc(sizeof(fc_port_t), flags);
+       if (!fcport)
+               return NULL;
 
        /* Setup fcport template structure. */
-       memset(fcport, 0, sizeof (fc_port_t));
        fcport->ha = ha;
        fcport->vp_idx = ha->vp_idx;
        fcport->port_type = FCT_UNKNOWN;
@@ -1801,7 +1806,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
        fcport->supported_classes = FC_COS_UNSPECIFIED;
        spin_lock_init(&fcport->rport_lock);
 
-       return (fcport);
+       return fcport;
 }
 
 /*
@@ -2127,15 +2132,9 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
        if (!IS_IIDMA_CAPABLE(ha))
                return;
 
-       if (fcport->fp_speed == PORT_SPEED_UNKNOWN) {
-               DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
-                   "unsupported FM port operating speed.\n",
-                   ha->host_no, fcport->port_name[0], fcport->port_name[1],
-                   fcport->port_name[2], fcport->port_name[3],
-                   fcport->port_name[4], fcport->port_name[5],
-                   fcport->port_name[6], fcport->port_name[7]));
+       if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
+           fcport->fp_speed > ha->link_data_rate)
                return;
-       }
 
        rval = qla2x00_set_idma_speed(ha, fcport->loop_id, fcport->fp_speed,
            mb);
@@ -2473,13 +2472,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
        rval = QLA_SUCCESS;
 
        /* Try GID_PT to get device list, else GAN. */
-       swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC);
-       if (swl == NULL) {
+       swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_ATOMIC);
+       if (!swl) {
                /*EMPTY*/
                DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
                    "on GA_NXT\n", ha->host_no));
        } else {
-               memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES);
                if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) {
                        kfree(swl);
                        swl = NULL;
index 3a5e78cb6b3f62c156ba0133a06fdbf00cb6ad35..7f6a89bd94f3400f2d9987586b20c7423ae7c4cc 100644 (file)
@@ -308,7 +308,7 @@ qla2x00_start_scsi(srb_t *sp)
                handle++;
                if (handle == MAX_OUTSTANDING_COMMANDS)
                        handle = 1;
-               if (ha->outstanding_cmds[handle] == 0)
+               if (!ha->outstanding_cmds[handle])
                        break;
        }
        if (index == MAX_OUTSTANDING_COMMANDS)
@@ -711,7 +711,7 @@ qla24xx_start_scsi(srb_t *sp)
                handle++;
                if (handle == MAX_OUTSTANDING_COMMANDS)
                        handle = 1;
-               if (ha->outstanding_cmds[handle] == 0)
+               if (!ha->outstanding_cmds[handle])
                        break;
        }
        if (index == MAX_OUTSTANDING_COMMANDS)
index eecae9905ece16b2af17e3d133115778b5a7fb2a..c4768c4f39904f0fe80f53e0aeb5d17b01adde01 100644 (file)
@@ -6,6 +6,7 @@
  */
 #include "qla_def.h"
 
+#include <linux/delay.h>
 #include <scsi/scsi_tcq.h>
 
 static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
@@ -34,6 +35,7 @@ qla2100_intr_handler(int irq, void *dev_id)
        int             status;
        unsigned long   flags;
        unsigned long   iter;
+       uint16_t        hccr;
        uint16_t        mb[4];
 
        ha = (scsi_qla_host_t *) dev_id;
@@ -48,7 +50,23 @@ qla2100_intr_handler(int irq, void *dev_id)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (iter = 50; iter--; ) {
-               if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
+               hccr = RD_REG_WORD(&reg->hccr);
+               if (hccr & HCCR_RISC_PAUSE) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
+                       /*
+                        * Issue a "HARD" reset in order for the RISC interrupt
+                        * bit to be cleared.  Schedule a big hammmer to get
+                        * out of the RISC PAUSED state.
+                        */
+                       WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+                       RD_REG_WORD(&reg->hccr);
+
+                       ha->isp_ops->fw_dump(ha, 1);
+                       set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                       break;
+               } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
                        break;
 
                if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
@@ -127,6 +145,9 @@ qla2300_intr_handler(int irq, void *dev_id)
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
                if (stat & HSR_RISC_PAUSED) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
                        hccr = RD_REG_WORD(&reg->hccr);
                        if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
                                qla_printk(KERN_INFO, ha, "Parity error -- "
@@ -1464,6 +1485,52 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
        WRT_REG_DWORD(&reg->rsp_q_out, ha->rsp_ring_index);
 }
 
+static void
+qla2xxx_check_risc_status(scsi_qla_host_t *ha)
+{
+       int rval;
+       uint32_t cnt;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       if (!IS_QLA25XX(ha))
+               return;
+
+       rval = QLA_SUCCESS;
+       WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+       RD_REG_DWORD(&reg->iobase_addr);
+       WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+       for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt) {
+                       WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+                       udelay(10);
+               } else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+       if (rval == QLA_SUCCESS)
+               goto next_test;
+
+       WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+       for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt) {
+                       WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+                       udelay(10);
+               } else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+       if (rval != QLA_SUCCESS)
+               goto done;
+
+next_test:
+       if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
+               qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
+
+done:
+       WRT_REG_DWORD(&reg->iobase_window, 0x0000);
+       RD_REG_DWORD(&reg->iobase_window);
+}
+
 /**
  * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
  * @irq:
@@ -1499,10 +1566,16 @@ qla24xx_intr_handler(int irq, void *dev_id)
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
                        hccr = RD_REG_DWORD(&reg->hccr);
 
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
                            "Dumping firmware!\n", hccr);
+
+                       qla2xxx_check_risc_status(ha);
+
                        ha->isp_ops->fw_dump(ha, 1);
                        set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
                        break;
@@ -1606,7 +1679,6 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
        qla24xx_process_response_queue(ha);
 
        WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
-       RD_REG_DWORD_RELAXED(&reg->hccr);
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -1620,7 +1692,6 @@ qla24xx_msix_default(int irq, void *dev_id)
        struct device_reg_24xx __iomem *reg;
        int             status;
        unsigned long   flags;
-       unsigned long   iter;
        uint32_t        stat;
        uint32_t        hccr;
        uint16_t        mb[4];
@@ -1630,13 +1701,19 @@ qla24xx_msix_default(int irq, void *dev_id)
        status = 0;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       for (iter = 50; iter--; ) {
+       do {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
+                       if (pci_channel_offline(ha->pdev))
+                               break;
+
                        hccr = RD_REG_DWORD(&reg->hccr);
 
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
                            "Dumping firmware!\n", hccr);
+
+                       qla2xxx_check_risc_status(ha);
+
                        ha->isp_ops->fw_dump(ha, 1);
                        set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
                        break;
@@ -1669,8 +1746,7 @@ qla24xx_msix_default(int irq, void *dev_id)
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
-               RD_REG_DWORD_RELAXED(&reg->hccr);
-       }
+       } while (0);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
index d3746ec80a857a3e1b9557378055382259b72dca..c53ec67c47f4df600445f960ad503040248650e0 100644 (file)
@@ -391,7 +391,8 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
                mcp->mb[1] = MSW(risc_addr);
                mcp->mb[2] = LSW(risc_addr);
                mcp->mb[3] = 0;
-               mcp->out_mb |= MBX_3|MBX_2|MBX_1;
+               mcp->mb[4] = 0;
+               mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
                mcp->in_mb |= MBX_1;
        } else {
                mcp->mb[1] = LSW(risc_addr);
@@ -1919,7 +1920,8 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
  */
 int
 qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
-    uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, uint16_t *orig_iocb_cnt)
+    uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
+    uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports)
 {
        int rval;
        mbx_cmd_t mc;
@@ -1929,7 +1931,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
 
        mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
        mcp->out_mb = MBX_0;
-       mcp->in_mb = MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->tov = 30;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
@@ -1940,9 +1942,9 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
                    ha->host_no, mcp->mb[0]));
        } else {
                DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
-                   "mb7=%x mb10=%x.\n", __func__, ha->host_no,
+                   "mb7=%x mb10=%x mb11=%x.\n", __func__, ha->host_no,
                    mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7],
-                   mcp->mb[10]));
+                   mcp->mb[10], mcp->mb[11]));
 
                if (cur_xchg_cnt)
                        *cur_xchg_cnt = mcp->mb[3];
@@ -1952,6 +1954,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
                        *cur_iocb_cnt = mcp->mb[7];
                if (orig_iocb_cnt)
                        *orig_iocb_cnt = mcp->mb[10];
+               if (max_npiv_vports)
+                       *max_npiv_vports = mcp->mb[11];
        }
 
        return (rval);
@@ -2980,3 +2984,51 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
 
        return rval;
 }
+
+int
+qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr,
+    uint32_t size)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+       if (MSW(addr) || IS_FWI2_CAPABLE(ha)) {
+               mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED;
+               mcp->mb[8] = MSW(addr);
+               mcp->out_mb = MBX_8|MBX_0;
+       } else {
+               mcp->mb[0] = MBC_DUMP_RISC_RAM;
+               mcp->out_mb = MBX_0;
+       }
+       mcp->mb[1] = LSW(addr);
+       mcp->mb[2] = MSW(req_dma);
+       mcp->mb[3] = LSW(req_dma);
+       mcp->mb[6] = MSW(MSD(req_dma));
+       mcp->mb[7] = LSW(MSD(req_dma));
+       mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
+       if (IS_FWI2_CAPABLE(ha)) {
+               mcp->mb[4] = MSW(size);
+               mcp->mb[5] = LSW(size);
+               mcp->out_mb |= MBX_5|MBX_4;
+       } else {
+               mcp->mb[4] = LSW(size);
+               mcp->out_mb |= MBX_4;
+       }
+
+       mcp->in_mb = MBX_0;
+       mcp->tov = 30;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(ha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+                   ha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+       }
+
+       return rval;
+}
index 54dc415d8b535850db36a155532aca4efbe84750..821ee74aadc675ed4a7f3f5a1157000d76079413 100644 (file)
@@ -104,7 +104,7 @@ qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
  *
  * Context:
  */
-void
+static void
 qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
 {
        fc_port_t *fcport;
@@ -179,37 +179,7 @@ enable_failed:
        return 1;
 }
 
-/**
- * qla24xx_modify_vport() -  Modifies the virtual fabric port's configuration
- * @ha: HA context
- * @vp: pointer to buffer of virtual port parameters.
- * @ret_code: return error code:
- *
- * Returns the virtual port id, or MAX_VSAN_ID, if couldn't create.
- */
-uint32_t
-qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t *vp_id)
-{
-       scsi_qla_host_t *vha;
-
-       vha = qla24xx_find_vhost_by_name(ha, vp->port_name);
-       if (!vha) {
-               *vp_id = MAX_NUM_VPORT_LOOP;
-               return VP_RET_CODE_WWPN;
-       }
-
-       if (qla24xx_enable_vp(vha)) {
-               scsi_host_put(vha->host);
-               qla2x00_mem_free(vha);
-               *vp_id = MAX_NUM_VPORT_LOOP;
-               return VP_RET_CODE_RESOURCES;
-       }
-
-       *vp_id = vha->vp_idx;
-       return VP_RET_CODE_OK;
-}
-
-void
+static void
 qla24xx_configure_vp(scsi_qla_host_t *vha)
 {
        struct fc_vport *fc_vport;
@@ -363,7 +333,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
 int
 qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
 {
-       scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
        scsi_qla_host_t *vha;
        uint8_t port_name[WWN_SIZE];
 
@@ -397,7 +367,7 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
 scsi_qla_host_t *
 qla24xx_create_vhost(struct fc_vport *fc_vport)
 {
-       scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
        scsi_qla_host_t *vha;
        struct Scsi_Host *host;
 
@@ -409,7 +379,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
                return(NULL);
        }
 
-       vha = (scsi_qla_host_t *)host->hostdata;
+       vha = shost_priv(host);
 
        /* clone the parent hba */
        memcpy(vha, ha, sizeof (scsi_qla_host_t));
index acca898ce0a2efb4773e4c76bbdd9ccd04585764..a6bb8d0ecf139fe46de567eb773abd8fead11dba 100644 (file)
@@ -379,12 +379,17 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport,
 static int
 qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
        srb_t *sp;
        int rval;
 
+       if (unlikely(pci_channel_offline(ha->pdev))) {
+               cmd->result = DID_REQUEUE << 16;
+               goto qc_fail_command;
+       }
+
        rval = fc_remote_port_chkready(rport);
        if (rval) {
                cmd->result = rval;
@@ -440,13 +445,18 @@ qc_fail_command:
 static int
 qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
        srb_t *sp;
        int rval;
        scsi_qla_host_t *pha = to_qla_parent(ha);
 
+       if (unlikely(pci_channel_offline(ha->pdev))) {
+               cmd->result = DID_REQUEUE << 16;
+               goto qc24_fail_command;
+       }
+
        rval = fc_remote_port_chkready(rport);
        if (rval) {
                cmd->result = rval;
@@ -653,7 +663,7 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
 static int
 qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        srb_t *sp;
        int ret, i;
        unsigned int id, lun;
@@ -793,7 +803,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
 static int
 qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
        unsigned int id, lun;
@@ -922,7 +932,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
 static int
 qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        scsi_qla_host_t *pha = to_qla_parent(ha);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
@@ -982,7 +992,7 @@ eh_bus_reset_done:
 static int
 qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
        unsigned int id, lun;
@@ -1132,7 +1142,7 @@ qla2xxx_slave_alloc(struct scsi_device *sdev)
 static int
 qla2xxx_slave_configure(struct scsi_device *sdev)
 {
-       scsi_qla_host_t *ha = to_qla_host(sdev->host);
+       scsi_qla_host_t *ha = shost_priv(sdev->host);
        struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
 
        if (sdev->tagged_supported)
@@ -1384,7 +1394,7 @@ static struct isp_operations qla25xx_isp_ops = {
        .beacon_on              = qla24xx_beacon_on,
        .beacon_off             = qla24xx_beacon_off,
        .beacon_blink           = qla24xx_beacon_blink,
-       .read_optrom            = qla24xx_read_optrom_data,
+       .read_optrom            = qla25xx_read_optrom_data,
        .write_optrom           = qla24xx_write_optrom_data,
        .get_flash_version      = qla24xx_get_flash_version,
 };
@@ -1533,7 +1543,7 @@ iospace_error_exit:
 static void
 qla2xxx_scan_start(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
        set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
@@ -1543,7 +1553,7 @@ qla2xxx_scan_start(struct Scsi_Host *shost)
 static int
 qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        if (!ha->host)
                return 1;
@@ -1571,6 +1581,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        if (pci_enable_device(pdev))
                goto probe_out;
 
+       if (pci_find_aer_capability(pdev))
+               if (pci_enable_pcie_error_reporting(pdev))
+                       goto probe_out;
+
        sht = &qla2x00_driver_template;
        if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
@@ -1586,7 +1600,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* Clear our data area */
-       ha = (scsi_qla_host_t *)host->hostdata;
+       ha = shost_priv(host);
        memset(ha, 0, sizeof(scsi_qla_host_t));
 
        ha->pdev = pdev;
@@ -2423,7 +2437,6 @@ qla2x00_do_dpc(void *data)
                                if (atomic_read(&fcport->state) != FCS_ONLINE &&
                                    fcport->login_retry) {
 
-                                       fcport->login_retry--;
                                        if (fcport->flags & FCF_FABRIC_DEVICE) {
                                                if (fcport->flags &
                                                    FCF_TAPE_PRESENT)
@@ -2439,6 +2452,7 @@ qla2x00_do_dpc(void *data)
                                                    qla2x00_local_device_login(
                                                        ha, fcport);
 
+                                       fcport->login_retry--;
                                        if (status == QLA_SUCCESS) {
                                                fcport->old_loop_id = fcport->loop_id;
 
@@ -2456,6 +2470,8 @@ qla2x00_do_dpc(void *data)
                                        } else {
                                                fcport->login_retry = 0;
                                        }
+                                       if (fcport->login_retry == 0)
+                                               fcport->loop_id = FC_NO_LOOP_ID;
                                }
                                if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
                                        break;
@@ -2814,6 +2830,105 @@ qla2x00_release_firmware(void)
        up(&qla_fw_lock);
 }
 
+static pci_ers_result_t
+qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       switch (state) {
+       case pci_channel_io_normal:
+               return PCI_ERS_RESULT_CAN_RECOVER;
+       case pci_channel_io_frozen:
+               pci_disable_device(pdev);
+               return PCI_ERS_RESULT_NEED_RESET;
+       case pci_channel_io_perm_failure:
+               qla2x00_remove_one(pdev);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
+{
+       int risc_paused = 0;
+       uint32_t stat;
+       unsigned long flags;
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       if (IS_QLA2100(ha) || IS_QLA2200(ha)){
+               stat = RD_REG_DWORD(&reg->hccr);
+               if (stat & HCCR_RISC_PAUSE)
+                       risc_paused = 1;
+       } else if (IS_QLA23XX(ha)) {
+               stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+               if (stat & HSR_RISC_PAUSED)
+                       risc_paused = 1;
+       } else if (IS_FWI2_CAPABLE(ha)) {
+               stat = RD_REG_DWORD(&reg24->host_status);
+               if (stat & HSRX_RISC_PAUSED)
+                       risc_paused = 1;
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       if (risc_paused) {
+               qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
+                   "Dumping firmware!\n");
+               ha->isp_ops->fw_dump(ha, 0);
+
+               return PCI_ERS_RESULT_NEED_RESET;
+       } else
+               return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_slot_reset(struct pci_dev *pdev)
+{
+       pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+
+       if (pci_enable_device(pdev)) {
+               qla_printk(KERN_WARNING, ha,
+                   "Can't re-enable PCI device after reset.\n");
+
+               return ret;
+       }
+       pci_set_master(pdev);
+
+       if (ha->isp_ops->pci_config(ha))
+               return ret;
+
+       set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+       if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
+               ret =  PCI_ERS_RESULT_RECOVERED;
+       clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+       return ret;
+}
+
+static void
+qla2xxx_pci_resume(struct pci_dev *pdev)
+{
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+       int ret;
+
+       ret = qla2x00_wait_for_hba_online(ha);
+       if (ret != QLA_SUCCESS) {
+               qla_printk(KERN_ERR, ha,
+                   "the device failed to resume I/O "
+                   "from slot/link_reset");
+       }
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static struct pci_error_handlers qla2xxx_err_handler = {
+       .error_detected = qla2xxx_pci_error_detected,
+       .mmio_enabled = qla2xxx_pci_mmio_enabled,
+       .slot_reset = qla2xxx_pci_slot_reset,
+       .resume = qla2xxx_pci_resume,
+};
+
 static struct pci_device_id qla2xxx_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
@@ -2839,6 +2954,7 @@ static struct pci_driver qla2xxx_pci_driver = {
        .id_table       = qla2xxx_pci_tbl,
        .probe          = qla2x00_probe_one,
        .remove         = __devexit_p(qla2x00_remove_one),
+       .err_handler    = &qla2xxx_err_handler,
 };
 
 /**
index a925a3f179f959e196b7e12bf5bff46c82e06743..40b059fc19813db3c5c3f41bd0b2482d09db4731 100644 (file)
@@ -425,6 +425,9 @@ qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat)
 /* Flash Manipulation Routines                                               */
 /*****************************************************************************/
 
+#define OPTROM_BURST_SIZE      0x1000
+#define OPTROM_BURST_DWORDS    (OPTROM_BURST_SIZE / 4)
+
 static inline uint32_t
 flash_conf_to_access_addr(uint32_t faddr)
 {
@@ -544,41 +547,59 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
     uint32_t dwords)
 {
        int ret;
-       uint32_t liter;
-       uint32_t sec_mask, rest_addr, conf_addr, sec_end_mask;
+       uint32_t liter, miter;
+       uint32_t sec_mask, rest_addr, conf_addr;
        uint32_t fdata, findex ;
        uint8_t man_id, flash_id;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+       dma_addr_t optrom_dma;
+       void *optrom = NULL;
+       uint32_t *s, *d;
 
        ret = QLA_SUCCESS;
 
+       /* Prepare burst-capable write on supported ISPs. */
+       if (IS_QLA25XX(ha) && !(faddr & 0xfff) &&
+           dwords > OPTROM_BURST_DWORDS) {
+               optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+                   &optrom_dma, GFP_KERNEL);
+               if (!optrom) {
+                       qla_printk(KERN_DEBUG, ha,
+                           "Unable to allocate memory for optrom burst write "
+                           "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+               }
+       }
+
        qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
        DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__,
            ha->host_no, man_id, flash_id));
 
-       sec_end_mask = 0;
        conf_addr = flash_conf_to_access_addr(0x03d8);
        switch (man_id) {
        case 0xbf: /* STT flash. */
-               rest_addr = 0x1fff;
-               sec_mask = 0x3e000;
+               if (flash_id == 0x8e) {
+                       rest_addr = 0x3fff;
+                       sec_mask = 0x7c000;
+               } else {
+                       rest_addr = 0x1fff;
+                       sec_mask = 0x7e000;
+               }
                if (flash_id == 0x80)
                        conf_addr = flash_conf_to_access_addr(0x0352);
                break;
        case 0x13: /* ST M25P80. */
                rest_addr = 0x3fff;
-               sec_mask = 0x3c000;
+               sec_mask = 0x7c000;
                break;
        case 0x1f: // Atmel 26DF081A
-               rest_addr = 0x0fff;
-               sec_mask = 0xff000;
-               sec_end_mask = 0x003ff;
+               rest_addr = 0x3fff;
+               sec_mask = 0x7c000;
                conf_addr = flash_conf_to_access_addr(0x0320);
                break;
        default:
                /* Default to 64 kb sector size. */
                rest_addr = 0x3fff;
-               sec_mask = 0x3c000;
+               sec_mask = 0x7c000;
                break;
        }
 
@@ -592,56 +613,81 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
        /* Some flash parts need an additional zero-write to clear bits.*/
        qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
 
-       do {    /* Loop once to provide quick error exit. */
-               for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
-                       if (man_id == 0x1f) {
-                               findex = faddr << 2;
-                               fdata = findex & sec_mask;
-                       } else {
-                               findex = faddr;
-                               fdata = (findex & sec_mask) << 2;
-                       }
+       for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
+               if (man_id == 0x1f) {
+                       findex = faddr << 2;
+                       fdata = findex & sec_mask;
+               } else {
+                       findex = faddr;
+                       fdata = (findex & sec_mask) << 2;
+               }
 
-                       /* Are we at the beginning of a sector? */
-                       if ((findex & rest_addr) == 0) {
-                               /*
-                                * Do sector unprotect at 4K boundry for Atmel
-                                * part.
-                                */
-                               if (man_id == 0x1f)
-                                       qla24xx_write_flash_dword(ha,
-                                           flash_conf_to_access_addr(0x0339),
-                                           (fdata & 0xff00) | ((fdata << 16) &
-                                           0xff0000) | ((fdata >> 16) & 0xff));
-                               ret = qla24xx_write_flash_dword(ha, conf_addr,
-                                   (fdata & 0xff00) |((fdata << 16) &
+               /* Are we at the beginning of a sector? */
+               if ((findex & rest_addr) == 0) {
+                       /* Do sector unprotect at 4K boundry for Atmel part. */
+                       if (man_id == 0x1f)
+                               qla24xx_write_flash_dword(ha,
+                                   flash_conf_to_access_addr(0x0339),
+                                   (fdata & 0xff00) | ((fdata << 16) &
                                    0xff0000) | ((fdata >> 16) & 0xff));
-                               if (ret != QLA_SUCCESS) {
-                                       DEBUG9(printk("%s(%ld) Unable to flash "
-                                           "sector: address=%x.\n", __func__,
-                                           ha->host_no, faddr));
-                                       break;
-                               }
+                       ret = qla24xx_write_flash_dword(ha, conf_addr,
+                           (fdata & 0xff00) |((fdata << 16) &
+                           0xff0000) | ((fdata >> 16) & 0xff));
+                       if (ret != QLA_SUCCESS) {
+                               DEBUG9(printk("%s(%ld) Unable to flash "
+                                   "sector: address=%x.\n", __func__,
+                                   ha->host_no, faddr));
+                               break;
                        }
-                       ret = qla24xx_write_flash_dword(ha,
+               }
+
+               /* Go with burst-write. */
+               if (optrom && (liter + OPTROM_BURST_DWORDS) < dwords) {
+                       /* Copy data to DMA'ble buffer. */
+                       for (miter = 0, s = optrom, d = dwptr;
+                           miter < OPTROM_BURST_DWORDS; miter++, s++, d++)
+                               *s = cpu_to_le32(*d);
+
+                       ret = qla2x00_load_ram(ha, optrom_dma,
                            flash_data_to_access_addr(faddr),
-                           cpu_to_le32(*dwptr));
+                           OPTROM_BURST_DWORDS);
                        if (ret != QLA_SUCCESS) {
-                               DEBUG9(printk("%s(%ld) Unable to program flash "
-                                   "address=%x data=%x.\n", __func__,
-                                   ha->host_no, faddr, *dwptr));
-                               break;
+                               qla_printk(KERN_WARNING, ha,
+                                   "Unable to burst-write optrom segment "
+                                   "(%x/%x/%llx).\n", ret,
+                                   flash_data_to_access_addr(faddr),
+                                   optrom_dma);
+                               qla_printk(KERN_WARNING, ha,
+                                   "Reverting to slow-write.\n");
+
+                               dma_free_coherent(&ha->pdev->dev,
+                                   OPTROM_BURST_SIZE, optrom, optrom_dma);
+                               optrom = NULL;
+                       } else {
+                               liter += OPTROM_BURST_DWORDS - 1;
+                               faddr += OPTROM_BURST_DWORDS - 1;
+                               dwptr += OPTROM_BURST_DWORDS - 1;
+                               continue;
                        }
+               }
 
-                       /* Do sector protect at 4K boundry for Atmel part. */
-                       if (man_id == 0x1f &&
-                           ((faddr & sec_end_mask) == 0x3ff))
-                               qla24xx_write_flash_dword(ha,
-                                   flash_conf_to_access_addr(0x0336),
-                                   (fdata & 0xff00) | ((fdata << 16) &
-                                   0xff0000) | ((fdata >> 16) & 0xff));
+               ret = qla24xx_write_flash_dword(ha,
+                   flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr));
+               if (ret != QLA_SUCCESS) {
+                       DEBUG9(printk("%s(%ld) Unable to program flash "
+                           "address=%x data=%x.\n", __func__,
+                           ha->host_no, faddr, *dwptr));
+                       break;
                }
-       } while (0);
+
+               /* Do sector protect at 4K boundry for Atmel part. */
+               if (man_id == 0x1f &&
+                   ((faddr & rest_addr) == rest_addr))
+                       qla24xx_write_flash_dword(ha,
+                           flash_conf_to_access_addr(0x0336),
+                           (fdata & 0xff00) | ((fdata << 16) &
+                           0xff0000) | ((fdata >> 16) & 0xff));
+       }
 
        /* Enable flash write-protection. */
        qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
@@ -651,6 +697,10 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
            RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
        RD_REG_DWORD(&reg->ctrl_status);        /* PCI Posting. */
 
+       if (optrom)
+               dma_free_coherent(&ha->pdev->dev,
+                   OPTROM_BURST_SIZE, optrom, optrom_dma);
+
        return ret;
 }
 
@@ -1728,7 +1778,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
 {
        /* Suspend HBA. */
        scsi_block_requests(ha->host);
-       ha->isp_ops->disable_intrs(ha);
        set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
 
        /* Go with read. */
@@ -1736,7 +1785,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
 
        /* Resume HBA. */
        clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
-       ha->isp_ops->enable_intrs(ha);
        scsi_unblock_requests(ha->host);
 
        return buf;
@@ -1750,7 +1798,6 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
 
        /* Suspend HBA. */
        scsi_block_requests(ha->host);
-       ha->isp_ops->disable_intrs(ha);
        set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
 
        /* Go with write. */
@@ -1767,6 +1814,70 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
        return rval;
 }
 
+uint8_t *
+qla25xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
+    uint32_t offset, uint32_t length)
+{
+       int rval;
+       dma_addr_t optrom_dma;
+       void *optrom;
+       uint8_t *pbuf;
+       uint32_t faddr, left, burst;
+
+       if (offset & 0xfff)
+               goto slow_read;
+       if (length < OPTROM_BURST_SIZE)
+               goto slow_read;
+
+       optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+           &optrom_dma, GFP_KERNEL);
+       if (!optrom) {
+               qla_printk(KERN_DEBUG, ha,
+                   "Unable to allocate memory for optrom burst read "
+                   "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+
+               goto slow_read;
+       }
+
+       pbuf = buf;
+       faddr = offset >> 2;
+       left = length >> 2;
+       burst = OPTROM_BURST_DWORDS;
+       while (left != 0) {
+               if (burst > left)
+                       burst = left;
+
+               rval = qla2x00_dump_ram(ha, optrom_dma,
+                   flash_data_to_access_addr(faddr), burst);
+               if (rval) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Unable to burst-read optrom segment "
+                           "(%x/%x/%llx).\n", rval,
+                           flash_data_to_access_addr(faddr), optrom_dma);
+                       qla_printk(KERN_WARNING, ha,
+                           "Reverting to slow-read.\n");
+
+                       dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+                           optrom, optrom_dma);
+                       goto slow_read;
+               }
+
+               memcpy(pbuf, optrom, burst * 4);
+
+               left -= burst;
+               faddr += burst;
+               pbuf += burst * 4;
+       }
+
+       dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
+           optrom_dma);
+
+       return buf;
+
+slow_read:
+    return qla24xx_read_optrom_data(ha, buf, offset, length);
+}
+
 /**
  * qla2x00_get_fcode_version() - Determine an FCODE image's version.
  * @ha: HA context
index 18095b9b76f487553ac0a4ec7ecc30a047d79246..2d551a3006f6a2e23280c5514c01d35cf44f140a 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.02.00-k3"
+#define QLA2XXX_VERSION      "8.02.00-k4"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   2
index 94baca840efe45308070d964c4fb8612c9208198..1e874f1fb5c64a403fd6e7da8365edce51b929df 100644 (file)
@@ -166,6 +166,7 @@ static int qlogicfas_release(struct Scsi_Host *shost)
 {
        struct qlogicfas408_priv *priv = get_priv_by_host(shost);
 
+       scsi_remove_host(shost);
        if (shost->irq) {
                qlogicfas408_disable_ints(priv);        
                free_irq(shost->irq, shost);
@@ -174,7 +175,6 @@ static int qlogicfas_release(struct Scsi_Host *shost)
                free_dma(shost->dma_channel);
        if (shost->io_port && shost->n_io_port)
                release_region(shost->io_port, shost->n_io_port);
-       scsi_remove_host(shost);
        scsi_host_put(shost);
 
        return 0;
index 594887205b0fe7876a3fea97493a89f9402d9fb9..e93f80316a19369d7d3416c887ece96bed1117c6 100644 (file)
@@ -310,8 +310,6 @@ static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
                }
                qpti->dev_param[i].device_enable = 1;
        }
-       /* this is very important to set! */
-       qpti->sbits = 1 << qpti->scsi_id;
 }
 
 static int qlogicpti_reset_hardware(struct Scsi_Host *host)
@@ -951,153 +949,35 @@ static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int
        host->sg_tablesize = QLOGICPTI_MAX_SG(num_free);
 }
 
-static unsigned int scsi_rbuf_get(struct scsi_cmnd *cmd, unsigned char **buf_out)
+static int qlogicpti_slave_configure(struct scsi_device *sdev)
 {
-       unsigned char *buf;
-       unsigned int buflen;
-
-       if (cmd->use_sg) {
-               struct scatterlist *sg;
+       struct qlogicpti *qpti = shost_priv(sdev->host);
+       int tgt = sdev->id;
+       u_short param[6];
 
-               sg = (struct scatterlist *) cmd->request_buffer;
-               buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
-               buflen = sg->length;
+       /* tags handled in midlayer */
+       /* enable sync mode? */
+       if (sdev->sdtr) {
+               qpti->dev_param[tgt].device_flags |= 0x10;
        } else {
-               buf = cmd->request_buffer;
-               buflen = cmd->request_bufflen;
+               qpti->dev_param[tgt].synchronous_offset = 0;
+               qpti->dev_param[tgt].synchronous_period = 0;
        }
-
-       *buf_out = buf;
-       return buflen;
-}
-
-static void scsi_rbuf_put(struct scsi_cmnd *cmd, unsigned char *buf)
-{
-       if (cmd->use_sg) {
-               struct scatterlist *sg;
-
-               sg = (struct scatterlist *) cmd->request_buffer;
-               kunmap_atomic(buf - sg->offset, KM_IRQ0);
-       }
-}
-
-/*
- * Until we scan the entire bus with inquiries, go throught this fella...
- */
-static void ourdone(struct scsi_cmnd *Cmnd)
-{
-       struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
-       int tgt = Cmnd->device->id;
-       void (*done) (struct scsi_cmnd *);
-
-       /* This grot added by DaveM, blame him for ugliness.
-        * The issue is that in the 2.3.x driver we use the
-        * host_scribble portion of the scsi command as a
-        * completion linked list at interrupt service time,
-        * so we have to store the done function pointer elsewhere.
-        */
-       done = (void (*)(struct scsi_cmnd *))
-               (((unsigned long) Cmnd->SCp.Message)
-#ifdef __sparc_v9__
-                | ((unsigned long) Cmnd->SCp.Status << 32UL)
-#endif
-                );
-
-       if ((qpti->sbits & (1 << tgt)) == 0) {
-               int ok = host_byte(Cmnd->result) == DID_OK;
-               if (Cmnd->cmnd[0] == 0x12 && ok) {
-                       unsigned char *iqd;
-                       unsigned int iqd_len;
-
-                       iqd_len = scsi_rbuf_get(Cmnd, &iqd);
-
-                       /* tags handled in midlayer */
-                       /* enable sync mode? */
-                       if (iqd[7] & 0x10) {
-                               qpti->dev_param[tgt].device_flags |= 0x10;
-                       } else {
-                               qpti->dev_param[tgt].synchronous_offset = 0;
-                               qpti->dev_param[tgt].synchronous_period = 0;
-                       }
-                       /* are we wide capable? */
-                       if (iqd[7] & 0x20) {
-                               qpti->dev_param[tgt].device_flags |= 0x20;
-                       }
-
-                       scsi_rbuf_put(Cmnd, iqd);
-
-                       qpti->sbits |= (1 << tgt);
-               } else if (!ok) {
-                       qpti->sbits |= (1 << tgt);
-               }
-       }
-       done(Cmnd);
-}
-
-static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *));
-
-static int qlogicpti_queuecommand_slow(struct scsi_cmnd *Cmnd,
-                                      void (*done)(struct scsi_cmnd *))
-{
-       struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
-
-       /*
-        * done checking this host adapter?
-        * If not, then rewrite the command
-        * to finish through ourdone so we
-        * can peek at Inquiry data results.
-        */
-       if (qpti->sbits && qpti->sbits != 0xffff) {
-               /* See above about in ourdone this ugliness... */
-               Cmnd->SCp.Message = ((unsigned long)done) & 0xffffffff;
-#ifdef CONFIG_SPARC64
-               Cmnd->SCp.Status = ((unsigned long)done >> 32UL) & 0xffffffff;
-#endif
-               return qlogicpti_queuecommand(Cmnd, ourdone);
-       }
-
-       /*
-        * We've peeked at all targets for this bus- time
-        * to set parameters for devices for real now.
-        */
-       if (qpti->sbits == 0xffff) {
-               int i;
-               for(i = 0; i < MAX_TARGETS; i++) {
-                       u_short param[6];
-                       param[0] = MBOX_SET_TARGET_PARAMS;
-                       param[1] = (i << 8);
-                       param[2] = (qpti->dev_param[i].device_flags << 8);
-                       if (qpti->dev_param[i].device_flags & 0x10) {
-                               param[3] = (qpti->dev_param[i].synchronous_offset << 8) |
-                                       qpti->dev_param[i].synchronous_period;
-                       } else {
-                               param[3] = 0;
-                       }
-                       (void) qlogicpti_mbox_command(qpti, param, 0);
-               }
-               /*
-                * set to zero so any traverse through ourdone
-                * doesn't start the whole process again,
-                */
-               qpti->sbits = 0;
-       }
-
-       /* check to see if we're done with all adapters... */
-       for (qpti = qptichain; qpti != NULL; qpti = qpti->next) {
-               if (qpti->sbits) {
-                       break;
-               }
+       /* are we wide capable? */
+       if (sdev->wdtr)
+               qpti->dev_param[tgt].device_flags |= 0x20;
+
+       param[0] = MBOX_SET_TARGET_PARAMS;
+       param[1] = (tgt << 8);
+       param[2] = (qpti->dev_param[tgt].device_flags << 8);
+       if (qpti->dev_param[tgt].device_flags & 0x10) {
+               param[3] = (qpti->dev_param[tgt].synchronous_offset << 8) |
+                       qpti->dev_param[tgt].synchronous_period;
+       } else {
+               param[3] = 0;
        }
-
-       /*
-        * if we hit the end of the chain w/o finding adapters still
-        * capability-configuring, then we're done with all adapters
-        * and can rock on..
-        */
-       if (qpti == NULL)
-               Cmnd->device->host->hostt->queuecommand = qlogicpti_queuecommand;
-
-       return qlogicpti_queuecommand(Cmnd, done);
+       qlogicpti_mbox_command(qpti, param, 0);
+       return 0;
 }
 
 /*
@@ -1390,7 +1270,8 @@ static struct scsi_host_template qpti_template = {
        .module                 = THIS_MODULE,
        .name                   = "qlogicpti",
        .info                   = qlogicpti_info,
-       .queuecommand           = qlogicpti_queuecommand_slow,
+       .queuecommand           = qlogicpti_queuecommand,
+       .slave_configure        = qlogicpti_slave_configure,
        .eh_abort_handler       = qlogicpti_abort,
        .eh_bus_reset_handler   = qlogicpti_reset,
        .can_queue              = QLOGICPTI_REQ_QUEUE_LEN,
index 6cd1c0771d29a515d74a1587f8e6b58c0ffbbe4d..ef6da2df584ba29fbfddcbb19e105d0fe7b1a319 100644 (file)
@@ -380,8 +380,7 @@ struct qlogicpti {
        unsigned char             swsreg;
        unsigned int    
                gotirq  :       1,      /* this instance got an irq */
-               is_pti  :       1,      /* Non-zero if this is a PTI board. */
-               sbits   :       16;     /* syncmode known bits */
+               is_pti  :       1;      /* Non-zero if this is a PTI board. */
 };
 
 /* How to twiddle them bits... */
index a5de1a829a76dbb2bba8d6baaa4cc8e7bd580805..192948822455fd666ee8b7516ecedb812ac5744a 100644 (file)
@@ -59,6 +59,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
@@ -367,9 +368,8 @@ void scsi_log_send(struct scsi_cmnd *cmd)
                        scsi_print_command(cmd);
                        if (level > 3) {
                                printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
-                                      " done = 0x%p, queuecommand 0x%p\n",
+                                      " queuecommand 0x%p\n",
                                        scsi_sglist(cmd), scsi_bufflen(cmd),
-                                       cmd->done,
                                        cmd->device->host->hostt->queuecommand);
 
                        }
@@ -442,7 +442,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
 #endif
 
 /* 
- * Assign a serial number and pid to the request for error recovery
+ * Assign a serial number to the request for error recovery
  * and debugging purposes.  Protected by the Host_Lock of host.
  */
 static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
@@ -450,10 +450,6 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
        cmd->serial_number = host->cmd_serial_number++;
        if (cmd->serial_number == 0) 
                cmd->serial_number = host->cmd_serial_number++;
-       
-       cmd->pid = host->cmd_pid++;
-       if (cmd->pid == 0)
-               cmd->pid = host->cmd_pid++;
 }
 
 /*
@@ -658,6 +654,12 @@ void __scsi_done(struct scsi_cmnd *cmd)
        blk_complete_request(rq);
 }
 
+/* Move this to a header if it becomes more generally useful */
+static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
+{
+       return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
+}
+
 /*
  * Function:    scsi_finish_command
  *
@@ -669,6 +671,8 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
 {
        struct scsi_device *sdev = cmd->device;
        struct Scsi_Host *shost = sdev->host;
+       struct scsi_driver *drv;
+       unsigned int good_bytes;
 
        scsi_device_unbusy(sdev);
 
@@ -694,7 +698,13 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
                                "Notifying upper driver of completion "
                                "(result %x)\n", cmd->result));
 
-       cmd->done(cmd);
+       good_bytes = cmd->request_bufflen;
+        if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
+               drv = scsi_cmd_to_driver(cmd);
+               if (drv->done)
+                       good_bytes = drv->done(cmd);
+       }
+       scsi_io_completion(cmd, good_bytes);
 }
 EXPORT_SYMBOL(scsi_finish_command);
 
index e2ea739e33df121dae6b91b25339efee7cdf3696..348cc5a6e3cdf002b091ea73762e16f0baf5b6d7 100644 (file)
@@ -214,6 +214,7 @@ static struct {
        {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
        {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
        {"Promise", "", NULL, BLIST_SPARSELUN},
+       {"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
        {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
        {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
        {"SEAGATE", "ST34555N", "0930", BLIST_NOTQ},    /* Chokes on tagged INQUIRY */
index 8a525abda30fcad2d7b5cf54dfab5b46bc067e68..d29f8464b74fadd26de9e5535ede03cfa21d08dd 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
+#include "scsi_transport_api.h"
 
 #define SENSE_TIMEOUT          (10*HZ)
 
@@ -589,39 +590,23 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
 }
 
 /**
- * scsi_send_eh_cmnd  - submit a scsi command as part of error recory
+ * scsi_eh_prep_cmnd  - Save a scsi command info as part of error recory
  * @scmd:       SCSI command structure to hijack
- * @cmnd:       CDB to send
+ * @ses:        structure to save restore information
+ * @cmnd:       CDB to send. Can be NULL if no new cmnd is needed
  * @cmnd_size:  size in bytes of @cmnd
- * @timeout:    timeout for this request
- * @copy_sense: request sense data if set to 1
- *
- * This function is used to send a scsi command down to a target device
- * as part of the error recovery process.  If @copy_sense is 0 the command
- * sent must be one that does not transfer any data.  If @copy_sense is 1
- * the command must be REQUEST_SENSE and this functions copies out the
- * sense buffer it got into @scmd->sense_buffer.
+ * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
  *
- * Return value:
- *    SUCCESS or FAILED or NEEDS_RETRY
+ * This function is used to save a scsi command information before re-execution
+ * as part of the error recovery process.  If @sense_bytes is 0 the command
+ * sent must be one that does not transfer any data.  If @sense_bytes != 0
+ * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
+ * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
  **/
-static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
-                            int cmnd_size, int timeout, int copy_sense)
+void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
+                       unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
 {
        struct scsi_device *sdev = scmd->device;
-       struct Scsi_Host *shost = sdev->host;
-       int old_result = scmd->result;
-       DECLARE_COMPLETION_ONSTACK(done);
-       unsigned long timeleft;
-       unsigned long flags;
-       struct scatterlist sgl;
-       unsigned char old_cmnd[MAX_COMMAND_SIZE];
-       enum dma_data_direction old_data_direction;
-       unsigned short old_use_sg;
-       unsigned char old_cmd_len;
-       unsigned old_bufflen;
-       void *old_buffer;
-       int rtn;
 
        /*
         * We need saved copies of a number of fields - this is because
@@ -630,35 +615,42 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
         * we will need to restore these values prior to running the actual
         * command.
         */
-       old_buffer = scmd->request_buffer;
-       old_bufflen = scmd->request_bufflen;
-       memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd));
-       old_data_direction = scmd->sc_data_direction;
-       old_cmd_len = scmd->cmd_len;
-       old_use_sg = scmd->use_sg;
-
-       memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
-       memcpy(scmd->cmnd, cmnd, cmnd_size);
-
-       if (copy_sense) {
-               sg_init_one(&sgl, scmd->sense_buffer,
-                           sizeof(scmd->sense_buffer));
-
+       ses->cmd_len = scmd->cmd_len;
+       memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+       ses->data_direction = scmd->sc_data_direction;
+       ses->bufflen = scmd->request_bufflen;
+       ses->buffer = scmd->request_buffer;
+       ses->use_sg = scmd->use_sg;
+       ses->resid = scmd->resid;
+       ses->result = scmd->result;
+
+       if (sense_bytes) {
+               scmd->request_bufflen = min_t(unsigned,
+                                      sizeof(scmd->sense_buffer), sense_bytes);
+               sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
+                                                      scmd->request_bufflen);
+               scmd->request_buffer = &ses->sense_sgl;
                scmd->sc_data_direction = DMA_FROM_DEVICE;
-               scmd->request_bufflen = sgl.length;
-               scmd->request_buffer = &sgl;
                scmd->use_sg = 1;
+               memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+               scmd->cmnd[0] = REQUEST_SENSE;
+               scmd->cmnd[4] = scmd->request_bufflen;
+               scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
        } else {
                scmd->request_buffer = NULL;
                scmd->request_bufflen = 0;
                scmd->sc_data_direction = DMA_NONE;
                scmd->use_sg = 0;
+               if (cmnd) {
+                       memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+                       memcpy(scmd->cmnd, cmnd, cmnd_size);
+                       scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+               }
        }
 
        scmd->underflow = 0;
-       scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
 
-       if (sdev->scsi_level <= SCSI_2)
+       if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN)
                scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
                        (sdev->lun << 5 & 0xe0);
 
@@ -667,7 +659,58 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
         * untransferred sense data should be interpreted as being zero.
         */
        memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+}
+EXPORT_SYMBOL(scsi_eh_prep_cmnd);
+
+/**
+ * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recory
+ * @scmd:       SCSI command structure to restore
+ * @ses:        saved information from a coresponding call to scsi_prep_eh_cmnd
+ *
+ * Undo any damage done by above scsi_prep_eh_cmnd().
+ **/
+void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
+{
+       /*
+        * Restore original data
+        */
+       scmd->cmd_len = ses->cmd_len;
+       memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+       scmd->sc_data_direction = ses->data_direction;
+       scmd->request_bufflen = ses->bufflen;
+       scmd->request_buffer = ses->buffer;
+       scmd->use_sg = ses->use_sg;
+       scmd->resid = ses->resid;
+       scmd->result = ses->result;
+}
+EXPORT_SYMBOL(scsi_eh_restore_cmnd);
 
+/**
+ * scsi_send_eh_cmnd  - submit a scsi command as part of error recory
+ * @scmd:       SCSI command structure to hijack
+ * @cmnd:       CDB to send
+ * @cmnd_size:  size in bytes of @cmnd
+ * @timeout:    timeout for this request
+ * @sense_bytes: size of sense data to copy or 0
+ *
+ * This function is used to send a scsi command down to a target device
+ * as part of the error recovery process. See also scsi_eh_prep_cmnd() above.
+ *
+ * Return value:
+ *    SUCCESS or FAILED or NEEDS_RETRY
+ **/
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+                            int cmnd_size, int timeout, unsigned sense_bytes)
+{
+       struct scsi_device *sdev = scmd->device;
+       struct Scsi_Host *shost = sdev->host;
+       DECLARE_COMPLETION_ONSTACK(done);
+       unsigned long timeleft;
+       unsigned long flags;
+       struct scsi_eh_save ses;
+       int rtn;
+
+       scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
        shost->eh_action = &done;
 
        spin_lock_irqsave(shost->host_lock, flags);
@@ -711,17 +754,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
                rtn = FAILED;
        }
 
-
-       /*
-        * Restore original data
-        */
-       scmd->request_buffer = old_buffer;
-       scmd->request_bufflen = old_bufflen;
-       memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd));
-       scmd->sc_data_direction = old_data_direction;
-       scmd->cmd_len = old_cmd_len;
-       scmd->use_sg = old_use_sg;
-       scmd->result = old_result;
+       scsi_eh_restore_cmnd(scmd, &ses);
        return rtn;
 }
 
@@ -736,10 +769,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
  **/
 static int scsi_request_sense(struct scsi_cmnd *scmd)
 {
-       static unsigned char generic_sense[6] =
-               {REQUEST_SENSE, 0, 0, 0, 252, 0};
-
-       return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1);
+       return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0);
 }
 
 /**
@@ -1136,9 +1166,8 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
        struct scsi_cmnd *scmd, *next;
 
        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
-               sdev_printk(KERN_INFO, scmd->device,
-                           "scsi: Device offlined - not"
-                           " ready after error recovery\n");
+               sdev_printk(KERN_INFO, scmd->device, "Device offlined - "
+                           "not ready after error recovery\n");
                scsi_device_set_state(scmd->device, SDEV_OFFLINE);
                if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) {
                        /*
@@ -1671,7 +1700,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
        memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
     
        scmd->scsi_done         = scsi_reset_provider_done_command;
-       scmd->done                      = NULL;
        scmd->request_buffer            = NULL;
        scmd->request_bufflen           = 0;
 
@@ -1681,12 +1709,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
 
        init_timer(&scmd->eh_timeout);
 
-       /*
-        * Sometimes the command can get back into the timer chain,
-        * so use the pid as an identifier.
-        */
-       scmd->pid                       = 0;
-
        spin_lock_irqsave(shost->host_lock, flags);
        shost->tmf_in_progress = 1;
        spin_unlock_irqrestore(shost->host_lock, flags);
index 604f4d7179334a3cb1ce61d354f842285eb2234d..207f1aa08869f209be7ba1bde8f727534796701b 100644 (file)
@@ -288,7 +288,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
 {
        struct request_queue *q = rq->q;
        int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       unsigned int data_len = 0, len, bytes, off;
+       unsigned int data_len = bufflen, len, bytes, off;
        struct page *page;
        struct bio *bio = NULL;
        int i, err, nr_vecs = 0;
@@ -297,10 +297,15 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
                page = sgl[i].page;
                off = sgl[i].offset;
                len = sgl[i].length;
-               data_len += len;
 
-               while (len > 0) {
+               while (len > 0 && data_len > 0) {
+                       /*
+                        * sg sends a scatterlist that is larger than
+                        * the data_len it wants transferred for certain
+                        * IO sizes
+                        */
                        bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+                       bytes = min(bytes, data_len);
 
                        if (!bio) {
                                nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
@@ -332,12 +337,13 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
 
                        page++;
                        len -= bytes;
+                       data_len -=bytes;
                        off = 0;
                }
        }
 
        rq->buffer = rq->data = NULL;
-       rq->data_len = data_len;
+       rq->data_len = bufflen;
        return 0;
 
 free_bios:
@@ -430,6 +436,7 @@ EXPORT_SYMBOL_GPL(scsi_execute_async);
 static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 {
        cmd->serial_number = 0;
+       cmd->resid = 0;
        memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
        if (cmd->cmd_len == 0)
                cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
@@ -924,11 +931,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                                        break;
                                }
                        }
-                       if (!(req->cmd_flags & REQ_QUIET)) {
-                               scmd_printk(KERN_INFO, cmd,
-                                           "Device not ready: ");
-                               scsi_print_sense_hdr("", &sshdr);
-                       }
+                       if (!(req->cmd_flags & REQ_QUIET))
+                               scsi_cmd_print_sense_hdr(cmd,
+                                                        "Device not ready",
+                                                        &sshdr);
+
                        scsi_end_request(cmd, 0, this_count, 1);
                        return;
                case VOLUME_OVERFLOW:
@@ -962,7 +969,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
        }
        scsi_end_request(cmd, 0, this_count, !result);
 }
-EXPORT_SYMBOL(scsi_io_completion);
 
 /*
  * Function:    scsi_init_io()
@@ -1019,9 +1025,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
        printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
                        req->current_nr_sectors);
 
-       /* release the command and kill it */
-       scsi_release_buffers(cmd);
-       scsi_put_command(cmd);
        return BLKPREP_KILL;
 }
 
@@ -1046,21 +1049,13 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
        return cmd;
 }
 
-static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
-{
-       BUG_ON(!blk_pc_request(cmd->request));
-       /*
-        * This will complete the whole command with uptodate=1 so
-        * as far as the block layer is concerned the command completed
-        * successfully. Since this is a REQ_BLOCK_PC command the
-        * caller should check the request's errors value
-        */
-       scsi_io_completion(cmd, cmd->request_bufflen);
-}
-
-static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
 {
        struct scsi_cmnd *cmd;
+       int ret = scsi_prep_state_check(sdev, req);
+
+       if (ret != BLKPREP_OK)
+               return ret;
 
        cmd = scsi_get_cmd_from_req(sdev, req);
        if (unlikely(!cmd))
@@ -1103,21 +1098,22 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
        cmd->transfersize = req->data_len;
        cmd->allowed = req->retries;
        cmd->timeout_per_command = req->timeout;
-       cmd->done = scsi_blk_pc_done;
        return BLKPREP_OK;
 }
+EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd);
 
 /*
  * Setup a REQ_TYPE_FS command.  These are simple read/write request
  * from filesystems that still need to be translated to SCSI CDBs from
  * the ULD.
  */
-static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
 {
        struct scsi_cmnd *cmd;
-       struct scsi_driver *drv;
-       int ret;
+       int ret = scsi_prep_state_check(sdev, req);
 
+       if (ret != BLKPREP_OK)
+               return ret;
        /*
         * Filesystem requests must transfer data.
         */
@@ -1127,26 +1123,12 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
        if (unlikely(!cmd))
                return BLKPREP_DEFER;
 
-       ret = scsi_init_io(cmd);
-       if (unlikely(ret))
-               return ret;
-
-       /*
-        * Initialize the actual SCSI command for this request.
-        */
-       drv = *(struct scsi_driver **)req->rq_disk->private_data;
-       if (unlikely(!drv->init_command(cmd))) {
-               scsi_release_buffers(cmd);
-               scsi_put_command(cmd);
-               return BLKPREP_KILL;
-       }
-
-       return BLKPREP_OK;
+       return scsi_init_io(cmd);
 }
+EXPORT_SYMBOL(scsi_setup_fs_cmnd);
 
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
 {
-       struct scsi_device *sdev = q->queuedata;
        int ret = BLKPREP_OK;
 
        /*
@@ -1192,35 +1174,25 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                                ret = BLKPREP_KILL;
                        break;
                }
-
-               if (ret != BLKPREP_OK)
-                       goto out;
        }
+       return ret;
+}
+EXPORT_SYMBOL(scsi_prep_state_check);
 
-       switch (req->cmd_type) {
-       case REQ_TYPE_BLOCK_PC:
-               ret = scsi_setup_blk_pc_cmnd(sdev, req);
-               break;
-       case REQ_TYPE_FS:
-               ret = scsi_setup_fs_cmnd(sdev, req);
-               break;
-       default:
-               /*
-                * All other command types are not supported.
-                *
-                * Note that these days the SCSI subsystem does not use
-                * REQ_TYPE_SPECIAL requests anymore.  These are only used
-                * (directly or via blk_insert_request) by non-SCSI drivers.
-                */
-               blk_dump_rq_flags(req, "SCSI bad req");
-               ret = BLKPREP_KILL;
-               break;
-       }
+int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
+{
+       struct scsi_device *sdev = q->queuedata;
 
- out:
        switch (ret) {
        case BLKPREP_KILL:
                req->errors = DID_NO_CONNECT << 16;
+               /* release the command and kill it */
+               if (req->special) {
+                       struct scsi_cmnd *cmd = req->special;
+                       scsi_release_buffers(cmd);
+                       scsi_put_command(cmd);
+                       req->special = NULL;
+               }
                break;
        case BLKPREP_DEFER:
                /*
@@ -1237,6 +1209,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
 
        return ret;
 }
+EXPORT_SYMBOL(scsi_prep_return);
+
+static int scsi_prep_fn(struct request_queue *q, struct request *req)
+{
+       struct scsi_device *sdev = q->queuedata;
+       int ret = BLKPREP_KILL;
+
+       if (req->cmd_type == REQ_TYPE_BLOCK_PC)
+               ret = scsi_setup_blk_pc_cmnd(sdev, req);
+       return scsi_prep_return(q, req, ret);
+}
 
 /*
  * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else
index ee8efe849bf41c0c906c5a9f0769e9a054d483a2..eff0059518954b26c62b116cd737f9e11e78da6a 100644 (file)
@@ -68,6 +68,7 @@ extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
 extern void scsi_device_unbusy(struct scsi_device *sdev);
 extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
 extern void scsi_next_command(struct scsi_cmnd *cmd);
+extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
 extern void scsi_free_queue(struct request_queue *q);
index a86e62f4b3ba86b934cdaaecc7f7213d1ef45d68..b53c5f67e372684cc23c81a9f0ce19a41109e1ac 100644 (file)
@@ -85,7 +85,7 @@ static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
 static unsigned int max_scsi_luns = 1;
 #endif
 
-module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_luns, max_scsi_luns, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(max_luns,
                 "last scsi LUN (should be between 1 and 2^32-1)");
 
@@ -109,18 +109,19 @@ MODULE_PARM_DESC(scan, "sync, async or none");
  */
 static unsigned int max_scsi_report_luns = 511;
 
-module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(max_report_luns,
                 "REPORT LUNS maximum number of LUNS received (should be"
                 " between 1 and 16384)");
 
 static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
 
-module_param_named(inq_timeout, scsi_inq_timeout, int, S_IRUGO|S_IWUSR);
+module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(inq_timeout, 
                 "Timeout (in seconds) waiting for devices to answer INQUIRY."
                 " Default is 5. Some non-compliant devices need more.");
 
+/* This lock protects only this list */
 static DEFINE_SPINLOCK(async_scan_lock);
 static LIST_HEAD(scanning_hosts);
 
@@ -1466,14 +1467,14 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
        if (strncmp(scsi_scan_type, "none", 4) == 0)
                return ERR_PTR(-ENODEV);
 
-       if (!shost->async_scan)
-               scsi_complete_async_scans();
-
        starget = scsi_alloc_target(parent, channel, id);
        if (!starget)
                return ERR_PTR(-ENOMEM);
 
        mutex_lock(&shost->scan_mutex);
+       if (!shost->async_scan)
+               scsi_complete_async_scans();
+
        if (scsi_host_scan_allowed(shost))
                scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
        mutex_unlock(&shost->scan_mutex);
@@ -1586,10 +1587,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
        if (strncmp(scsi_scan_type, "none", 4) == 0)
                return;
 
+       mutex_lock(&shost->scan_mutex);
        if (!shost->async_scan)
                scsi_complete_async_scans();
 
-       mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost))
                __scsi_scan_target(parent, channel, id, lun, rescan);
        mutex_unlock(&shost->scan_mutex);
@@ -1634,15 +1635,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
                "%s: <%u:%u:%u>\n",
                __FUNCTION__, channel, id, lun));
 
-       if (!shost->async_scan)
-               scsi_complete_async_scans();
-
        if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
            ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
            ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
                return -EINVAL;
 
        mutex_lock(&shost->scan_mutex);
+       if (!shost->async_scan)
+               scsi_complete_async_scans();
+
        if (scsi_host_scan_allowed(shost)) {
                if (channel == SCAN_WILD_CARD)
                        for (channel = 0; channel <= shost->max_channel;
@@ -1661,7 +1662,8 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
 {
        struct scsi_device *sdev;
        shost_for_each_device(sdev, shost) {
-               if (scsi_sysfs_add_sdev(sdev) != 0)
+               if (!scsi_host_scan_allowed(shost) ||
+                   scsi_sysfs_add_sdev(sdev) != 0)
                        scsi_destroy_sdev(sdev);
        }
 }
@@ -1679,6 +1681,7 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
 static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
 {
        struct async_scan_data *data;
+       unsigned long flags;
 
        if (strncmp(scsi_scan_type, "sync", 4) == 0)
                return NULL;
@@ -1698,8 +1701,13 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
                goto err;
        init_completion(&data->prev_finished);
 
-       spin_lock(&async_scan_lock);
+       mutex_lock(&shost->scan_mutex);
+       spin_lock_irqsave(shost->host_lock, flags);
        shost->async_scan = 1;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+       mutex_unlock(&shost->scan_mutex);
+
+       spin_lock(&async_scan_lock);
        if (list_empty(&scanning_hosts))
                complete(&data->prev_finished);
        list_add_tail(&data->list, &scanning_hosts);
@@ -1723,11 +1731,15 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
 static void scsi_finish_async_scan(struct async_scan_data *data)
 {
        struct Scsi_Host *shost;
+       unsigned long flags;
 
        if (!data)
                return;
 
        shost = data->shost;
+
+       mutex_lock(&shost->scan_mutex);
+
        if (!shost->async_scan) {
                printk("%s called twice for host %d", __FUNCTION__,
                                shost->host_no);
@@ -1739,8 +1751,13 @@ static void scsi_finish_async_scan(struct async_scan_data *data)
 
        scsi_sysfs_add_devices(shost);
 
-       spin_lock(&async_scan_lock);
+       spin_lock_irqsave(shost->host_lock, flags);
        shost->async_scan = 0;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
+       mutex_unlock(&shost->scan_mutex);
+
+       spin_lock(&async_scan_lock);
        list_del(&data->list);
        if (!list_empty(&scanning_hosts)) {
                struct async_scan_data *next = list_entry(scanning_hosts.next,
@@ -1782,6 +1799,7 @@ static int do_scan_async(void *_data)
  **/
 void scsi_scan_host(struct Scsi_Host *shost)
 {
+       struct task_struct *p;
        struct async_scan_data *data;
 
        if (strncmp(scsi_scan_type, "none", 4) == 0)
@@ -1793,7 +1811,9 @@ void scsi_scan_host(struct Scsi_Host *shost)
                return;
        }
 
-       kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+       p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+       if (unlikely(IS_ERR(p)))
+               do_scan_async(data);
 }
 EXPORT_SYMBOL(scsi_scan_host);
 
index ede9986d349ad00ee4baa1ffbb14fe157fa5d65c..daed37df00b14eb6fb11160cabaf77b46a8f8d27 100644 (file)
@@ -190,6 +190,46 @@ show_shost_state(struct class_device *class_dev, char *buf)
 
 static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state);
 
+static ssize_t
+show_shost_mode(unsigned int mode, char *buf)
+{
+       ssize_t len = 0;
+
+       if (mode & MODE_INITIATOR)
+               len = sprintf(buf, "%s", "Initiator");
+
+       if (mode & MODE_TARGET)
+               len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target");
+
+       len += sprintf(buf + len, "\n");
+
+       return len;
+}
+
+static ssize_t show_shost_supported_mode(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+
+       if (shost->hostt->supported_mode == MODE_UNKNOWN)
+               return snprintf(buf, 20, "unknown\n");
+       else
+               return show_shost_mode(shost->hostt->supported_mode, buf);
+}
+
+static CLASS_DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL);
+
+static ssize_t show_shost_active_mode(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+
+       if (shost->active_mode == MODE_UNKNOWN)
+               return snprintf(buf, 20, "unknown\n");
+       else
+               return show_shost_mode(shost->active_mode, buf);
+}
+
+static CLASS_DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL);
+
 shost_rd_attr(unique_id, "%u\n");
 shost_rd_attr(host_busy, "%hu\n");
 shost_rd_attr(cmd_per_lun, "%hd\n");
@@ -208,6 +248,8 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
        &class_device_attr_proc_name,
        &class_device_attr_scan,
        &class_device_attr_state,
+       &class_device_attr_supported_mode,
+       &class_device_attr_active_mode,
        NULL
 };
 
@@ -571,24 +613,31 @@ sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
 static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
 
 /* Default template for device attributes.  May NOT be modified */
-static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
-       &dev_attr_device_blocked,
-       &dev_attr_queue_depth,
-       &dev_attr_queue_type,
-       &dev_attr_type,
-       &dev_attr_scsi_level,
-       &dev_attr_vendor,
-       &dev_attr_model,
-       &dev_attr_rev,
-       &dev_attr_rescan,
-       &dev_attr_delete,
-       &dev_attr_state,
-       &dev_attr_timeout,
-       &dev_attr_iocounterbits,
-       &dev_attr_iorequest_cnt,
-       &dev_attr_iodone_cnt,
-       &dev_attr_ioerr_cnt,
-       &dev_attr_modalias,
+static struct attribute *scsi_sdev_attrs[] = {
+       &dev_attr_device_blocked.attr,
+       &dev_attr_type.attr,
+       &dev_attr_scsi_level.attr,
+       &dev_attr_vendor.attr,
+       &dev_attr_model.attr,
+       &dev_attr_rev.attr,
+       &dev_attr_rescan.attr,
+       &dev_attr_delete.attr,
+       &dev_attr_state.attr,
+       &dev_attr_timeout.attr,
+       &dev_attr_iocounterbits.attr,
+       &dev_attr_iorequest_cnt.attr,
+       &dev_attr_iodone_cnt.attr,
+       &dev_attr_ioerr_cnt.attr,
+       &dev_attr_modalias.attr,
+       NULL
+};
+
+static struct attribute_group scsi_sdev_attr_group = {
+       .attrs =        scsi_sdev_attrs,
+};
+
+static struct attribute_group *scsi_sdev_attr_groups[] = {
+       &scsi_sdev_attr_group,
        NULL
 };
 
@@ -650,56 +699,6 @@ static struct device_attribute sdev_attr_queue_type_rw =
        __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
               sdev_store_queue_type_rw);
 
-static struct device_attribute *attr_changed_internally(
-               struct Scsi_Host *shost,
-               struct device_attribute * attr)
-{
-       if (!strcmp("queue_depth", attr->attr.name)
-           && shost->hostt->change_queue_depth)
-               return &sdev_attr_queue_depth_rw;
-       else if (!strcmp("queue_type", attr->attr.name)
-           && shost->hostt->change_queue_type)
-               return &sdev_attr_queue_type_rw;
-       return attr;
-}
-
-
-static struct device_attribute *attr_overridden(
-               struct device_attribute **attrs,
-               struct device_attribute *attr)
-{
-       int i;
-
-       if (!attrs)
-               return NULL;
-       for (i = 0; attrs[i]; i++)
-               if (!strcmp(attrs[i]->attr.name, attr->attr.name))
-                       return attrs[i];
-       return NULL;
-}
-
-static int attr_add(struct device *dev, struct device_attribute *attr)
-{
-       struct device_attribute *base_attr;
-
-       /*
-        * Spare the caller from having to copy things it's not interested in.
-        */
-       base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr);
-       if (base_attr) {
-               /* extend permissions */
-               attr->attr.mode |= base_attr->attr.mode;
-
-               /* override null show/store with default */
-               if (!attr->show)
-                       attr->show = base_attr->show;
-               if (!attr->store)
-                       attr->store = base_attr->store;
-       }
-
-       return device_create_file(dev, attr);
-}
-
 /**
  * scsi_sysfs_add_sdev - add scsi device to sysfs
  * @sdev:      scsi_device to add
@@ -731,6 +730,24 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
         * released by the sdev_class .release */
        get_device(&sdev->sdev_gendev);
 
+       /* create queue files, which may be writable, depending on the host */
+       if (sdev->host->hostt->change_queue_depth)
+               error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);
+       else
+               error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
+       if (error) {
+               __scsi_remove_device(sdev);
+               goto out;
+       }
+       if (sdev->host->hostt->change_queue_type)
+               error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
+       else
+               error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
+       if (error) {
+               __scsi_remove_device(sdev);
+               goto out;
+       }
+
        error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
 
        if (error)
@@ -741,9 +758,10 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
         * nothing went wrong */
        error = 0;
 
+       /* add additional host specific attributes */
        if (sdev->host->hostt->sdev_attrs) {
                for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
-                       error = attr_add(&sdev->sdev_gendev,
+                       error = device_create_file(&sdev->sdev_gendev,
                                        sdev->host->hostt->sdev_attrs[i]);
                        if (error) {
                                __scsi_remove_device(sdev);
@@ -751,20 +769,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
                        }
                }
        }
-       
-       for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) {
-               if (!attr_overridden(sdev->host->hostt->sdev_attrs,
-                                       scsi_sysfs_sdev_attrs[i])) {
-                       struct device_attribute * attr = 
-                               attr_changed_internally(sdev->host, 
-                                                       scsi_sysfs_sdev_attrs[i]);
-                       error = device_create_file(&sdev->sdev_gendev, attr);
-                       if (error) {
-                               __scsi_remove_device(sdev);
-                               goto out;
-                       }
-               }
-       }
 
        transport_add_device(&sdev->sdev_gendev);
  out:
@@ -951,6 +955,12 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
        return 0;
 }
 
+static struct device_type scsi_dev_type = {
+       .name =         "scsi_device",
+       .release =      scsi_device_dev_release,
+       .groups =       scsi_sdev_attr_groups,
+};
+
 void scsi_sysfs_device_initialize(struct scsi_device *sdev)
 {
        unsigned long flags;
@@ -959,7 +969,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
 
        device_initialize(&sdev->sdev_gendev);
        sdev->sdev_gendev.bus = &scsi_bus_type;
-       sdev->sdev_gendev.release = scsi_device_dev_release;
+       sdev->sdev_gendev.type = &scsi_dev_type;
        sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
                sdev->host->host_no, sdev->channel, sdev->id,
                sdev->lun);
@@ -980,7 +990,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
 
 int scsi_is_sdev_device(const struct device *dev)
 {
-       return dev->release == scsi_device_dev_release;
+       return dev->type == &scsi_dev_type;
 }
 EXPORT_SYMBOL(scsi_is_sdev_device);
 
index ca22ddf8174639d2349ccc6c8a42e2d4976ade5f..9815a1a2db24a4c671ee769a670bfc3d6035fbbe 100644 (file)
@@ -102,7 +102,8 @@ static int tgt_uspace_send_event(u32 type, struct tgt_event *p)
        return 0;
 }
 
-int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag)
+int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
+                            struct scsi_lun *lun, u64 tag)
 {
        struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
        struct tgt_event ev;
@@ -110,6 +111,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta
 
        memset(&ev, 0, sizeof(ev));
        ev.p.cmd_req.host_no = shost->host_no;
+       ev.p.cmd_req.itn_id = itn_id;
        ev.p.cmd_req.data_len = cmd->request_bufflen;
        memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
        memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
@@ -127,7 +129,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta
        return err;
 }
 
-int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag)
 {
        struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
        struct tgt_event ev;
@@ -135,6 +137,7 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
 
        memset(&ev, 0, sizeof(ev));
        ev.p.cmd_done.host_no = shost->host_no;
+       ev.p.cmd_done.itn_id = itn_id;
        ev.p.cmd_done.tag = tag;
        ev.p.cmd_done.result = cmd->result;
 
@@ -149,14 +152,15 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
        return err;
 }
 
-int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
-                                 struct scsi_lun *scsilun, void *data)
+int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function,
+                                 u64 tag, struct scsi_lun *scsilun, void *data)
 {
        struct tgt_event ev;
        int err;
 
        memset(&ev, 0, sizeof(ev));
        ev.p.tsk_mgmt_req.host_no = host_no;
+       ev.p.tsk_mgmt_req.itn_id = itn_id;
        ev.p.tsk_mgmt_req.function = function;
        ev.p.tsk_mgmt_req.tag = tag;
        memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun));
@@ -172,6 +176,29 @@ int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
        return err;
 }
 
+int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id,
+                                         int function, char *initiator_id)
+{
+       struct tgt_event ev;
+       int err;
+
+       memset(&ev, 0, sizeof(ev));
+       ev.p.it_nexus_req.host_no = host_no;
+       ev.p.it_nexus_req.function = function;
+       ev.p.it_nexus_req.itn_id = itn_id;
+       if (initiator_id)
+               strncpy(ev.p.it_nexus_req.initiator_id, initiator_id,
+                       sizeof(ev.p.it_nexus_req.initiator_id));
+
+       dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id);
+
+       err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev);
+       if (err)
+               eprintk("tx buf is full, could not send\n");
+
+       return err;
+}
+
 static int event_recv_msg(struct tgt_event *ev)
 {
        int err = 0;
@@ -179,6 +206,7 @@ static int event_recv_msg(struct tgt_event *ev)
        switch (ev->hdr.type) {
        case TGT_UEVENT_CMD_RSP:
                err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
+                                          ev->p.cmd_rsp.itn_id,
                                           ev->p.cmd_rsp.result,
                                           ev->p.cmd_rsp.tag,
                                           ev->p.cmd_rsp.uaddr,
@@ -189,9 +217,15 @@ static int event_recv_msg(struct tgt_event *ev)
                break;
        case TGT_UEVENT_TSK_MGMT_RSP:
                err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no,
+                                              ev->p.tsk_mgmt_rsp.itn_id,
                                               ev->p.tsk_mgmt_rsp.mid,
                                               ev->p.tsk_mgmt_rsp.result);
                break;
+       case TGT_UEVENT_IT_NEXUS_RSP:
+               err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no,
+                                                  ev->p.it_nexus_rsp.itn_id,
+                                                  ev->p.it_nexus_rsp.result);
+               break;
        default:
                eprintk("unknown type %d\n", ev->hdr.type);
                err = -EINVAL;
index 371b69c110bcc5403b81d4b046ba31dc9888cc9e..66c692ffa3054a2ddafa8c8435bbe642e3737e5c 100644 (file)
@@ -27,6 +27,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
 #include <scsi/scsi_tgt.h>
 
 #include "scsi_tgt_priv.h"
@@ -46,6 +47,7 @@ struct scsi_tgt_cmd {
 
        struct list_head hash_list;
        struct request *rq;
+       u64 itn_id;
        u64 tag;
 };
 
@@ -185,12 +187,13 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
 }
 
 static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,
-                             u64 tag)
+                             u64 itn_id, u64 tag)
 {
        struct scsi_tgt_queuedata *qdata = rq->q->queuedata;
        unsigned long flags;
        struct list_head *head;
 
+       tcmd->itn_id = itn_id;
        tcmd->tag = tag;
        tcmd->bio = NULL;
        INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
@@ -234,7 +237,7 @@ int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
         * command as is recvd to userspace. uspace can then make
         * sure we do not overload the HBA
         */
-       q->nr_requests = shost->hostt->can_queue;
+       q->nr_requests = shost->can_queue;
        /*
         * We currently only support software LLDs so this does
         * not matter for now. Do we need this for the cards we support?
@@ -301,14 +304,14 @@ EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
  * @scsilun:   scsi lun
  * @tag:       unique value to identify this command for tmf
  */
-int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
-                          u64 tag)
+int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id,
+                          struct scsi_lun *scsilun, u64 tag)
 {
        struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
        int err;
 
-       init_scsi_tgt_cmd(cmd->request, tcmd, tag);
-       err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag);
+       init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag);
+       err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag);
        if (err)
                cmd_hashlist_del(cmd);
 
@@ -326,7 +329,7 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
 
        dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
 
-       scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+       scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
 
        if (cmd->request_buffer)
                scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
@@ -459,7 +462,7 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
        return rq;
 }
 
-int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
                         unsigned long uaddr, u32 len, unsigned long sense_uaddr,
                         u32 sense_len, u8 rw)
 {
@@ -541,21 +544,22 @@ done:
        return err;
 }
 
-int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag,
-                             struct scsi_lun *scsilun, void *data)
+int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id,
+                             int function, u64 tag, struct scsi_lun *scsilun,
+                             void *data)
 {
        int err;
 
        /* TODO: need to retry if this fails. */
-       err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function,
-                                           tag, scsilun, data);
+       err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id,
+                                           function, tag, scsilun, data);
        if (err < 0)
                eprintk("The task management request lost!\n");
        return err;
 }
 EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);
 
-int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
+int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result)
 {
        struct Scsi_Host *shost;
        int err = -EINVAL;
@@ -573,7 +577,60 @@ int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
                goto done;
        }
 
-       err = shost->hostt->tsk_mgmt_response(mid, result);
+       err = shost->transportt->tsk_mgmt_response(shost, itn_id, mid, result);
+done:
+       scsi_host_put(shost);
+       return err;
+}
+
+int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+                            char *initiator)
+{
+       int err;
+
+       /* TODO: need to retry if this fails. */
+       err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0,
+                                                   initiator);
+       if (err < 0)
+               eprintk("The i_t_neuxs request lost, %d %llx!\n",
+                       shost->host_no, (unsigned long long)itn_id);
+       return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create);
+
+int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+       int err;
+
+       /* TODO: need to retry if this fails. */
+       err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no,
+                                                   itn_id, 1, NULL);
+       if (err < 0)
+               eprintk("The i_t_neuxs request lost, %d %llx!\n",
+                       shost->host_no, (unsigned long long)itn_id);
+       return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy);
+
+int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
+{
+       struct Scsi_Host *shost;
+       int err = -EINVAL;
+
+       dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
+
+       shost = scsi_host_lookup(host_no);
+       if (IS_ERR(shost)) {
+               printk(KERN_ERR "Could not find host no %d\n", host_no);
+               return err;
+       }
+
+       if (!shost->uspace_req_q) {
+               printk(KERN_ERR "Not target scsi host %d\n", host_no);
+               goto done;
+       }
+
+       err = shost->transportt->it_nexus_response(shost, itn_id, result);
 done:
        scsi_host_put(shost);
        return err;
index e9e6db1c417f38543bedd8415d93e1ce30a6b0c8..cb92888948f9a04756a19bf994e389c02c03a350 100644 (file)
@@ -15,12 +15,18 @@ do {                                                                \
 extern void scsi_tgt_if_exit(void);
 extern int scsi_tgt_if_init(void);
 
-extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
-                                   u64 tag);
-extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
-extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
-                               unsigned long uaddr, u32 len, unsigned long sense_uaddr,
-                               u32 sense_len, u8 rw);
-extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
+extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 it_nexus_id,
+                                   struct scsi_lun *lun, u64 tag);
+extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 it_nexus_id,
+                                      u64 tag);
+extern int scsi_tgt_kspace_exec(int host_no, u64 it_nexus_id, int result, u64 tag,
+                               unsigned long uaddr, u32 len,
+                               unsigned long sense_uaddr, u32 sense_len, u8 rw);
+extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 it_nexus_id,
+                                        int function, u64 tag,
                                         struct scsi_lun *scsilun, void *data);
-extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
+extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 it_nexus_id,
+                                   u64 mid, int result);
+extern int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 it_nexus_id,
+                                                int function, char *initiator);
+extern int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 it_nexus_id, int result);
index 47057254850dae0cf3d7f4b86811474c953455bd..7a7cfe583b2ab46171bb51929465aca2abad2ae5 100644 (file)
@@ -36,6 +36,7 @@
 #include <net/netlink.h>
 #include <scsi/scsi_netlink_fc.h>
 #include "scsi_priv.h"
+#include "scsi_transport_fc_internal.h"
 
 static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
 static void fc_vport_sched_delete(struct work_struct *work);
@@ -473,7 +474,7 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class,
  */
 static unsigned int fc_dev_loss_tmo = 60;              /* seconds */
 
-module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
+module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(dev_loss_tmo,
                 "Maximum number of seconds that the FC transport should"
                 " insulate the loss of a remote port. Once this value is"
@@ -1956,6 +1957,19 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
        return 0;
 }
 
+static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
+                               int result)
+{
+       struct fc_internal *i = to_fc_internal(shost->transportt);
+       return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
+}
+
+static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+{
+       struct fc_internal *i = to_fc_internal(shost->transportt);
+       return i->f->it_nexus_response(shost, nexus, result);
+}
+
 struct scsi_transport_template *
 fc_attach_transport(struct fc_function_template *ft)
 {
@@ -1999,6 +2013,10 @@ fc_attach_transport(struct fc_function_template *ft)
 
        i->t.user_scan = fc_user_scan;
 
+       /* target-mode drivers' functions */
+       i->t.tsk_mgmt_response = fc_tsk_mgmt_response;
+       i->t.it_nexus_response = fc_it_nexus_response;
+
        /*
         * Setup SCSI Target Attributes.
         */
@@ -2756,6 +2774,10 @@ fc_remote_port_delete(struct fc_rport  *rport)
 
        spin_unlock_irqrestore(shost->host_lock, flags);
 
+       if (rport->roles & FC_PORT_ROLE_FCP_INITIATOR &&
+           shost->active_mode & MODE_TARGET)
+               fc_tgt_it_nexus_destroy(shost, (unsigned long)rport);
+
        scsi_target_block(&rport->dev);
 
        /* see if we need to kill io faster than waiting for device loss */
@@ -2796,6 +2818,7 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
        struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
        unsigned long flags;
        int create = 0;
+       int ret;
 
        spin_lock_irqsave(shost->host_lock, flags);
        if (roles & FC_PORT_ROLE_FCP_TARGET) {
@@ -2804,6 +2827,12 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
                        create = 1;
                } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET))
                        create = 1;
+       } else if (shost->active_mode & MODE_TARGET) {
+               ret = fc_tgt_it_nexus_create(shost, (unsigned long)rport,
+                                            (char *)&rport->node_name);
+               if (ret)
+                       printk(KERN_ERR "FC Remore Port tgt nexus failed %d\n",
+                              ret);
        }
 
        rport->roles = roles;
@@ -2988,10 +3017,12 @@ fc_scsi_scan_rport(struct work_struct *work)
        struct fc_rport *rport =
                container_of(work, struct fc_rport, scan_work);
        struct Scsi_Host *shost = rport_to_shost(rport);
+       struct fc_internal *i = to_fc_internal(shost->transportt);
        unsigned long flags;
 
        if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
-           (rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
+           (rport->roles & FC_PORT_ROLE_FCP_TARGET) &&
+           !(i->f->disable_target_scan)) {
                scsi_scan_target(&rport->dev, rport->channel,
                        rport->scsi_target_id, SCAN_WILD_CARD, 1);
        }
diff --git a/drivers/scsi/scsi_transport_fc_internal.h b/drivers/scsi/scsi_transport_fc_internal.h
new file mode 100644 (file)
index 0000000..e7bfbe7
--- /dev/null
@@ -0,0 +1,26 @@
+#include <scsi/scsi_tgt.h>
+
+#ifdef CONFIG_SCSI_FC_TGT_ATTRS
+static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+                                        char *initiator)
+{
+       return scsi_tgt_it_nexus_create(shost, itn_id, initiator);
+}
+
+static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+       return scsi_tgt_it_nexus_destroy(shost, itn_id);
+}
+#else
+static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+                                        char *initiator)
+{
+       return 0;
+}
+
+static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+       return 0;
+}
+
+#endif
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
new file mode 100644 (file)
index 0000000..44a340b
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * SCSI RDMA (SRP) transport class
+ *
+ * Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org>
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_srp.h>
+#include "scsi_transport_srp_internal.h"
+
+struct srp_host_attrs {
+       atomic_t next_port_id;
+};
+#define to_srp_host_attrs(host)        ((struct srp_host_attrs *)(host)->shost_data)
+
+#define SRP_HOST_ATTRS 0
+#define SRP_RPORT_ATTRS 2
+
+struct srp_internal {
+       struct scsi_transport_template t;
+       struct srp_function_template *f;
+
+       struct class_device_attribute *host_attrs[SRP_HOST_ATTRS + 1];
+
+       struct class_device_attribute *rport_attrs[SRP_RPORT_ATTRS + 1];
+       struct class_device_attribute private_rport_attrs[SRP_RPORT_ATTRS];
+       struct transport_container rport_attr_cont;
+};
+
+#define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t)
+
+#define        dev_to_rport(d) container_of(d, struct srp_rport, dev)
+#define transport_class_to_srp_rport(cdev) dev_to_rport((cdev)->dev)
+
+static int srp_host_setup(struct transport_container *tc, struct device *dev,
+                         struct class_device *cdev)
+{
+       struct Scsi_Host *shost = dev_to_shost(dev);
+       struct srp_host_attrs *srp_host = to_srp_host_attrs(shost);
+
+       atomic_set(&srp_host->next_port_id, 0);
+       return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(srp_host_class, "srp_host", srp_host_setup,
+                              NULL, NULL);
+
+static DECLARE_TRANSPORT_CLASS(srp_rport_class, "srp_remote_ports",
+                              NULL, NULL, NULL);
+
+#define SETUP_TEMPLATE(attrb, field, perm, test, ro_test, ro_perm)     \
+       i->private_##attrb[count] = class_device_attr_##field;          \
+       i->private_##attrb[count].attr.mode = perm;                     \
+       if (ro_test) {                                                  \
+               i->private_##attrb[count].attr.mode = ro_perm;          \
+               i->private_##attrb[count].store = NULL;                 \
+       }                                                               \
+       i->attrb[count] = &i->private_##attrb[count];                   \
+       if (test)                                                       \
+               count++
+
+#define SETUP_RPORT_ATTRIBUTE_RD(field)                                        \
+       SETUP_TEMPLATE(rport_attrs, field, S_IRUGO, 1, 0, 0)
+
+#define SETUP_RPORT_ATTRIBUTE_RW(field)                                        \
+       SETUP_TEMPLATE(rport_attrs, field, S_IRUGO | S_IWUSR,           \
+                      1, 1, S_IRUGO)
+
+#define SRP_PID(p) \
+       (p)->port_id[0], (p)->port_id[1], (p)->port_id[2], (p)->port_id[3], \
+       (p)->port_id[4], (p)->port_id[5], (p)->port_id[6], (p)->port_id[7], \
+       (p)->port_id[8], (p)->port_id[9], (p)->port_id[10], (p)->port_id[11], \
+       (p)->port_id[12], (p)->port_id[13], (p)->port_id[14], (p)->port_id[15]
+
+#define SRP_PID_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \
+       "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
+
+static ssize_t
+show_srp_rport_id(struct class_device *cdev, char *buf)
+{
+       struct srp_rport *rport = transport_class_to_srp_rport(cdev);
+       return sprintf(buf, SRP_PID_FMT "\n", SRP_PID(rport));
+}
+
+static CLASS_DEVICE_ATTR(port_id, S_IRUGO, show_srp_rport_id, NULL);
+
+static const struct {
+       u32 value;
+       char *name;
+} srp_rport_role_names[] = {
+       {SRP_RPORT_ROLE_INITIATOR, "SRP Initiator"},
+       {SRP_RPORT_ROLE_TARGET, "SRP Target"},
+};
+
+static ssize_t
+show_srp_rport_roles(struct class_device *cdev, char *buf)
+{
+       struct srp_rport *rport = transport_class_to_srp_rport(cdev);
+       int i;
+       char *name = NULL;
+
+       for (i = 0; i < ARRAY_SIZE(srp_rport_role_names); i++)
+               if (srp_rport_role_names[i].value == rport->roles) {
+                       name = srp_rport_role_names[i].name;
+                       break;
+               }
+       return sprintf(buf, "%s\n", name ? : "unknown");
+}
+
+static CLASS_DEVICE_ATTR(roles, S_IRUGO, show_srp_rport_roles, NULL);
+
+static void srp_rport_release(struct device *dev)
+{
+       struct srp_rport *rport = dev_to_rport(dev);
+
+       put_device(dev->parent);
+       kfree(rport);
+}
+
+static int scsi_is_srp_rport(const struct device *dev)
+{
+       return dev->release == srp_rport_release;
+}
+
+static int srp_rport_match(struct attribute_container *cont,
+                          struct device *dev)
+{
+       struct Scsi_Host *shost;
+       struct srp_internal *i;
+
+       if (!scsi_is_srp_rport(dev))
+               return 0;
+
+       shost = dev_to_shost(dev->parent);
+       if (!shost->transportt)
+               return 0;
+       if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
+               return 0;
+
+       i = to_srp_internal(shost->transportt);
+       return &i->rport_attr_cont.ac == cont;
+}
+
+static int srp_host_match(struct attribute_container *cont, struct device *dev)
+{
+       struct Scsi_Host *shost;
+       struct srp_internal *i;
+
+       if (!scsi_is_host_device(dev))
+               return 0;
+
+       shost = dev_to_shost(dev);
+       if (!shost->transportt)
+               return 0;
+       if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
+               return 0;
+
+       i = to_srp_internal(shost->transportt);
+       return &i->t.host_attrs.ac == cont;
+}
+
+/**
+ * srp_rport_add - add a SRP remote port to the device hierarchy
+ *
+ * @shost:     scsi host the remote port is connected to.
+ * @ids:       The port id for the remote port.
+ *
+ * publishes a port to the rest of the system
+ */
+struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
+                               struct srp_rport_identifiers *ids)
+{
+       struct srp_rport *rport;
+       struct device *parent = &shost->shost_gendev;
+       int id, ret;
+
+       rport = kzalloc(sizeof(*rport), GFP_KERNEL);
+       if (!rport)
+               return ERR_PTR(-ENOMEM);
+
+       device_initialize(&rport->dev);
+
+       rport->dev.parent = get_device(parent);
+       rport->dev.release = srp_rport_release;
+
+       memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id));
+       rport->roles = ids->roles;
+
+       id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id);
+       sprintf(rport->dev.bus_id, "port-%d:%d", shost->host_no, id);
+
+       transport_setup_device(&rport->dev);
+
+       ret = device_add(&rport->dev);
+       if (ret) {
+               transport_destroy_device(&rport->dev);
+               put_device(&rport->dev);
+               return ERR_PTR(ret);
+       }
+
+       if (shost->active_mode & MODE_TARGET &&
+           ids->roles == SRP_RPORT_ROLE_INITIATOR) {
+               ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport,
+                                             rport->port_id);
+               if (ret) {
+                       device_del(&rport->dev);
+                       transport_destroy_device(&rport->dev);
+                       put_device(&rport->dev);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       transport_add_device(&rport->dev);
+       transport_configure_device(&rport->dev);
+
+       return rport;
+}
+EXPORT_SYMBOL_GPL(srp_rport_add);
+
+/**
+ * srp_rport_del  --  remove a SRP remote port
+ * @port:      SRP remote port to remove
+ *
+ * Removes the specified SRP remote port.
+ */
+void srp_rport_del(struct srp_rport *rport)
+{
+       struct device *dev = &rport->dev;
+       struct Scsi_Host *shost = dev_to_shost(dev->parent);
+
+       if (shost->active_mode & MODE_TARGET &&
+           rport->roles == SRP_RPORT_ROLE_INITIATOR)
+               srp_tgt_it_nexus_destroy(shost, (unsigned long)rport);
+
+       transport_remove_device(dev);
+       device_del(dev);
+       transport_destroy_device(dev);
+       put_device(dev);
+}
+EXPORT_SYMBOL_GPL(srp_rport_del);
+
+static int do_srp_rport_del(struct device *dev, void *data)
+{
+       srp_rport_del(dev_to_rport(dev));
+       return 0;
+}
+
+/**
+ * srp_remove_host  --  tear down a Scsi_Host's SRP data structures
+ * @shost:     Scsi Host that is torn down
+ *
+ * Removes all SRP remote ports for a given Scsi_Host.
+ * Must be called just before scsi_remove_host for SRP HBAs.
+ */
+void srp_remove_host(struct Scsi_Host *shost)
+{
+       device_for_each_child(&shost->shost_gendev, NULL, do_srp_rport_del);
+}
+EXPORT_SYMBOL_GPL(srp_remove_host);
+
+static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
+                                int result)
+{
+       struct srp_internal *i = to_srp_internal(shost->transportt);
+       return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
+}
+
+static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+{
+       struct srp_internal *i = to_srp_internal(shost->transportt);
+       return i->f->it_nexus_response(shost, nexus, result);
+}
+
+/**
+ * srp_attach_transport  --  instantiate SRP transport template
+ * @ft:                SRP transport class function template
+ */
+struct scsi_transport_template *
+srp_attach_transport(struct srp_function_template *ft)
+{
+       int count;
+       struct srp_internal *i;
+
+       i = kzalloc(sizeof(*i), GFP_KERNEL);
+       if (!i)
+               return NULL;
+
+       i->t.tsk_mgmt_response = srp_tsk_mgmt_response;
+       i->t.it_nexus_response = srp_it_nexus_response;
+
+       i->t.host_size = sizeof(struct srp_host_attrs);
+       i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+       i->t.host_attrs.ac.class = &srp_host_class.class;
+       i->t.host_attrs.ac.match = srp_host_match;
+       i->host_attrs[0] = NULL;
+       transport_container_register(&i->t.host_attrs);
+
+       i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
+       i->rport_attr_cont.ac.class = &srp_rport_class.class;
+       i->rport_attr_cont.ac.match = srp_rport_match;
+       transport_container_register(&i->rport_attr_cont);
+
+       count = 0;
+       SETUP_RPORT_ATTRIBUTE_RD(port_id);
+       SETUP_RPORT_ATTRIBUTE_RD(roles);
+       i->rport_attrs[count] = NULL;
+
+       i->f = ft;
+
+       return &i->t;
+}
+EXPORT_SYMBOL_GPL(srp_attach_transport);
+
+/**
+ * srp_release_transport  --  release SRP transport template instance
+ * @t:         transport template instance
+ */
+void srp_release_transport(struct scsi_transport_template *t)
+{
+       struct srp_internal *i = to_srp_internal(t);
+
+       transport_container_unregister(&i->t.host_attrs);
+       transport_container_unregister(&i->rport_attr_cont);
+
+       kfree(i);
+}
+EXPORT_SYMBOL_GPL(srp_release_transport);
+
+static __init int srp_transport_init(void)
+{
+       int ret;
+
+       ret = transport_class_register(&srp_host_class);
+       if (ret)
+               return ret;
+       ret = transport_class_register(&srp_rport_class);
+       if (ret)
+               goto unregister_host_class;
+
+       return 0;
+unregister_host_class:
+       transport_class_unregister(&srp_host_class);
+       return ret;
+}
+
+static void __exit srp_transport_exit(void)
+{
+       transport_class_unregister(&srp_host_class);
+       transport_class_unregister(&srp_rport_class);
+}
+
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_DESCRIPTION("SRP Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(srp_transport_init);
+module_exit(srp_transport_exit);
diff --git a/drivers/scsi/scsi_transport_srp_internal.h b/drivers/scsi/scsi_transport_srp_internal.h
new file mode 100644 (file)
index 0000000..8a79747
--- /dev/null
@@ -0,0 +1,25 @@
+#include <scsi/scsi_tgt.h>
+
+#ifdef CONFIG_SCSI_SRP_TGT_ATTRS
+static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+                                         char *initiator)
+{
+       return scsi_tgt_it_nexus_create(shost, itn_id, initiator);
+}
+
+static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+       return scsi_tgt_it_nexus_destroy(shost, itn_id);
+}
+
+#else
+static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+                                         char *initiator)
+{
+       return 0;
+}
+static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+       return 0;
+}
+#endif
index 2c6116fd457818a27be8552119425030a6143e68..0a3a528212c2f3fca24f39a9951caba2f2d4e2d0 100644 (file)
@@ -86,6 +86,19 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
 MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
 MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
 
+static int  sd_revalidate_disk(struct gendisk *);
+static int  sd_probe(struct device *);
+static int  sd_remove(struct device *);
+static void sd_shutdown(struct device *);
+static int sd_suspend(struct device *, pm_message_t state);
+static int sd_resume(struct device *);
+static void sd_rescan(struct device *);
+static int sd_done(struct scsi_cmnd *);
+static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
+static void scsi_disk_release(struct class_device *cdev);
+static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
+static void sd_print_result(struct scsi_disk *, int);
+
 static DEFINE_IDR(sd_index_idr);
 static DEFINE_SPINLOCK(sd_index_lock);
 
@@ -240,7 +253,7 @@ static struct scsi_driver sd_template = {
                .shutdown       = sd_shutdown,
        },
        .rescan                 = sd_rescan,
-       .init_command           = sd_init_command,
+       .done                   = sd_done,
 };
 
 /*
@@ -331,14 +344,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
  *
  *     Returns 1 if successful and 0 if error (or cannot be done now).
  **/
-static int sd_init_command(struct scsi_cmnd * SCpnt)
+static int sd_prep_fn(struct request_queue *q, struct request *rq)
 {
-       struct scsi_device *sdp = SCpnt->device;
-       struct request *rq = SCpnt->request;
+       struct scsi_cmnd *SCpnt;
+       struct scsi_device *sdp = q->queuedata;
        struct gendisk *disk = rq->rq_disk;
        sector_t block = rq->sector;
-       unsigned int this_count = SCpnt->request_bufflen >> 9;
+       unsigned int this_count = rq->nr_sectors;
        unsigned int timeout = sdp->timeout;
+       int ret;
+
+       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+               ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+               goto out;
+       } else if (rq->cmd_type != REQ_TYPE_FS) {
+               ret = BLKPREP_KILL;
+               goto out;
+       }
+       ret = scsi_setup_fs_cmnd(sdp, rq);
+       if (ret != BLKPREP_OK)
+               goto out;
+       SCpnt = rq->special;
+
+       /* from here on until we're complete, any goto out
+        * is used for a killable error condition */
+       ret = BLKPREP_KILL;
 
        SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
                                        "sd_init_command: block=%llu, "
@@ -353,7 +383,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                                                rq->nr_sectors));
                SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
                                                "Retry with 0x%p\n", SCpnt));
-               return 0;
+               goto out;
        }
 
        if (sdp->changed) {
@@ -362,8 +392,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                 * the changed bit has been reset
                 */
                /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
-               return 0;
+               goto out;
        }
+
        SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
                                        (unsigned long long)block));
 
@@ -382,7 +413,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                if ((block & 1) || (rq->nr_sectors & 1)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
-                       return 0;
+                       goto out;
                } else {
                        block = block >> 1;
                        this_count = this_count >> 1;
@@ -392,7 +423,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                if ((block & 3) || (rq->nr_sectors & 3)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
-                       return 0;
+                       goto out;
                } else {
                        block = block >> 2;
                        this_count = this_count >> 2;
@@ -402,7 +433,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                if ((block & 7) || (rq->nr_sectors & 7)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
-                       return 0;
+                       goto out;
                } else {
                        block = block >> 3;
                        this_count = this_count >> 3;
@@ -410,7 +441,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
        }
        if (rq_data_dir(rq) == WRITE) {
                if (!sdp->writeable) {
-                       return 0;
+                       goto out;
                }
                SCpnt->cmnd[0] = WRITE_6;
                SCpnt->sc_data_direction = DMA_TO_DEVICE;
@@ -419,7 +450,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                SCpnt->sc_data_direction = DMA_FROM_DEVICE;
        } else {
                scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
-               return 0;
+               goto out;
        }
 
        SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
@@ -470,7 +501,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                         */
                        scmd_printk(KERN_ERR, SCpnt,
                                    "FUA write on READ/WRITE(6) drive\n");
-                       return 0;
+                       goto out;
                }
 
                SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
@@ -491,17 +522,13 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
        SCpnt->allowed = SD_MAX_RETRIES;
        SCpnt->timeout_per_command = timeout;
 
-       /*
-        * This is the completion routine we use.  This is matched in terms
-        * of capability to this function.
-        */
-       SCpnt->done = sd_rw_intr;
-
        /*
         * This indicates that the command is ready from our end to be
         * queued.
         */
-       return 1;
+       ret = BLKPREP_OK;
+ out:
+       return scsi_prep_return(q, rq, ret);
 }
 
 /**
@@ -889,13 +916,13 @@ static struct block_device_operations sd_fops = {
 };
 
 /**
- *     sd_rw_intr - bottom half handler: called when the lower level
+ *     sd_done - bottom half handler: called when the lower level
  *     driver has completed (successfully or otherwise) a scsi command.
  *     @SCpnt: mid-level's per command structure.
  *
  *     Note: potentially run from within an ISR. Must not block.
  **/
-static void sd_rw_intr(struct scsi_cmnd * SCpnt)
+static int sd_done(struct scsi_cmnd *SCpnt)
 {
        int result = SCpnt->result;
        unsigned int xfer_size = SCpnt->request_bufflen;
@@ -916,7 +943,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
        SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));
        if (sense_valid) {
                SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
-                                                  "sd_rw_intr: sb[respc,sk,asc,"
+                                                  "sd_done: sb[respc,sk,asc,"
                                                   "ascq]=%x,%x,%x,%x\n",
                                                   sshdr.response_code,
                                                   sshdr.sense_key, sshdr.asc,
@@ -988,7 +1015,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
                break;
        }
  out:
-       scsi_io_completion(SCpnt, good_bytes);
+       return good_bytes;
 }
 
 static int media_not_present(struct scsi_disk *sdkp,
@@ -1669,6 +1696,7 @@ static int sd_probe(struct device *dev)
 
        sd_revalidate_disk(gd);
 
+       blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
        blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);
 
        gd->driverfs_dev = &sdp->sdev_gendev;
index 85d38940a6c91e2b0d5b546bb0705bdd3ab37f8a..f6f5fc7d0ceeed80a55e7c1a53d95928c767efcf 100644 (file)
@@ -43,6 +43,7 @@ static int sg_version_num = 30534;    /* 2 digits for each component */
 #include <linux/poll.h>
 #include <linux/moduleparam.h>
 #include <linux/cdev.h>
+#include <linux/idr.h>
 #include <linux/seq_file.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
@@ -99,12 +100,11 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_DEV_ARR_LUMP 32     /* amount to over allocate sg_dev_arr by */
-
 static int sg_add(struct class_device *, struct class_interface *);
 static void sg_remove(struct class_device *, struct class_interface *);
 
-static DEFINE_RWLOCK(sg_dev_arr_lock); /* Also used to lock
+static DEFINE_IDR(sg_index_idr);
+static DEFINE_RWLOCK(sg_index_lock);   /* Also used to lock
                                                           file descriptor list for device */
 
 static struct class_interface sg_interface = {
@@ -114,7 +114,7 @@ static struct class_interface sg_interface = {
 
 typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
        unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
-       unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
+       unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */
        unsigned bufflen;       /* Size of (aggregate) data buffer */
        unsigned b_malloc_len;  /* actual len malloc'ed in buffer */
        struct scatterlist *buffer;/* scatter list */
@@ -162,6 +162,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
        struct scsi_device *device;
        wait_queue_head_t o_excl_wait;  /* queue open() when O_EXCL in use */
        int sg_tablesize;       /* adapter's max scatter-gather table size */
+       u32 index;              /* device index number */
        Sg_fd *headfp;          /* first open fd belonging to this device */
        volatile char detached; /* 0->attached, 1->detached pending removal */
        volatile char exclude;  /* opened for exclusive access */
@@ -209,10 +210,6 @@ static Sg_device *sg_get_dev(int dev);
 static int sg_last_dev(void);
 #endif
 
-static Sg_device **sg_dev_arr = NULL;
-static int sg_dev_max;
-static int sg_nr_dev;
-
 #define SZ_SG_HEADER sizeof(struct sg_header)
 #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
 #define SZ_SG_IOVEC sizeof(sg_iovec_t)
@@ -1331,40 +1328,35 @@ static struct class *sg_sysfs_class;
 
 static int sg_sysfs_valid = 0;
 
-static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
+static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
 {
        struct request_queue *q = scsidp->request_queue;
        Sg_device *sdp;
        unsigned long iflags;
-       void *old_sg_dev_arr = NULL;
-       int k, error;
+       int error;
+       u32 k;
 
        sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
        if (!sdp) {
                printk(KERN_WARNING "kmalloc Sg_device failure\n");
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
+       }
+       error = -ENOMEM;
+       if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) {
+               printk(KERN_WARNING "idr expansion Sg_device failure\n");
+               goto out;
        }
 
-       write_lock_irqsave(&sg_dev_arr_lock, iflags);
-       if (unlikely(sg_nr_dev >= sg_dev_max)) {        /* try to resize */
-               Sg_device **tmp_da;
-               int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
-               write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-
-               tmp_da = kzalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL);
-               if (unlikely(!tmp_da))
-                       goto expand_failed;
+       write_lock_irqsave(&sg_index_lock, iflags);
+       error = idr_get_new(&sg_index_idr, sdp, &k);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
 
-               write_lock_irqsave(&sg_dev_arr_lock, iflags);
-               memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *));
-               old_sg_dev_arr = sg_dev_arr;
-               sg_dev_arr = tmp_da;
-               sg_dev_max = tmp_dev_max;
+       if (error) {
+               printk(KERN_WARNING "idr allocation Sg_device failure: %d\n",
+                      error);
+               goto out;
        }
 
-       for (k = 0; k < sg_dev_max; k++)
-               if (!sg_dev_arr[k])
-                       break;
        if (unlikely(k >= SG_MAX_DEVS))
                goto overflow;
 
@@ -1375,25 +1367,17 @@ static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
        sdp->device = scsidp;
        init_waitqueue_head(&sdp->o_excl_wait);
        sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments);
+       sdp->index = k;
 
-       sg_nr_dev++;
-       sg_dev_arr[k] = sdp;
-       write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-       error = k;
-
+       error = 0;
  out:
-       if (error < 0)
+       if (error) {
                kfree(sdp);
-       kfree(old_sg_dev_arr);
-       return error;
-
- expand_failed:
-       printk(KERN_WARNING "sg_alloc: device array cannot be resized\n");
-       error = -ENOMEM;
-       goto out;
+               return ERR_PTR(error);
+       }
+       return sdp;
 
  overflow:
-       write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
        sdev_printk(KERN_WARNING, scsidp,
                    "Unable to attach sg device type=%d, minor "
                    "number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1);
@@ -1408,7 +1392,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
        struct gendisk *disk;
        Sg_device *sdp = NULL;
        struct cdev * cdev = NULL;
-       int error, k;
+       int error;
        unsigned long iflags;
 
        disk = alloc_disk(1);
@@ -1427,15 +1411,15 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
        cdev->owner = THIS_MODULE;
        cdev->ops = &sg_fops;
 
-       error = sg_alloc(disk, scsidp);
-       if (error < 0) {
+       sdp = sg_alloc(disk, scsidp);
+       if (IS_ERR(sdp)) {
                printk(KERN_WARNING "sg_alloc failed\n");
+               error = PTR_ERR(sdp);
                goto out;
        }
-       k = error;
-       sdp = sg_dev_arr[k];
 
-       error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
+       class_set_devdata(cl_dev, sdp);
+       error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
        if (error)
                goto cdev_add_err;
 
@@ -1444,8 +1428,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
                struct class_device * sg_class_member;
 
                sg_class_member = class_device_create(sg_sysfs_class, NULL,
-                               MKDEV(SCSI_GENERIC_MAJOR, k), 
-                               cl_dev->dev, "%s", 
+                               MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
+                               cl_dev->dev, "%s",
                                disk->disk_name);
                if (IS_ERR(sg_class_member))
                        printk(KERN_WARNING "sg_add: "
@@ -1455,21 +1439,21 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
                                          &sg_class_member->kobj, "generic");
                if (error)
                        printk(KERN_ERR "sg_add: unable to make symlink "
-                                       "'generic' back to sg%d\n", k);
+                                       "'generic' back to sg%d\n", sdp->index);
        } else
-               printk(KERN_WARNING "sg_add: sg_sys INvalid\n");
+               printk(KERN_WARNING "sg_add: sg_sys Invalid\n");
 
        sdev_printk(KERN_NOTICE, scsidp,
-                   "Attached scsi generic sg%d type %d\n", k,scsidp->type);
+                   "Attached scsi generic sg%d type %d\n", sdp->index,
+                   scsidp->type);
 
        return 0;
 
 cdev_add_err:
-       write_lock_irqsave(&sg_dev_arr_lock, iflags);
-       kfree(sg_dev_arr[k]);
-       sg_dev_arr[k] = NULL;
-       sg_nr_dev--;
-       write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+       write_lock_irqsave(&sg_index_lock, iflags);
+       idr_remove(&sg_index_idr, sdp->index);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
+       kfree(sdp);
 
 out:
        put_disk(disk);
@@ -1482,64 +1466,56 @@ static void
 sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
 {
        struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
-       Sg_device *sdp = NULL;
+       Sg_device *sdp = class_get_devdata(cl_dev);
        unsigned long iflags;
        Sg_fd *sfp;
        Sg_fd *tsfp;
        Sg_request *srp;
        Sg_request *tsrp;
-       int k, delay;
+       int delay;
 
-       if (NULL == sg_dev_arr)
+       if (!sdp)
                return;
+
        delay = 0;
-       write_lock_irqsave(&sg_dev_arr_lock, iflags);
-       for (k = 0; k < sg_dev_max; k++) {
-               sdp = sg_dev_arr[k];
-               if ((NULL == sdp) || (sdp->device != scsidp))
-                       continue;       /* dirty but lowers nesting */
-               if (sdp->headfp) {
-                       sdp->detached = 1;
-                       for (sfp = sdp->headfp; sfp; sfp = tsfp) {
-                               tsfp = sfp->nextfp;
-                               for (srp = sfp->headrp; srp; srp = tsrp) {
-                                       tsrp = srp->nextrp;
-                                       if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
-                                               sg_finish_rem_req(srp);
-                               }
-                               if (sfp->closed) {
-                                       scsi_device_put(sdp->device);
-                                       __sg_remove_sfp(sdp, sfp);
-                               } else {
-                                       delay = 1;
-                                       wake_up_interruptible(&sfp->read_wait);
-                                       kill_fasync(&sfp->async_qp, SIGPOLL,
-                                                   POLL_HUP);
-                               }
+       write_lock_irqsave(&sg_index_lock, iflags);
+       if (sdp->headfp) {
+               sdp->detached = 1;
+               for (sfp = sdp->headfp; sfp; sfp = tsfp) {
+                       tsfp = sfp->nextfp;
+                       for (srp = sfp->headrp; srp; srp = tsrp) {
+                               tsrp = srp->nextrp;
+                               if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
+                                       sg_finish_rem_req(srp);
                        }
-                       SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k));
-                       if (NULL == sdp->headfp) {
-                               sg_dev_arr[k] = NULL;
+                       if (sfp->closed) {
+                               scsi_device_put(sdp->device);
+                               __sg_remove_sfp(sdp, sfp);
+                       } else {
+                               delay = 1;
+                               wake_up_interruptible(&sfp->read_wait);
+                               kill_fasync(&sfp->async_qp, SIGPOLL,
+                                           POLL_HUP);
                        }
-               } else {        /* nothing active, simple case */
-                       SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k));
-                       sg_dev_arr[k] = NULL;
                }
-               sg_nr_dev--;
-               break;
-       }
-       write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-
-       if (sdp) {
-               sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
-               class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k));
-               cdev_del(sdp->cdev);
-               sdp->cdev = NULL;
-               put_disk(sdp->disk);
-               sdp->disk = NULL;
-               if (NULL == sdp->headfp)
-                       kfree((char *) sdp);
-       }
+               SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index));
+               if (NULL == sdp->headfp) {
+                       idr_remove(&sg_index_idr, sdp->index);
+               }
+       } else {        /* nothing active, simple case */
+               SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index));
+               idr_remove(&sg_index_idr, sdp->index);
+       }
+       write_unlock_irqrestore(&sg_index_lock, iflags);
+
+       sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
+       class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
+       cdev_del(sdp->cdev);
+       sdp->cdev = NULL;
+       put_disk(sdp->disk);
+       sdp->disk = NULL;
+       if (NULL == sdp->headfp)
+               kfree(sdp);
 
        if (delay)
                msleep(10);     /* dirty detach so delay device destruction */
@@ -1609,9 +1585,7 @@ exit_sg(void)
        sg_sysfs_valid = 0;
        unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
                                 SG_MAX_DEVS);
-       kfree((char *)sg_dev_arr);
-       sg_dev_arr = NULL;
-       sg_dev_max = 0;
+       idr_destroy(&sg_index_idr);
 }
 
 static int
@@ -2331,10 +2305,10 @@ sg_get_nth_sfp(Sg_device * sdp, int nth)
        unsigned long iflags;
        int k;
 
-       read_lock_irqsave(&sg_dev_arr_lock, iflags);
+       read_lock_irqsave(&sg_index_lock, iflags);
        for (k = 0, resp = sdp->headfp; resp && (k < nth);
             ++k, resp = resp->nextfp) ;
-       read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+       read_unlock_irqrestore(&sg_index_lock, iflags);
        return resp;
 }
 #endif
@@ -2361,7 +2335,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
        sfp->cmd_q = SG_DEF_COMMAND_Q;
        sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
        sfp->parentdp = sdp;
-       write_lock_irqsave(&sg_dev_arr_lock, iflags);
+       write_lock_irqsave(&sg_index_lock, iflags);
        if (!sdp->headfp)
                sdp->headfp = sfp;
        else {                  /* add to tail of existing list */
@@ -2370,7 +2344,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
                        pfp = pfp->nextfp;
                pfp->nextfp = sfp;
        }
-       write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
        if (unlikely(sg_big_buff != def_reserved_size))
                sg_big_buff = def_reserved_size;
@@ -2431,22 +2405,14 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
        if (0 == dirty) {
                unsigned long iflags;
 
-               write_lock_irqsave(&sg_dev_arr_lock, iflags);
+               write_lock_irqsave(&sg_index_lock, iflags);
                __sg_remove_sfp(sdp, sfp);
                if (sdp->detached && (NULL == sdp->headfp)) {
-                       int k, maxd;
-
-                       maxd = sg_dev_max;
-                       for (k = 0; k < maxd; ++k) {
-                               if (sdp == sg_dev_arr[k])
-                                       break;
-                       }
-                       if (k < maxd)
-                               sg_dev_arr[k] = NULL;
-                       kfree((char *) sdp);
+                       idr_remove(&sg_index_idr, sdp->index);
+                       kfree(sdp);
                        res = 1;
                }
-               write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+               write_unlock_irqrestore(&sg_index_lock, iflags);
        } else {
                /* MOD_INC's to inhibit unloading sg and associated adapter driver */
                /* only bump the access_count if we actually succeeded in
@@ -2545,17 +2511,26 @@ sg_allow_access(unsigned char opcode, char dev_type)
 }
 
 #ifdef CONFIG_SCSI_PROC_FS
+static int
+sg_idr_max_id(int id, void *p, void *data)
+{
+       int *k = data;
+
+       if (*k < id)
+               *k = id;
+
+       return 0;
+}
+
 static int
 sg_last_dev(void)
 {
-       int k;
+       int k = 0;
        unsigned long iflags;
 
-       read_lock_irqsave(&sg_dev_arr_lock, iflags);
-       for (k = sg_dev_max - 1; k >= 0; --k)
-               if (sg_dev_arr[k] && sg_dev_arr[k]->device)
-                       break;
-       read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+       read_lock_irqsave(&sg_index_lock, iflags);
+       idr_for_each(&sg_index_idr, sg_idr_max_id, &k);
+       read_unlock_irqrestore(&sg_index_lock, iflags);
        return k + 1;           /* origin 1 */
 }
 #endif
@@ -2563,15 +2538,13 @@ sg_last_dev(void)
 static Sg_device *
 sg_get_dev(int dev)
 {
-       Sg_device *sdp = NULL;
+       Sg_device *sdp;
        unsigned long iflags;
 
-       if (sg_dev_arr && (dev >= 0)) {
-               read_lock_irqsave(&sg_dev_arr_lock, iflags);
-               if (dev < sg_dev_max)
-                       sdp = sg_dev_arr[dev];
-               read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-       }
+       read_lock_irqsave(&sg_index_lock, iflags);
+       sdp = idr_find(&sg_index_idr, dev);
+       read_unlock_irqrestore(&sg_index_lock, iflags);
+
        return sdp;
 }
 
@@ -2805,8 +2778,6 @@ static void * dev_seq_start(struct seq_file *s, loff_t *pos)
        if (! it)
                return NULL;
 
-       if (NULL == sg_dev_arr)
-               return NULL;
        it->index = *pos;
        it->max = sg_last_dev();
        if (it->index >= it->max)
@@ -2942,8 +2913,8 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
        Sg_device *sdp;
 
        if (it && (0 == it->index)) {
-               seq_printf(s, "dev_max(currently)=%d max_active_device=%d "
-                          "(origin 1)\n", sg_dev_max, (int)it->max);
+               seq_printf(s, "max_active_device=%d(origin 1)\n",
+                          (int)it->max);
                seq_printf(s, " def_reserved_size=%d\n", sg_big_buff);
        }
        sdp = it ? sg_get_dev(it->index) : NULL;
index 902eb11ffe8a1110d0c911a367432f06865dd3a0..c61999031141ca8912a3ac0cecd441bae53cc2db 100644 (file)
@@ -78,7 +78,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
 
 static int sr_probe(struct device *);
 static int sr_remove(struct device *);
-static int sr_init_command(struct scsi_cmnd *);
+static int sr_done(struct scsi_cmnd *);
 
 static struct scsi_driver sr_template = {
        .owner                  = THIS_MODULE,
@@ -87,7 +87,7 @@ static struct scsi_driver sr_template = {
                .probe          = sr_probe,
                .remove         = sr_remove,
        },
-       .init_command           = sr_init_command,
+       .done                   = sr_done,
 };
 
 static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG];
@@ -210,12 +210,12 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 }
  
 /*
- * rw_intr is the interrupt routine for the device driver.
+ * sr_done is the interrupt routine for the device driver.
  *
- * It will be notified on the end of a SCSI read / write, and will take on
+ * It will be notified on the end of a SCSI read / write, and will take one
  * of several actions based on success or failure.
  */
-static void rw_intr(struct scsi_cmnd * SCpnt)
+static int sr_done(struct scsi_cmnd *SCpnt)
 {
        int result = SCpnt->result;
        int this_count = SCpnt->request_bufflen;
@@ -288,27 +288,42 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
                }
        }
 
-       /*
-        * This calls the generic completion function, now that we know
-        * how many actual sectors finished, and how many sectors we need
-        * to say have failed.
-        */
-       scsi_io_completion(SCpnt, good_bytes);
+       return good_bytes;
 }
 
-static int sr_init_command(struct scsi_cmnd * SCpnt)
+static int sr_prep_fn(struct request_queue *q, struct request *rq)
 {
        int block=0, this_count, s_size, timeout = SR_TIMEOUT;
-       struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
+       struct scsi_cd *cd;
+       struct scsi_cmnd *SCpnt;
+       struct scsi_device *sdp = q->queuedata;
+       int ret;
+
+       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+               ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+               goto out;
+       } else if (rq->cmd_type != REQ_TYPE_FS) {
+               ret = BLKPREP_KILL;
+               goto out;
+       }
+       ret = scsi_setup_fs_cmnd(sdp, rq);
+       if (ret != BLKPREP_OK)
+               goto out;
+       SCpnt = rq->special;
+       cd = scsi_cd(rq->rq_disk);
+
+       /* from here on until we're complete, any goto out
+        * is used for a killable error condition */
+       ret = BLKPREP_KILL;
 
        SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
                                cd->disk->disk_name, block));
 
        if (!cd->device || !scsi_device_online(cd->device)) {
                SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
-                                       SCpnt->request->nr_sectors));
+                                       rq->nr_sectors));
                SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
-               return 0;
+               goto out;
        }
 
        if (cd->device->changed) {
@@ -316,7 +331,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
                 * quietly refuse to do anything to a changed disc until the
                 * changed bit has been reset
                 */
-               return 0;
+               goto out;
        }
 
        /*
@@ -333,21 +348,21 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
 
        if (s_size != 512 && s_size != 1024 && s_size != 2048) {
                scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size);
-               return 0;
+               goto out;
        }
 
-       if (rq_data_dir(SCpnt->request) == WRITE) {
+       if (rq_data_dir(rq) == WRITE) {
                if (!cd->device->writeable)
-                       return 0;
+                       goto out;
                SCpnt->cmnd[0] = WRITE_10;
                SCpnt->sc_data_direction = DMA_TO_DEVICE;
                cd->cdi.media_written = 1;
-       } else if (rq_data_dir(SCpnt->request) == READ) {
+       } else if (rq_data_dir(rq) == READ) {
                SCpnt->cmnd[0] = READ_10;
                SCpnt->sc_data_direction = DMA_FROM_DEVICE;
        } else {
-               blk_dump_rq_flags(SCpnt->request, "Unknown sr command");
-               return 0;
+               blk_dump_rq_flags(rq, "Unknown sr command");
+               goto out;
        }
 
        {
@@ -368,10 +383,10 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
        /*
         * request doesn't start on hw block boundary, add scatter pads
         */
-       if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) ||
+       if (((unsigned int)rq->sector % (s_size >> 9)) ||
            (SCpnt->request_bufflen % s_size)) {
                scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n");
-               return 0;
+               goto out;
        }
 
        this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9);
@@ -379,12 +394,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
 
        SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
                                cd->cdi.name,
-                               (rq_data_dir(SCpnt->request) == WRITE) ?
+                               (rq_data_dir(rq) == WRITE) ?
                                        "writing" : "reading",
-                               this_count, SCpnt->request->nr_sectors));
+                               this_count, rq->nr_sectors));
 
        SCpnt->cmnd[1] = 0;
-       block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
+       block = (unsigned int)rq->sector / (s_size >> 9);
 
        if (this_count > 0xffff) {
                this_count = 0xffff;
@@ -409,17 +424,13 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
        SCpnt->allowed = MAX_RETRIES;
        SCpnt->timeout_per_command = timeout;
 
-       /*
-        * This is the completion routine we use.  This is matched in terms
-        * of capability to this function.
-        */
-       SCpnt->done = rw_intr;
-
        /*
         * This indicates that the command is ready from our end to be
         * queued.
         */
-       return 1;
+       ret = BLKPREP_OK;
+ out:
+       return scsi_prep_return(q, rq, ret);
 }
 
 static int sr_block_open(struct inode *inode, struct file *file)
@@ -590,6 +601,7 @@ static int sr_probe(struct device *dev)
 
        /* FIXME: need to handle a get_capabilities failure properly ?? */
        get_capabilities(cd);
+       blk_queue_prep_rq(sdev->request_queue, sr_prep_fn);
        sr_vendor_init(cd);
 
        disk->driverfs_dev = &sdev->sdev_gendev;
index 98e3fe10c1dcfe8d6be2c12f9c8da461afcae710..dc15a22105f71ac6102cd4b63e5b60c2ab4ca3ef 100644 (file)
@@ -2055,7 +2055,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
                sink = 1;
                do_abort(instance);
                cmd->result = DID_ERROR  << 16;
-               cmd->done(cmd);
+               cmd->scsi_done(cmd);
                return;
 #endif
            case PHASE_DATAIN:
@@ -2115,7 +2115,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
                        sink = 1;
                        do_abort(instance);
                        cmd->result = DID_ERROR  << 16;
-                       cmd->done(cmd);
+                       cmd->scsi_done(cmd);
                        /* XXX - need to source or sink data here, as appropriate */
                    } else {
 #ifdef REAL_DMA
@@ -2254,25 +2254,21 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
                        cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
                    
 #ifdef AUTOSENSE
+                   if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+                                               hostdata->ses.cmd_len) {
+                       scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+                       hostdata->ses.cmd_len = 0 ;
+                   }
+
                    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
                        (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+                       scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
                        ASEN_PRINTK("scsi%d: performing request sense\n",
                                    HOSTNO);
-                       cmd->cmnd[0] = REQUEST_SENSE;
-                       cmd->cmnd[1] &= 0xe0;
-                       cmd->cmnd[2] = 0;
-                       cmd->cmnd[3] = 0;
-                       cmd->cmnd[4] = sizeof(cmd->sense_buffer);
-                       cmd->cmnd[5] = 0;
-                       cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
-                       cmd->use_sg = 0;
                        /* this is initialized from initialize_SCp 
                        cmd->SCp.buffer = NULL;
                        cmd->SCp.buffers_residual = 0;
                        */
-                       cmd->request_buffer = (char *) cmd->sense_buffer;
-                       cmd->request_bufflen = sizeof(cmd->sense_buffer);
 
                        local_irq_save(flags);
                        LIST(cmd,hostdata->issue_queue);
index 5db1520f8ba968a48a9bcc783d2e100cc5d0c98f..5c72ca31a47a9d69a11915f76d7f9e645071b685 100644 (file)
@@ -567,12 +567,12 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
        pDCB->TagMask |= 1 << tag[1];
        pSRB->TagNumber = tag[1];
        DC390_write8(ScsiFifo, tag[1]);
-       DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->pid, pSRB, tag[1]));
+       DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->serial_number, pSRB, tag[1]));
        cmd = SEL_W_ATN3;
     } else {
        /* No TagQ */
 //no_tag:
-       DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->pid, pSRB));
+       DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->serial_number, pSRB));
     }
 
     pSRB->SRBState = SRB_START_;
@@ -623,7 +623,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
     {
        dc390_freetag (pDCB, pSRB);
        DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n",
-               scmd->pid, scmd->device->id, scmd->device->lun));
+               scmd->serial_number, scmd->device->id, scmd->device->lun));
        pSRB->SRBState = SRB_READY;
        //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
        pACB->SelLost++;
@@ -1708,7 +1708,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
     status = pSRB->TargetStatus;
 
     DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
-               pSRB, pcmd->pid));
+               pSRB, pcmd->serial_number));
     if(pSRB->SRBFlag & AUTO_REQSENSE)
     {  /* Last command was a Request Sense */
        pSRB->SRBFlag &= ~AUTO_REQSENSE;
@@ -1729,7 +1729,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
            } else {
                SET_RES_DRV(pcmd->result, DRIVER_SENSE);
                //pSRB->ScsiCmdLen       = (u8) (pSRB->Segment1[0] >> 8);
-               DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+               DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
                pSRB->TotalXferredLen = 0;
                SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
            }
@@ -1749,7 +1749,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
        else if (status == SAM_STAT_TASK_SET_FULL)
        {
            scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1);
-           DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+           DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
            pSRB->TotalXferredLen = 0;
            SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
        }
@@ -1803,7 +1803,7 @@ cmd_done:
     /* Add to free list */
     dc390_Free_insert (pACB, pSRB);
 
-    DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid));
+    DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->serial_number));
     pcmd->scsi_done (pcmd);
 
     return;
@@ -1998,7 +1998,7 @@ static int DC390_abort(struct scsi_cmnd *cmd)
        struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata;
 
        scmd_printk(KERN_WARNING, cmd,
-               "DC390: Abort command (pid %li)\n", cmd->pid);
+               "DC390: Abort command (pid %li)\n", cmd->serial_number);
 
        /* abort() is too stupid for already sent commands at the moment. 
         * If it's called we are in trouble anyway, so let's dump some info 
@@ -2006,7 +2006,7 @@ static int DC390_abort(struct scsi_cmnd *cmd)
        dc390_dumpinfo(pACB, pDCB, NULL);
 
        pDCB->DCBFlag |= ABORT_DEV_;
-       printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->pid);
+       printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->serial_number);
 
        return FAILED;
 }
index 9e8232a1f16966efdd87b2257ac6706560b265b1..fc9f51818e8f3fb2b6e4a0d48027250d67a4eeaa 100644 (file)
@@ -1254,7 +1254,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
 
    if (SCpnt->host_scribble)
       panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
-            BN(j), SCpnt->pid, SCpnt);
+            BN(j), SCpnt->serial_number, SCpnt);
 
    /* i is the mailbox number, look for the first free mailbox
       starting from last_cp_used */
@@ -1285,7 +1285,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
 
    if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
                         BN(j), i, SCpnt->device->channel, SCpnt->device->id,
-                        SCpnt->device->lun, SCpnt->pid);
+                        SCpnt->device->lun, SCpnt->serial_number);
 
    cpp->opcode = OP_SCSI;
    cpp->channel = SCpnt->device->channel;
@@ -1312,7 +1312,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
       unmap_dma(i, j);
       SCpnt->host_scribble = NULL;
       scmd_printk(KERN_INFO, SCpnt,
-               "qcomm, pid %ld, adapter busy.\n", SCpnt->pid);
+               "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number);
       return 1;
       }
 
@@ -1333,13 +1333,13 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
 
    if (SCarg->host_scribble == NULL) {
       scmd_printk(KERN_INFO, SCarg, "abort, pid %ld inactive.\n",
-             SCarg->pid);
+             SCarg->serial_number);
       return SUCCESS;
       }
 
    i = *(unsigned int *)SCarg->host_scribble;
    scmd_printk(KERN_INFO, SCarg, "abort, mbox %d, pid %ld.\n",
-              i, SCarg->pid);
+              i, SCarg->serial_number);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -1383,7 +1383,7 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
       SCarg->host_scribble = NULL;
       HD(j)->cp_stat[i] = FREE;
       printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
-             BN(j), i, SCarg->pid);
+             BN(j), i, SCarg->serial_number);
       SCarg->scsi_done(SCarg);
       return SUCCESS;
       }
@@ -1397,12 +1397,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
    struct scsi_cmnd *SCpnt;
 
    j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
-   scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->pid);
+   scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->serial_number);
 
    spin_lock_irq(sh[j]->host_lock);
 
    if (SCarg->host_scribble == NULL)
-      printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+      printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->serial_number);
 
    if (HD(j)->in_reset) {
       printk("%s: reset, exit, already in reset.\n", BN(j));
@@ -1440,13 +1440,13 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
       if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
          HD(j)->cp_stat[i] = ABORTING;
          printk("%s: reset, mbox %d aborting, pid %ld.\n",
-                BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->serial_number);
          }
 
       else {
          HD(j)->cp_stat[i] = IN_RESET;
          printk("%s: reset, mbox %d in reset, pid %ld.\n",
-                BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->serial_number);
          }
 
       if (SCpnt->host_scribble == NULL)
@@ -1495,7 +1495,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
          HD(j)->cp_stat[i] = LOCKED;
 
          printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
-                BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->serial_number);
          }
 
       else if (HD(j)->cp_stat[i] == ABORTING) {
@@ -1508,7 +1508,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
          HD(j)->cp_stat[i] = FREE;
 
          printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
-                BN(j), i, SCpnt->pid);
+                BN(j), i, SCpnt->serial_number);
          }
 
       else
@@ -1522,7 +1522,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
    HD(j)->in_reset = FALSE;
    do_trace = FALSE;
 
-   if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+   if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->serial_number);
    else          printk("%s: reset, exit.\n", BN(j));
 
    spin_unlock_irq(sh[j]->host_lock);
@@ -1639,7 +1639,7 @@ static int reorder(unsigned int j, unsigned long cursec,
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-      ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid;
+      ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->serial_number;
 
       if (!n) continue;
 
@@ -1666,7 +1666,7 @@ static int reorder(unsigned int j, unsigned long cursec,
          printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\
                 " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
                 (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
-                SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
+                SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready,
                 SCpnt->request->sector, SCpnt->request->nr_sectors, cursec,
                 YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
                 YESNO(overlap), cpp->xdir);
@@ -1703,7 +1703,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in
          scmd_printk(KERN_INFO, SCpnt,
                "%s, pid %ld, mbox %d, adapter"
                 " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"),
-                SCpnt->pid, k);
+                SCpnt->serial_number, k);
          HD(j)->cp_stat[k] = ABORTING;
          continue;
          }
@@ -1787,11 +1787,11 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
 
    if (SCpnt->host_scribble == NULL)
       panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
-            SCpnt->pid, SCpnt);
+            SCpnt->serial_number, SCpnt);
 
    if (*(unsigned int *)SCpnt->host_scribble != i)
       panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
-            BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
+            BN(j), i, SCpnt->serial_number, *(unsigned int *)SCpnt->host_scribble);
 
    sync_dma(i, j);
 
@@ -1835,12 +1835,12 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
                (SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
             scmd_printk(KERN_INFO, SCpnt,
                "ihdlr, pid %ld, target_status 0x%x, sense key 0x%x.\n",
-                   SCpnt->pid, spp->target_status,
+                   SCpnt->serial_number, spp->target_status,
                    SCpnt->sense_buffer[2]);
 
          HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0;
 
-         if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
+         if (HD(j)->last_retried_pid == SCpnt->serial_number) HD(j)->retries = 0;
 
          break;
       case ASST:     /* Selection Time Out */
@@ -1877,7 +1877,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
 #endif
 
             HD(j)->retries++;
-            HD(j)->last_retried_pid = SCpnt->pid;
+            HD(j)->last_retried_pid = SCpnt->serial_number;
             }
          else
             status = DID_ERROR << 16;
@@ -1907,7 +1907,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
 #endif
       scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\
              " pid %ld, reg 0x%x, count %d.\n",
-             i, spp->adapter_status, spp->target_status, SCpnt->pid,
+             i, spp->adapter_status, spp->target_status, SCpnt->serial_number,
              reg, HD(j)->iocount);
 
    unmap_dma(i, j);
index b92ff047af381c223333aca9b6ac9a4449ccabd8..0e8e642fd3b031f28dbea5adec68b41e64206474 100644 (file)
@@ -381,7 +381,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
        hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
 
        DB(DB_QUEUE_COMMAND,
-          printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->pid))
+          printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->serial_number))
 
 /* Set up a few fields in the scsi_cmnd structure for our own use:
  *  - host_scribble is the pointer to the next cmd in the input queue
@@ -463,7 +463,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
 
        wd33c93_execute(cmd->device->host);
 
-       DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+       DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number))
 
        spin_unlock_irq(&hostdata->lock);
        return 0;
@@ -686,7 +686,7 @@ wd33c93_execute(struct Scsi_Host *instance)
         */
 
        DB(DB_EXECUTE,
-          printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+          printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number))
 }
 
 static void
@@ -963,7 +963,7 @@ wd33c93_intr(struct Scsi_Host *instance)
        case CSR_XFER_DONE | PHS_COMMAND:
        case CSR_UNEXP | PHS_COMMAND:
        case CSR_SRV_REQ | PHS_COMMAND:
-               DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+               DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))
                    transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR,
                                 hostdata);
                hostdata->state = S_CONNECTED;
@@ -1007,7 +1007,7 @@ wd33c93_intr(struct Scsi_Host *instance)
                switch (msg) {
 
                case COMMAND_COMPLETE:
-                       DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+                       DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))
                            write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
                        hostdata->state = S_PRE_CMP_DISC;
                        break;
@@ -1174,7 +1174,7 @@ wd33c93_intr(struct Scsi_Host *instance)
 
                write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
                if (phs == 0x60) {
-                       DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+                       DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number))
                            cmd->SCp.Message = COMMAND_COMPLETE;
                        lun = read_wd33c93(regs, WD_TARGET_LUN);
                        DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
@@ -1201,7 +1201,7 @@ wd33c93_intr(struct Scsi_Host *instance)
                } else {
                        printk
                            ("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",
-                            asr, sr, phs, cmd->pid);
+                            asr, sr, phs, cmd->serial_number);
                        spin_unlock_irqrestore(&hostdata->lock, flags);
                }
                break;
@@ -1266,7 +1266,7 @@ wd33c93_intr(struct Scsi_Host *instance)
                        spin_unlock_irqrestore(&hostdata->lock, flags);
                        return;
                }
-               DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+               DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number))
                    hostdata->connected = NULL;
                hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
                hostdata->state = S_UNCONNECTED;
@@ -1292,7 +1292,7 @@ wd33c93_intr(struct Scsi_Host *instance)
  */
 
                write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
-               DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+               DB(DB_INTR, printk("DISC-%ld", cmd->serial_number))
                    if (cmd == NULL) {
                        printk(" - Already disconnected! ");
                        hostdata->state = S_UNCONNECTED;
@@ -1491,7 +1491,7 @@ wd33c93_intr(struct Scsi_Host *instance)
                } else
                        hostdata->state = S_CONNECTED;
 
-               DB(DB_INTR, printk("-%ld", cmd->pid))
+               DB(DB_INTR, printk("-%ld", cmd->serial_number))
                    spin_unlock_irqrestore(&hostdata->lock, flags);
                break;
 
@@ -1638,7 +1638,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
                        cmd->result = DID_ABORT << 16;
                        printk
                            ("scsi%d: Abort - removing command %ld from input_Q. ",
-                            instance->host_no, cmd->pid);
+                            instance->host_no, cmd->serial_number);
                        enable_irq(cmd->device->host->irq);
                        cmd->scsi_done(cmd);
                        return SUCCESS;
@@ -1663,7 +1663,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
                unsigned long timeout;
 
                printk("scsi%d: Aborting connected command %ld - ",
-                      instance->host_no, cmd->pid);
+                      instance->host_no, cmd->serial_number);
 
                printk("stopping DMA - ");
                if (hostdata->dma == D_DMA_RUNNING) {
@@ -1730,7 +1730,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
                if (tmp == cmd) {
                        printk
                            ("scsi%d: Abort - command %ld found on disconnected_Q - ",
-                            instance->host_no, cmd->pid);
+                            instance->host_no, cmd->serial_number);
                        printk("Abort SNOOZE. ");
                        enable_irq(cmd->device->host->irq);
                        return FAILED;
@@ -2184,7 +2184,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
                if (hd->connected) {
                        cmd = (struct scsi_cmnd *) hd->connected;
                        sprintf(tbuf, " %ld-%d:%d(%02x)",
-                               cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+                               cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
                        strcat(bp, tbuf);
                }
        }
@@ -2193,7 +2193,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
                cmd = (struct scsi_cmnd *) hd->input_Q;
                while (cmd) {
                        sprintf(tbuf, " %ld-%d:%d(%02x)",
-                               cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+                               cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
                        strcat(bp, tbuf);
                        cmd = (struct scsi_cmnd *) cmd->host_scribble;
                }
@@ -2203,7 +2203,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
                cmd = (struct scsi_cmnd *) hd->disconnected_Q;
                while (cmd) {
                        sprintf(tbuf, " %ld-%d:%d(%02x)",
-                               cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+                               cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
                        strcat(bp, tbuf);
                        cmd = (struct scsi_cmnd *) cmd->host_scribble;
                }
index c822debc2668ef687368443907c9ad2d1bca87f7..ac67394c737319582f808fe779c1e2ef8f7c134e 100644 (file)
@@ -69,7 +69,7 @@ static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
 static int __devinit zorro7xx_init_one(struct zorro_dev *z,
                                       const struct zorro_device_id *ent)
 {
-       struct Scsi_Host * host = NULL;
+       struct Scsi_Host *host;
        struct NCR_700_Host_Parameters *hostdata;
        struct zorro_driver_data *zdd;
        unsigned long board, ioaddr;
@@ -89,14 +89,12 @@ static int __devinit zorro7xx_init_one(struct zorro_dev *z,
                return -EBUSY;
        }
 
-       hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
-       if (hostdata == NULL) {
+       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+       if (!hostdata) {
                printk(KERN_ERR "zorro7xx: Failed to allocate host data\n");
                goto out_release;
        }
 
-       memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
-
        /* Fill in the required pieces of hostdata */
        if (ioaddr > 0x01000000)
                hostdata->base = ioremap(ioaddr, zorro_resource_len(z));
index 035cca0281995cfc12660bb4e47e24434560bcbc..ec36ad78d2fe042aafa149eac1ed3a65d3ace527 100644 (file)
@@ -756,8 +756,8 @@ mpc52xx_console_setup(struct console *co, char *options)
        if (port->membase == NULL)
                return -EINVAL;
 
-       pr_debug("mpc52xx-psc uart at %lx, mapped to %p, irq=%x, freq=%i\n",
-                port->mapbase, port->membase, port->irq, port->uartclk);
+       pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
+                (void*)port->mapbase, port->membase, port->irq, port->uartclk);
 
        /* Setup the port parameters accoding to options */
        if (options)
@@ -974,8 +974,8 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
        port->mapbase = res.start;
        port->irq = irq_of_parse_and_map(op->node, 0);
 
-       dev_dbg(&op->dev, "mpc52xx-psc uart at %lx, irq=%x, freq=%i\n",
-               port->mapbase, port->irq, port->uartclk);
+       dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
+               (void*)port->mapbase, port->irq, port->uartclk);
 
        if ((port->irq==NO_IRQ) || !port->mapbase) {
                printk(KERN_ERR "Could not allocate resources for PSC\n");
index 053fca41b08a325f48b0575795309c3c217a00b5..73440e26834beb8d09cd6b07edb0dd1e8b73208a 100644 (file)
@@ -4,6 +4,7 @@
  * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
  *
  *  Copyright (C) 2002 - 2006  Paul Mundt
+ *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
  *
  * based off of the old drivers/char/sh-sci.c by:
  *
@@ -301,6 +302,38 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
        }
        sci_out(port, SCFCR, fcr_val);
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+       unsigned int fcr_val = 0;
+       unsigned short data;
+
+       if (cflag & CRTSCTS) {
+               /* enable RTS/CTS */
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
+                       data = ctrl_inw(PORT_PTCR);
+                       ctrl_outw((data & 0xfc03), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 9-2 */
+                       data = ctrl_inw(PORT_PVCR);
+                       ctrl_outw((data & 0xfc03), PORT_PVCR);
+               }
+               fcr_val |= SCFCR_MCE;
+       } else {
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 5-2; enable only tx and rx  */
+                       data = ctrl_inw(PORT_PTCR);
+                       ctrl_outw((data & 0xffc3), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 5-2 */
+                       data = ctrl_inw(PORT_PVCR);
+                       ctrl_outw((data & 0xffc3), PORT_PVCR);
+               }
+       }
+       sci_out(port, SCFCR, fcr_val);
+}
+
 #elif defined(CONFIG_CPU_SH3)
 /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
 static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
@@ -1276,7 +1309,7 @@ static int __init sci_console_init(void)
 console_initcall(sci_console_init);
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
-#ifdef CONFIG_SH_KGDB
+#ifdef CONFIG_SH_KGDB_CONSOLE
 /*
  * FIXME: Most of this can go away.. at the moment, we rely on
  * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though
@@ -1334,9 +1367,7 @@ int __init kgdb_console_setup(struct console *co, char *options)
 
        return uart_set_options(port, co, baud, parity, bits, flow);
 }
-#endif /* CONFIG_SH_KGDB */
 
-#ifdef CONFIG_SH_KGDB_CONSOLE
 static struct console kgdb_console = {
        .name           = "ttySC",
        .device         = uart_console_device,
@@ -1432,7 +1463,7 @@ static int __devinit sci_probe(struct platform_device *dev)
 
 #ifdef CONFIG_CPU_FREQ
        cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
-       dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
+       dev_info(&dev->dev, "CPU frequency notifier registered\n");
 #endif
 
 #ifdef CONFIG_SH_STANDARD_BIOS
index cf75466ebf57eb19835f89d99788605a9d5b397f..e89ae29645d61d554b5ff67b698a7ece50659129 100644 (file)
  *  Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003).
  *  Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
  *  Removed SH7300 support (Jul 2007).
+ *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Aug 2007).
  */
 #include <linux/serial_core.h>
 #include <asm/io.h>
 
-#if defined(__H8300H__) || defined(__H8300S__)
 #include <asm/gpio.h>
+
 #if defined(CONFIG_H83007) || defined(CONFIG_H83068)
 #include <asm/regs306x.h>
 #endif
 #if defined(CONFIG_H8S2678)
 #include <asm/regs267x.h>
 #endif
-#endif
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
     defined(CONFIG_CPU_SUBTYPE_SH7707) || \
  */
 # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
 # define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+# define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCIF_ONLY
+#define SCIF_ORER    0x0200   /* overrun error bit */
 #elif defined(CONFIG_SH_RTS7751R2D)
 # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
 # define SCIF_ORER 0x0001   /* overrun error bit */
 #define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
 #define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720)
 #define SCIF_ORER    0x0200
 #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
 #define SCIF_RFDC_MASK 0x007f
 # define SCxSR_FER(port)               SCIF_FER
 # define SCxSR_PER(port)               SCIF_PER
 # define SCxSR_BRK(port)               SCIF_BRK
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720)
 # define SCxSR_RDxF_CLEAR(port)         (sci_in(port,SCxSR)&0xfffc)
 # define SCxSR_ERROR_CLEAR(port)        (sci_in(port,SCxSR)&0xfd73)
 # define SCxSR_TDxE_CLEAR(port)         (sci_in(port,SCxSR)&0xffdf)
   CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
 #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
          CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7720)
 #define SCIF_FNS(name, scif_offset, scif_size) \
   CPU_SCIF_FNS(name, scif_offset, scif_size)
 #else
   CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720)
 
 SCIF_FNS(SCSMR,  0x00, 16)
 SCIF_FNS(SCBRR,  0x04,  8)
@@ -510,7 +518,15 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port)
                return;
        }
 }
-
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xa4430000)
+               return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
+       else if (port->mapbase == 0xa4438000)
+               return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
+       return 1;
+}
 #elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
       defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
       defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
@@ -653,6 +669,7 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
        if (port->mapbase == 0xffc60000)
                return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+       return 1;
 }
 #endif
 
@@ -691,7 +708,8 @@ static inline int sci_rxd_in(struct uart_port *port)
 #if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
     defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7720)
 #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
 #elif defined(__H8300H__) || defined(__H8300S__)
 #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
index 8a143894e33f6cfdefa887c8436a032fabb7735b..a96f4a8cfeb8b1eec01b6e61d304bb6f441768fb 100644 (file)
@@ -2,5 +2,5 @@
 # Makefile for the SuperH specific drivers.
 #
 
-obj-$(CONFIG_SUPERHYWAY) += superhyway/
-
+obj-$(CONFIG_SUPERHYWAY)       += superhyway/
+obj-$(CONFIG_MAPLE)            += maple/
diff --git a/drivers/sh/maple/Makefile b/drivers/sh/maple/Makefile
new file mode 100644 (file)
index 0000000..65dfeeb
--- /dev/null
@@ -0,0 +1,3 @@
+# Makefile for Maple Bus
+
+obj-$(CONFIG_MAPLE) := maple.o
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
new file mode 100644 (file)
index 0000000..161d102
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+ * Core maple bus functionality
+ *
+ *  Copyright (C) 2007 Adrian McMenamin
+ *
+ * Based on 2.4 code by:
+ *
+ *  Copyright (C) 2000-2001 YAEGASHI Takeshi
+ *  Copyright (C) 2001 M. R. Brown
+ *  Copyright (C) 2001 Paul Mundt
+ *
+ * and others.
+ *
+ * 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 more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/maple.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/mach/dma.h>
+#include <asm/mach/sysasic.h>
+#include <asm/mach/maple.h>
+
+MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin");
+MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");
+
+static void maple_dma_handler(struct work_struct *work);
+static void maple_vblank_handler(struct work_struct *work);
+
+static DECLARE_WORK(maple_dma_process, maple_dma_handler);
+static DECLARE_WORK(maple_vblank_process, maple_vblank_handler);
+
+static LIST_HEAD(maple_waitq);
+static LIST_HEAD(maple_sentq);
+
+static DEFINE_MUTEX(maple_list_lock);
+
+static struct maple_driver maple_dummy_driver;
+static struct device maple_bus;
+static int subdevice_map[MAPLE_PORTS];
+static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
+static unsigned long maple_pnp_time;
+static int started, scanning, liststatus;
+static struct kmem_cache *maple_queue_cache;
+
+struct maple_device_specify {
+       int port;
+       int unit;
+};
+
+/**
+ *  maple_driver_register - register a device driver
+ *  automatically makes the driver bus a maple bus
+ *  @drv: the driver to be registered
+ */
+int maple_driver_register(struct device_driver *drv)
+{
+       if (!drv)
+               return -EINVAL;
+       drv->bus = &maple_bus_type;
+       return driver_register(drv);
+}
+EXPORT_SYMBOL_GPL(maple_driver_register);
+
+/* set hardware registers to enable next round of dma */
+static void maplebus_dma_reset(void)
+{
+       ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);
+       /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */
+       ctrl_outl(1, MAPLE_TRIGTYPE);
+       ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED);
+       ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
+       ctrl_outl(1, MAPLE_ENABLE);
+}
+
+/**
+ * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND
+ * @dev: device responding
+ * @callback: handler callback
+ * @interval: interval in jiffies between callbacks
+ * @function: the function code for the device
+ */
+void maple_getcond_callback(struct maple_device *dev,
+                           void (*callback) (struct mapleq * mq),
+                           unsigned long interval, unsigned long function)
+{
+       dev->callback = callback;
+       dev->interval = interval;
+       dev->function = cpu_to_be32(function);
+       dev->when = jiffies;
+}
+EXPORT_SYMBOL_GPL(maple_getcond_callback);
+
+static int maple_dma_done(void)
+{
+       return (ctrl_inl(MAPLE_STATE) & 1) == 0;
+}
+
+static void maple_release_device(struct device *dev)
+{
+       if (dev->type) {
+               kfree(dev->type->name);
+               kfree(dev->type);
+       }
+}
+
+/**
+ * maple_add_packet - add a single instruction to the queue
+ * @mq: instruction to add to waiting queue
+ */
+void maple_add_packet(struct mapleq *mq)
+{
+       mutex_lock(&maple_list_lock);
+       list_add(&mq->list, &maple_waitq);
+       mutex_unlock(&maple_list_lock);
+}
+EXPORT_SYMBOL_GPL(maple_add_packet);
+
+static struct mapleq *maple_allocq(struct maple_device *dev)
+{
+       struct mapleq *mq;
+
+       mq = kmalloc(sizeof(*mq), GFP_KERNEL);
+       if (!mq)
+               return NULL;
+
+       mq->dev = dev;
+       mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
+       mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp);
+       if (!mq->recvbuf) {
+               kfree(mq);
+               return NULL;
+       }
+
+       return mq;
+}
+
+static struct maple_device *maple_alloc_dev(int port, int unit)
+{
+       struct maple_device *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       dev->port = port;
+       dev->unit = unit;
+       dev->mq = maple_allocq(dev);
+
+       if (!dev->mq) {
+               kfree(dev);
+               return NULL;
+       }
+
+       return dev;
+}
+
+static void maple_free_dev(struct maple_device *mdev)
+{
+       if (!mdev)
+               return;
+       if (mdev->mq) {
+               kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp);
+               kfree(mdev->mq);
+       }
+       kfree(mdev);
+}
+
+/* process the command queue into a maple command block
+ * terminating command has bit 32 of first long set to 0
+ */
+static void maple_build_block(struct mapleq *mq)
+{
+       int port, unit, from, to, len;
+       unsigned long *lsendbuf = mq->sendbuf;
+
+       port = mq->dev->port & 3;
+       unit = mq->dev->unit;
+       len = mq->length;
+       from = port << 6;
+       to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20);
+
+       *maple_lastptr &= 0x7fffffff;
+       maple_lastptr = maple_sendptr;
+
+       *maple_sendptr++ = (port << 16) | len | 0x80000000;
+       *maple_sendptr++ = PHYSADDR(mq->recvbuf);
+       *maple_sendptr++ =
+           mq->command | (to << 8) | (from << 16) | (len << 24);
+
+       while (len-- > 0)
+               *maple_sendptr++ = *lsendbuf++;
+}
+
+/* build up command queue */
+static void maple_send(void)
+{
+       int i;
+       int maple_packets;
+       struct mapleq *mq, *nmq;
+
+       if (!list_empty(&maple_sentq))
+               return;
+       if (list_empty(&maple_waitq) || !maple_dma_done())
+               return;
+       maple_packets = 0;
+       maple_sendptr = maple_lastptr = maple_sendbuf;
+       list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {
+               maple_build_block(mq);
+               list_move(&mq->list, &maple_sentq);
+               if (maple_packets++ > MAPLE_MAXPACKETS)
+                       break;
+       }
+       if (maple_packets > 0) {
+               for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++)
+                       dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,
+                                      PAGE_SIZE, DMA_BIDIRECTIONAL);
+       }
+}
+
+static int attach_matching_maple_driver(struct device_driver *driver,
+                                       void *devptr)
+{
+       struct maple_driver *maple_drv;
+       struct maple_device *mdev;
+
+       mdev = devptr;
+       maple_drv = to_maple_driver(driver);
+       if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) {
+               if (maple_drv->connect(mdev) == 0) {
+                       mdev->driver = maple_drv;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static void maple_detach_driver(struct maple_device *mdev)
+{
+       if (!mdev)
+               return;
+       if (mdev->driver) {
+               if (mdev->driver->disconnect)
+                       mdev->driver->disconnect(mdev);
+       }
+       mdev->driver = NULL;
+       if (mdev->registered) {
+               maple_release_device(&mdev->dev);
+               device_unregister(&mdev->dev);
+       }
+       mdev->registered = 0;
+       maple_free_dev(mdev);
+}
+
+/* process initial MAPLE_COMMAND_DEVINFO for each device or port */
+static void maple_attach_driver(struct maple_device *dev)
+{
+       char *p;
+
+       char *recvbuf;
+       unsigned long function;
+       int matched, retval;
+
+       recvbuf = dev->mq->recvbuf;
+       memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo));
+       memcpy(dev->product_name, dev->devinfo.product_name, 30);
+       memcpy(dev->product_licence, dev->devinfo.product_licence, 60);
+       dev->product_name[30] = '\0';
+       dev->product_licence[60] = '\0';
+
+       for (p = dev->product_name + 29; dev->product_name <= p; p--)
+               if (*p == ' ')
+                       *p = '\0';
+               else
+                       break;
+
+       for (p = dev->product_licence + 59; dev->product_licence <= p; p--)
+               if (*p == ' ')
+                       *p = '\0';
+               else
+                       break;
+
+       function = be32_to_cpu(dev->devinfo.function);
+
+       if (function > 0x200) {
+               /* Do this silently - as not a real device */
+               function = 0;
+               dev->driver = &maple_dummy_driver;
+               sprintf(dev->dev.bus_id, "%d:0.port", dev->port);
+       } else {
+               printk(KERN_INFO
+                      "Maple bus at (%d, %d): Connected function 0x%lX\n",
+                      dev->port, dev->unit, function);
+
+               matched =
+                   bus_for_each_drv(&maple_bus_type, NULL, dev,
+                                    attach_matching_maple_driver);
+
+               if (matched == 0) {
+                       /* Driver does not exist yet */
+                       printk(KERN_INFO
+                              "No maple driver found for this device\n");
+                       dev->driver = &maple_dummy_driver;
+               }
+
+               sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port,
+                       dev->unit, function);
+       }
+       dev->function = function;
+       dev->dev.bus = &maple_bus_type;
+       dev->dev.parent = &maple_bus;
+       dev->dev.release = &maple_release_device;
+       retval = device_register(&dev->dev);
+       if (retval) {
+               printk(KERN_INFO
+                      "Maple bus: Attempt to register device (%x, %x) failed.\n",
+                      dev->port, dev->unit);
+               maple_free_dev(dev);
+       }
+       dev->registered = 1;
+}
+
+/*
+ * if device has been registered for the given
+ * port and unit then return 1 - allows identification
+ * of which devices need to be attached or detached
+ */
+static int detach_maple_device(struct device *device, void *portptr)
+{
+       struct maple_device_specify *ds;
+       struct maple_device *mdev;
+
+       ds = portptr;
+       mdev = to_maple_dev(device);
+       if (mdev->port == ds->port && mdev->unit == ds->unit)
+               return 1;
+       return 0;
+}
+
+static int setup_maple_commands(struct device *device, void *ignored)
+{
+       struct maple_device *maple_dev = to_maple_dev(device);
+
+       if ((maple_dev->interval > 0)
+           && time_after(jiffies, maple_dev->when)) {
+               maple_dev->when = jiffies + maple_dev->interval;
+               maple_dev->mq->command = MAPLE_COMMAND_GETCOND;
+               maple_dev->mq->sendbuf = &maple_dev->function;
+               maple_dev->mq->length = 1;
+               maple_add_packet(maple_dev->mq);
+               liststatus++;
+       } else {
+               if (time_after(jiffies, maple_pnp_time)) {
+                       maple_dev->mq->command = MAPLE_COMMAND_DEVINFO;
+                       maple_dev->mq->length = 0;
+                       maple_add_packet(maple_dev->mq);
+                       liststatus++;
+               }
+       }
+
+       return 0;
+}
+
+/* VBLANK bottom half - implemented via workqueue */
+static void maple_vblank_handler(struct work_struct *work)
+{
+       if (!maple_dma_done())
+               return;
+       if (!list_empty(&maple_sentq))
+               return;
+       ctrl_outl(0, MAPLE_ENABLE);
+       liststatus = 0;
+       bus_for_each_dev(&maple_bus_type, NULL, NULL,
+                        setup_maple_commands);
+       if (time_after(jiffies, maple_pnp_time))
+               maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL;
+       if (liststatus && list_empty(&maple_sentq)) {
+               INIT_LIST_HEAD(&maple_sentq);
+               maple_send();
+       }
+       maplebus_dma_reset();
+}
+
+/* handle devices added via hotplugs - placing them on queue for DEVINFO*/
+static void maple_map_subunits(struct maple_device *mdev, int submask)
+{
+       int retval, k, devcheck;
+       struct maple_device *mdev_add;
+       struct maple_device_specify ds;
+
+       for (k = 0; k < 5; k++) {
+               ds.port = mdev->port;
+               ds.unit = k + 1;
+               retval =
+                   bus_for_each_dev(&maple_bus_type, NULL, &ds,
+                                    detach_maple_device);
+               if (retval) {
+                       submask = submask >> 1;
+                       continue;
+               }
+               devcheck = submask & 0x01;
+               if (devcheck) {
+                       mdev_add = maple_alloc_dev(mdev->port, k + 1);
+                       if (!mdev_add)
+                               return;
+                       mdev_add->mq->command = MAPLE_COMMAND_DEVINFO;
+                       mdev_add->mq->length = 0;
+                       maple_add_packet(mdev_add->mq);
+                       scanning = 1;
+               }
+               submask = submask >> 1;
+       }
+}
+
+/* mark a device as removed */
+static void maple_clean_submap(struct maple_device *mdev)
+{
+       int killbit;
+
+       killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20);
+       killbit = ~killbit;
+       killbit &= 0xFF;
+       subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit;
+}
+
+/* handle empty port or hotplug removal */
+static void maple_response_none(struct maple_device *mdev,
+                               struct mapleq *mq)
+{
+       if (mdev->unit != 0) {
+               list_del(&mq->list);
+               maple_clean_submap(mdev);
+               printk(KERN_INFO
+                      "Maple bus device detaching at (%d, %d)\n",
+                      mdev->port, mdev->unit);
+               maple_detach_driver(mdev);
+               return;
+       }
+       if (!started) {
+               printk(KERN_INFO "No maple devices attached to port %d\n",
+                      mdev->port);
+               return;
+       }
+       maple_clean_submap(mdev);
+}
+
+/* preprocess hotplugs or scans */
+static void maple_response_devinfo(struct maple_device *mdev,
+                                  char *recvbuf)
+{
+       char submask;
+       if ((!started) || (scanning == 2)) {
+               maple_attach_driver(mdev);
+               return;
+       }
+       if (mdev->unit == 0) {
+               submask = recvbuf[2] & 0x1F;
+               if (submask ^ subdevice_map[mdev->port]) {
+                       maple_map_subunits(mdev, submask);
+                       subdevice_map[mdev->port] = submask;
+               }
+       }
+}
+
+/* maple dma end bottom half - implemented via workqueue */
+static void maple_dma_handler(struct work_struct *work)
+{
+       struct mapleq *mq, *nmq;
+       struct maple_device *dev;
+       char *recvbuf;
+       enum maple_code code;
+
+       if (!maple_dma_done())
+               return;
+       ctrl_outl(0, MAPLE_ENABLE);
+       if (!list_empty(&maple_sentq)) {
+               list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {
+                       recvbuf = mq->recvbuf;
+                       code = recvbuf[0];
+                       dev = mq->dev;
+                       switch (code) {
+                       case MAPLE_RESPONSE_NONE:
+                               maple_response_none(dev, mq);
+                               break;
+
+                       case MAPLE_RESPONSE_DEVINFO:
+                               maple_response_devinfo(dev, recvbuf);
+                               break;
+
+                       case MAPLE_RESPONSE_DATATRF:
+                               if (dev->callback)
+                                       dev->callback(mq);
+                               break;
+
+                       case MAPLE_RESPONSE_FILEERR:
+                       case MAPLE_RESPONSE_AGAIN:
+                       case MAPLE_RESPONSE_BADCMD:
+                       case MAPLE_RESPONSE_BADFUNC:
+                               printk(KERN_DEBUG
+                                      "Maple non-fatal error 0x%X\n",
+                                      code);
+                               break;
+
+                       case MAPLE_RESPONSE_ALLINFO:
+                               printk(KERN_DEBUG
+                                      "Maple - extended device information not supported\n");
+                               break;
+
+                       case MAPLE_RESPONSE_OK:
+                               break;
+
+                       default:
+                               break;
+                       }
+               }
+               INIT_LIST_HEAD(&maple_sentq);
+               if (scanning == 1) {
+                       maple_send();
+                       scanning = 2;
+               } else
+                       scanning = 0;
+
+               if (started == 0)
+                       started = 1;
+       }
+       maplebus_dma_reset();
+}
+
+static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id)
+{
+       /* Load everything into the bottom half */
+       schedule_work(&maple_dma_process);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id)
+{
+       schedule_work(&maple_vblank_process);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction maple_dma_irq = {
+       .name = "maple bus DMA handler",
+       .handler = maplebus_dma_interrupt,
+       .flags = IRQF_SHARED,
+};
+
+static struct irqaction maple_vblank_irq = {
+       .name = "maple bus VBLANK handler",
+       .handler = maplebus_vblank_interrupt,
+       .flags = IRQF_SHARED,
+};
+
+static int maple_set_dma_interrupt_handler(void)
+{
+       return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq);
+}
+
+static int maple_set_vblank_interrupt_handler(void)
+{
+       return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq);
+}
+
+static int maple_get_dma_buffer(void)
+{
+       maple_sendbuf =
+           (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+                                     MAPLE_DMA_PAGES);
+       if (!maple_sendbuf)
+               return -ENOMEM;
+       return 0;
+}
+
+static int match_maple_bus_driver(struct device *devptr,
+                                 struct device_driver *drvptr)
+{
+       struct maple_driver *maple_drv;
+       struct maple_device *maple_dev;
+
+       maple_drv = container_of(drvptr, struct maple_driver, drv);
+       maple_dev = container_of(devptr, struct maple_device, dev);
+       /* Trap empty port case */
+       if (maple_dev->devinfo.function == 0xFFFFFFFF)
+               return 0;
+       else if (maple_dev->devinfo.function &
+                be32_to_cpu(maple_drv->function))
+               return 1;
+       return 0;
+}
+
+static int maple_bus_uevent(struct device *dev, char **envp,
+                           int num_envp, char *buffer, int buffer_size)
+{
+       return 0;
+}
+
+static void maple_bus_release(struct device *dev)
+{
+}
+
+static struct maple_driver maple_dummy_driver = {
+       .drv = {
+               .name = "maple_dummy_driver",
+               .bus =  &maple_bus_type,
+       },
+};
+
+struct bus_type maple_bus_type = {
+       .name =         "maple",
+       .match =        match_maple_bus_driver,
+       .uevent =       maple_bus_uevent,
+};
+EXPORT_SYMBOL_GPL(maple_bus_type);
+
+static struct device maple_bus = {
+       .bus_id = "maple",
+       .release = maple_bus_release,
+};
+
+static int __init maple_bus_init(void)
+{
+       int retval, i;
+       struct maple_device *mdev[MAPLE_PORTS];
+       ctrl_outl(0, MAPLE_STATE);
+
+       retval = device_register(&maple_bus);
+       if (retval)
+               goto cleanup;
+
+       retval = bus_register(&maple_bus_type);
+       if (retval)
+               goto cleanup_device;
+
+       retval = driver_register(&maple_dummy_driver.drv);
+
+       if (retval)
+               goto cleanup_bus;
+
+       /* allocate memory for maple bus dma */
+       retval = maple_get_dma_buffer();
+       if (retval) {
+               printk(KERN_INFO
+                      "Maple bus: Failed to allocate Maple DMA buffers\n");
+               goto cleanup_basic;
+       }
+
+       /* set up DMA interrupt handler */
+       retval = maple_set_dma_interrupt_handler();
+       if (retval) {
+               printk(KERN_INFO
+                      "Maple bus: Failed to grab maple DMA IRQ\n");
+               goto cleanup_dma;
+       }
+
+       /* set up VBLANK interrupt handler */
+       retval = maple_set_vblank_interrupt_handler();
+       if (retval) {
+               printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n");
+               goto cleanup_irq;
+       }
+
+       maple_queue_cache =
+           kmem_cache_create("maple_queue_cache", 0x400, 0,
+                             SLAB_HWCACHE_ALIGN, NULL);
+
+       if (!maple_queue_cache)
+               goto cleanup_bothirqs;
+
+       /* setup maple ports */
+       for (i = 0; i < MAPLE_PORTS; i++) {
+               mdev[i] = maple_alloc_dev(i, 0);
+               if (!mdev[i]) {
+                       while (i-- > 0)
+                               maple_free_dev(mdev[i]);
+                       goto cleanup_cache;
+               }
+               mdev[i]->registered = 0;
+               mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO;
+               mdev[i]->mq->length = 0;
+               maple_attach_driver(mdev[i]);
+               maple_add_packet(mdev[i]->mq);
+               subdevice_map[i] = 0;
+       }
+
+       /* setup maplebus hardware */
+       maplebus_dma_reset();
+
+       /* initial detection */
+       maple_send();
+
+       maple_pnp_time = jiffies;
+
+       printk(KERN_INFO "Maple bus core now registered.\n");
+
+       return 0;
+
+cleanup_cache:
+       kmem_cache_destroy(maple_queue_cache);
+
+cleanup_bothirqs:
+       free_irq(HW_EVENT_VSYNC, 0);
+
+cleanup_irq:
+       free_irq(HW_EVENT_MAPLE_DMA, 0);
+
+cleanup_dma:
+       free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);
+
+cleanup_basic:
+       driver_unregister(&maple_dummy_driver.drv);
+
+cleanup_bus:
+       bus_unregister(&maple_bus_type);
+
+cleanup_device:
+       device_unregister(&maple_bus);
+
+cleanup:
+       printk(KERN_INFO "Maple bus registration failed\n");
+       return retval;
+}
+subsys_initcall(maple_bus_init);
index 74d5182db4b2b5fb2ea970b97777364e60984bec..c12a741b5574d21681d5ff5f2c89014675dff010 100644 (file)
@@ -11,6 +11,7 @@
 #include "ssb_private.h"
 
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/ssb/ssb.h>
 #include <linux/ssb/ssb_regs.h>
 #include <linux/dma-mapping.h>
@@ -320,23 +321,17 @@ static int ssb_bus_match(struct device *dev, struct device_driver *drv)
        return 0;
 }
 
-static int ssb_device_uevent(struct device *dev, char **envp, int num_envp,
-                            char *buffer, int buffer_size)
+static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
-       int ret, i = 0, length = 0;
 
        if (!dev)
                return -ENODEV;
 
-       ret = add_uevent_var(envp, num_envp, &i,
-                            buffer, buffer_size, &length,
+       return add_uevent_var(env,
                             "MODALIAS=ssb:v%04Xid%04Xrev%02X",
                             ssb_dev->id.vendor, ssb_dev->id.coreid,
                             ssb_dev->id.revision);
-       envp[i] = NULL;
-
-       return ret;
 }
 
 static struct bus_type ssb_bustype = {
index 7c773603b4025f41eacba761bc08484b60a470dd..b6abee846f023a81af3a4ecf3fb015ac642a5e53 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/ssb/ssb.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
index 8b132c4a503b61f7355d680c9c3b2aa0e012ec55..7d27c9cf3c43fee169f2c0deedb5eec1742687f1 100644 (file)
@@ -88,7 +88,7 @@ static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = {
 static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL;
 static unsigned char ModemMode = DEFAULT_MODEM_MODE;
 static unsigned char ModemOption[MODEM_OPTION_LENGTH];
-static int num_ModemOption;
+static unsigned int num_ModemOption;
 
 module_param(altsetting, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(altsetting,
index 70125c6d3be49d12fa9ae47947b65ab2cadcae0f..8472543eee81d4f117103836d6636b25abbc98e0 100644 (file)
@@ -29,7 +29,7 @@
 
 #define XUSBATM_PARM(name, type, parmtype, desc) \
        static type name[XUSBATM_DRIVERS_MAX]; \
-       static int num_##name; \
+       static unsigned int num_##name; \
        module_param_array(name, parmtype, &num_##name, 0444); \
        MODULE_PARM_DESC(name, desc)
 
index bc3e785d8c00838f91cdfdcf73dc6d487540edf0..fe70e72340de4e0735d40f67279a5d4ebcb6ce08 100644 (file)
@@ -117,8 +117,10 @@ static const struct hc_driver ssb_ohci_hc_driver = {
        .hub_status_data        = ohci_hub_status_data,
        .hub_control            = ohci_hub_control,
        .hub_irq_enable         = ohci_rhsc_enable,
+#ifdef CONFIG_PM
        .bus_suspend            = ohci_bus_suspend,
        .bus_resume             = ohci_bus_resume,
+#endif
 
        .start_port_reset       = ohci_start_port_reset,
 };
index 768b2c11a2311d6efa8237e7868c4c642d8998dc..e7d982a71548d819e08272a93eb9788defa14f48 100644 (file)
@@ -446,7 +446,8 @@ static void mts_data_done( struct urb* transfer )
        MTS_INT_INIT();
 
        if ( context->data_length != transfer->actual_length ) {
-               context->srb->resid = context->data_length - transfer->actual_length;
+               scsi_set_resid(context->srb, context->data_length -
+                              transfer->actual_length);
        } else if ( unlikely(status) ) {
                context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
        }
@@ -490,7 +491,8 @@ static void mts_command_done( struct urb *transfer )
                                           context->data_pipe,
                                           context->data,
                                           context->data_length,
-                                          context->srb->use_sg > 1 ? mts_do_sg : mts_data_done);
+                                          scsi_sg_count(context->srb) > 1 ?
+                                                  mts_do_sg : mts_data_done);
                } else {
                        mts_get_status(transfer);
                }
@@ -505,21 +507,23 @@ static void mts_do_sg (struct urb* transfer)
        int status = transfer->status;
        MTS_INT_INIT();
 
-       MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
+       MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,
+                                                 scsi_sg_count(context->srb));
 
        if (unlikely(status)) {
                 context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
                mts_transfer_cleanup(transfer);
         }
 
-       sg = context->srb->request_buffer;
+       sg = scsi_sglist(context->srb);
        context->fragment++;
        mts_int_submit_urb(transfer,
                           context->data_pipe,
                           page_address(sg[context->fragment].page) +
                           sg[context->fragment].offset,
                           sg[context->fragment].length,
-                          context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg);
+                          context->fragment + 1 == scsi_sg_count(context->srb) ?
+                          mts_data_done : mts_do_sg);
        return;
 }
 
@@ -547,20 +551,12 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
        desc->context.srb = srb;
        desc->context.fragment = 0;
 
-       if (!srb->use_sg) {
-               if ( !srb->request_bufflen ){
-                       desc->context.data = NULL;
-                       desc->context.data_length = 0;
-                       return;
-               } else {
-                       desc->context.data = srb->request_buffer;
-                       desc->context.data_length = srb->request_bufflen;
-                       MTS_DEBUG("length = %d or %d\n",
-                                 srb->request_bufflen, srb->bufflen);
-               }
+       if (!scsi_bufflen(srb)) {
+               desc->context.data = NULL;
+               desc->context.data_length = 0;
+               return;
        } else {
-               MTS_DEBUG("Using scatter/gather\n");
-               sg = srb->request_buffer;
+               sg = scsi_sglist(srb);
                desc->context.data = page_address(sg[0].page) + sg[0].offset;
                desc->context.data_length = sg[0].length;
        }
index f98626ae75fea01a773d379f85b94af4acefea07..1f0149495fb4f218067433a53a07abe8721ace57 100644 (file)
@@ -214,13 +214,13 @@ static int debug;
 static int low_latency = TI_DEFAULT_LOW_LATENCY;
 static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
 static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
-static int vendor_3410_count;
+static unsigned int vendor_3410_count;
 static ushort product_3410[TI_EXTRA_VID_PID_COUNT];
-static int product_3410_count;
+static unsigned int product_3410_count;
 static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];
-static int vendor_5052_count;
+static unsigned int vendor_5052_count;
 static ushort product_5052[TI_EXTRA_VID_PID_COUNT];
-static int product_5052_count;
+static unsigned int product_5052_count;
 
 /* supported devices */
 /* the array dimension is the number of default entries plus */
index 323293a3e61f08936ab16fcbc9820fdcc9056492..c646750ccc3076ddba7d6f9187c04a3d55da809c 100644 (file)
@@ -50,7 +50,7 @@
 #include <linux/slab.h>
 
 #include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
 #include <scsi/scsi_device.h>
 
 #include "usb.h"
@@ -580,25 +580,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
        /* Now, if we need to do the auto-sense, let's do it */
        if (need_auto_sense) {
                int temp_result;
-               void* old_request_buffer;
-               unsigned short old_sg;
-               unsigned old_request_bufflen;
-               unsigned char old_sc_data_direction;
-               unsigned char old_cmd_len;
-               unsigned char old_cmnd[MAX_COMMAND_SIZE];
-               int old_resid;
+               struct scsi_eh_save ses;
 
                US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
 
-               /* save the old command */
-               memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
-               old_cmd_len = srb->cmd_len;
-
-               /* set the command and the LUN */
-               memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
-               srb->cmnd[0] = REQUEST_SENSE;
-               srb->cmnd[1] = old_cmnd[1] & 0xE0;
-               srb->cmnd[4] = 18;
+               scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
 
                /* FIXME: we must do the protocol translation here */
                if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
@@ -606,36 +592,12 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
                else
                        srb->cmd_len = 12;
 
-               /* set the transfer direction */
-               old_sc_data_direction = srb->sc_data_direction;
-               srb->sc_data_direction = DMA_FROM_DEVICE;
-
-               /* use the new buffer we have */
-               old_request_buffer = srb->request_buffer;
-               srb->request_buffer = us->sensebuf;
-
-               /* set the buffer length for transfer */
-               old_request_bufflen = srb->request_bufflen;
-               srb->request_bufflen = US_SENSE_SIZE;
-
-               /* set up for no scatter-gather use */
-               old_sg = srb->use_sg;
-               srb->use_sg = 0;
-
                /* issue the auto-sense command */
-               old_resid = srb->resid;
                srb->resid = 0;
                temp_result = us->transport(us->srb, us);
 
                /* let's clean up right away */
-               memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE);
-               srb->resid = old_resid;
-               srb->request_buffer = old_request_buffer;
-               srb->request_bufflen = old_request_bufflen;
-               srb->use_sg = old_sg;
-               srb->sc_data_direction = old_sc_data_direction;
-               srb->cmd_len = old_cmd_len;
-               memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+               scsi_eh_restore_cmnd(srb, &ses);
 
                if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
                        US_DEBUGP("-- auto-sense aborted\n");
index 0899fccbd5709f203d10ecdd1c5b2b60215606cd..fbea2bd129c73d5eb5f49eacf39f5d5795ef9a3b 100644 (file)
@@ -125,8 +125,8 @@ static int hp680bl_remove(struct platform_device *pdev)
 {
        struct backlight_device *bd = platform_get_drvdata(pdev);
 
-       hp680bl_data.brightness = 0;
-       hp680bl_data.power = 0;
+       bd->props.brightness = 0;
+       bd->props.power = 0;
        hp680bl_send_intensity(bd);
 
        backlight_device_unregister(bd);
index ee9046db9c7da58c4fe110a070a1ab28bb8cd1db..549891d76ef5dba2728d905ff75217b95cf26f70 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 
 #include <asm/io.h>
-#include <asm/prom.h>
 #include <asm/of_device.h>
 #include <asm/fbio.h>
 
@@ -38,6 +37,7 @@ static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
 static int cg6_sync(struct fb_info *);
 static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
 static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 
 /*
  *  Frame buffer operations
@@ -48,7 +48,7 @@ static struct fb_ops cg6_ops = {
        .fb_setcolreg           = cg6_setcolreg,
        .fb_blank               = cg6_blank,
        .fb_fillrect            = cg6_fillrect,
-       .fb_copyarea            = cfb_copyarea,
+       .fb_copyarea            = cg6_copyarea,
        .fb_imageblit           = cg6_imageblit,
        .fb_sync                = cg6_sync,
        .fb_mmap                = cg6_mmap,
@@ -65,41 +65,41 @@ static struct fb_ops cg6_ops = {
  * The FBC could be the frame buffer control
  * The FHC could is the frame buffer hardware control.
  */
-#define CG6_ROM_OFFSET       0x0UL
-#define CG6_BROOKTREE_OFFSET 0x200000UL
-#define CG6_DHC_OFFSET       0x240000UL
-#define CG6_ALT_OFFSET       0x280000UL
-#define CG6_FHC_OFFSET       0x300000UL
-#define CG6_THC_OFFSET       0x301000UL
-#define CG6_FBC_OFFSET       0x700000UL
-#define CG6_TEC_OFFSET       0x701000UL
-#define CG6_RAM_OFFSET       0x800000UL
+#define CG6_ROM_OFFSET                 0x0UL
+#define CG6_BROOKTREE_OFFSET           0x200000UL
+#define CG6_DHC_OFFSET                 0x240000UL
+#define CG6_ALT_OFFSET                 0x280000UL
+#define CG6_FHC_OFFSET                 0x300000UL
+#define CG6_THC_OFFSET                 0x301000UL
+#define CG6_FBC_OFFSET                 0x700000UL
+#define CG6_TEC_OFFSET                 0x701000UL
+#define CG6_RAM_OFFSET                 0x800000UL
 
 /* FHC definitions */
-#define CG6_FHC_FBID_SHIFT           24
-#define CG6_FHC_FBID_MASK            255
-#define CG6_FHC_REV_SHIFT            20
-#define CG6_FHC_REV_MASK             15
-#define CG6_FHC_FROP_DISABLE         (1 << 19)
-#define CG6_FHC_ROW_DISABLE          (1 << 18)
-#define CG6_FHC_SRC_DISABLE          (1 << 17)
-#define CG6_FHC_DST_DISABLE          (1 << 16)
-#define CG6_FHC_RESET                (1 << 15)
-#define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
-#define CG6_FHC_RES_MASK             (3 << 11)
-#define CG6_FHC_1024                 (0 << 11)
-#define CG6_FHC_1152                 (1 << 11)
-#define CG6_FHC_1280                 (2 << 11)
-#define CG6_FHC_1600                 (3 << 11)
-#define CG6_FHC_CPU_MASK             (3 << 9)
-#define CG6_FHC_CPU_SPARC            (0 << 9)
-#define CG6_FHC_CPU_68020            (1 << 9)
-#define CG6_FHC_CPU_386              (2 << 9)
-#define CG6_FHC_TEST                (1 << 8)
-#define CG6_FHC_TEST_X_SHIFT        4
-#define CG6_FHC_TEST_X_MASK         15
-#define CG6_FHC_TEST_Y_SHIFT        0
-#define CG6_FHC_TEST_Y_MASK         15
+#define CG6_FHC_FBID_SHIFT             24
+#define CG6_FHC_FBID_MASK              255
+#define CG6_FHC_REV_SHIFT              20
+#define CG6_FHC_REV_MASK               15
+#define CG6_FHC_FROP_DISABLE           (1 << 19)
+#define CG6_FHC_ROW_DISABLE            (1 << 18)
+#define CG6_FHC_SRC_DISABLE            (1 << 17)
+#define CG6_FHC_DST_DISABLE            (1 << 16)
+#define CG6_FHC_RESET                  (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN          (1 << 13)
+#define CG6_FHC_RES_MASK               (3 << 11)
+#define CG6_FHC_1024                   (0 << 11)
+#define CG6_FHC_1152                   (1 << 11)
+#define CG6_FHC_1280                   (2 << 11)
+#define CG6_FHC_1600                   (3 << 11)
+#define CG6_FHC_CPU_MASK               (3 << 9)
+#define CG6_FHC_CPU_SPARC              (0 << 9)
+#define CG6_FHC_CPU_68020              (1 << 9)
+#define CG6_FHC_CPU_386                        (2 << 9)
+#define CG6_FHC_TEST                   (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT           4
+#define CG6_FHC_TEST_X_MASK            15
+#define CG6_FHC_TEST_Y_SHIFT           0
+#define CG6_FHC_TEST_Y_MASK            15
 
 /* FBC mode definitions */
 #define CG6_FBC_BLIT_IGNORE            0x00000000
@@ -150,17 +150,17 @@ static struct fb_ops cg6_ops = {
 #define CG6_FBC_INDEX_MASK             0x00000030
 
 /* THC definitions */
-#define CG6_THC_MISC_REV_SHIFT       16
-#define CG6_THC_MISC_REV_MASK        15
-#define CG6_THC_MISC_RESET           (1 << 12)
-#define CG6_THC_MISC_VIDEO           (1 << 10)
-#define CG6_THC_MISC_SYNC            (1 << 9)
-#define CG6_THC_MISC_VSYNC           (1 << 8)
-#define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
-#define CG6_THC_MISC_CURS_RES        (1 << 6)
-#define CG6_THC_MISC_INT_ENAB        (1 << 5)
-#define CG6_THC_MISC_INT             (1 << 4)
-#define CG6_THC_MISC_INIT            0x9f
+#define CG6_THC_MISC_REV_SHIFT         16
+#define CG6_THC_MISC_REV_MASK          15
+#define CG6_THC_MISC_RESET             (1 << 12)
+#define CG6_THC_MISC_VIDEO             (1 << 10)
+#define CG6_THC_MISC_SYNC              (1 << 9)
+#define CG6_THC_MISC_VSYNC             (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB         (1 << 7)
+#define CG6_THC_MISC_CURS_RES          (1 << 6)
+#define CG6_THC_MISC_INT_ENAB          (1 << 5)
+#define CG6_THC_MISC_INT               (1 << 4)
+#define CG6_THC_MISC_INIT              0x9f
 
 /* The contents are unknown */
 struct cg6_tec {
@@ -170,25 +170,25 @@ struct cg6_tec {
 };
 
 struct cg6_thc {
-        u32 thc_pad0[512];
-       u32 thc_hs;             /* hsync timing */
-       u32 thc_hsdvs;
-       u32 thc_hd;
-       u32 thc_vs;             /* vsync timing */
-       u32 thc_vd;
-       u32 thc_refresh;
-       u32 thc_misc;
-       u32 thc_pad1[56];
-       u32 thc_cursxy; /* cursor x,y position (16 bits each) */
-       u32 thc_cursmask[32];   /* cursor mask bits */
-       u32 thc_cursbits[32];   /* what to show where mask enabled */
+       u32     thc_pad0[512];
+       u32     thc_hs;         /* hsync timing */
+       u32     thc_hsdvs;
+       u32     thc_hd;
+       u32     thc_vs;         /* vsync timing */
+       u32     thc_vd;
+       u32     thc_refresh;
+       u32     thc_misc;
+       u32     thc_pad1[56];
+       u32     thc_cursxy;     /* cursor x,y position (16 bits each) */
+       u32     thc_cursmask[32];       /* cursor mask bits */
+       u32     thc_cursbits[32];       /* what to show where mask enabled */
 };
 
 struct cg6_fbc {
        u32     xxx0[1];
        u32     mode;
        u32     clip;
-       u32     xxx1[1];            
+       u32     xxx1[1];
        u32     s;
        u32     draw;
        u32     blit;
@@ -243,10 +243,10 @@ struct cg6_fbc {
 };
 
 struct bt_regs {
-       u32 addr;
-       u32 color_map;
-       u32 control;
-       u32 cursor;
+       u32     addr;
+       u32     color_map;
+       u32     control;
+       u32     cursor;
 };
 
 struct cg6_par {
@@ -267,7 +267,7 @@ struct cg6_par {
 
 static int cg6_sync(struct fb_info *info)
 {
-       struct cg6_par *par = (struct cg6_par *) info->par;
+       struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_fbc __iomem *fbc = par->fbc;
        int limit = 10000;
 
@@ -281,24 +281,24 @@ static int cg6_sync(struct fb_info *info)
 }
 
 /**
- *      cg6_fillrect - REQUIRED function. Can use generic routines if 
- *                     non acclerated hardware and packed pixel based.
- *                     Draws a rectangle on the screen.               
+ *     cg6_fillrect -  Draws a rectangle on the screen.
  *
- *      @info: frame buffer structure that represents a single frame buffer
- *      @rect: structure defining the rectagle and operation.
+ *     @info: frame buffer structure that represents a single frame buffer
+ *     @rect: structure defining the rectagle and operation.
  */
 static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
-       struct cg6_par *par = (struct cg6_par *) info->par;
+       struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_fbc __iomem *fbc = par->fbc;
        unsigned long flags;
        s32 val;
 
-       /* XXX doesn't handle ROP_XOR */
+       /* CG6 doesn't handle ROP_XOR */
 
        spin_lock_irqsave(&par->lock, flags);
+
        cg6_sync(info);
+
        sbus_writel(rect->color, &fbc->fg);
        sbus_writel(~(u32)0, &fbc->pixelm);
        sbus_writel(0xea80ff00, &fbc->alu);
@@ -316,16 +316,56 @@ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 }
 
 /**
- *      cg6_imageblit - REQUIRED function. Can use generic routines if
- *                      non acclerated hardware and packed pixel based.
- *                      Copies a image from system memory to the screen. 
+ *     cg6_copyarea - Copies one area of the screen to another area.
+ *
+ *     @info: frame buffer structure that represents a single frame buffer
+ *     @area: Structure providing the data to copy the framebuffer contents
+ *             from one region to another.
+ *
+ *     This drawing operation copies a rectangular area from one area of the
+ *     screen to another area.
+ */
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+       struct cg6_par *par = (struct cg6_par *)info->par;
+       struct cg6_fbc __iomem *fbc = par->fbc;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&par->lock, flags);
+
+       cg6_sync(info);
+
+       sbus_writel(0xff, &fbc->fg);
+       sbus_writel(0x00, &fbc->bg);
+       sbus_writel(~0, &fbc->pixelm);
+       sbus_writel(0xe880cccc, &fbc->alu);
+       sbus_writel(0, &fbc->s);
+       sbus_writel(0, &fbc->clip);
+
+       sbus_writel(area->sy, &fbc->y0);
+       sbus_writel(area->sx, &fbc->x0);
+       sbus_writel(area->sy + area->height - 1, &fbc->y1);
+       sbus_writel(area->sx + area->width - 1, &fbc->x1);
+       sbus_writel(area->dy, &fbc->y2);
+       sbus_writel(area->dx, &fbc->x2);
+       sbus_writel(area->dy + area->height - 1, &fbc->y3);
+       sbus_writel(area->dx + area->width - 1, &fbc->x3);
+       do {
+               i = sbus_readl(&fbc->blit);
+       } while (i < 0 && (i & 0x20000000));
+       spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *     cg6_imageblit - Copies a image from system memory to the screen.
  *
- *      @info: frame buffer structure that represents a single frame buffer
- *      @image: structure defining the image.
+ *     @info: frame buffer structure that represents a single frame buffer
+ *     @image: structure defining the image.
  */
 static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
 {
-       struct cg6_par *par = (struct cg6_par *) info->par;
+       struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_fbc __iomem *fbc = par->fbc;
        const u8 *data = image->data;
        unsigned long flags;
@@ -363,7 +403,7 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
                        sbus_writel(y, &fbc->y0);
                        sbus_writel(x, &fbc->x0);
                        sbus_writel(x + 32 - 1, &fbc->x1);
-                       
+
                        val = ((u32)data[0] << 24) |
                              ((u32)data[1] << 16) |
                              ((u32)data[2] <<  8) |
@@ -404,19 +444,20 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
 }
 
 /**
- *      cg6_setcolreg - Optional function. Sets a color register.
- *      @regno: boolean, 0 copy local, 1 get_user() function
- *      @red: frame buffer colormap structure
- *      @green: The green value which can be up to 16 bits wide
- *      @blue:  The blue value which can be up to 16 bits wide.
- *      @transp: If supported the alpha value which can be up to 16 bits wide.
- *      @info: frame buffer info structure
+ *     cg6_setcolreg - Sets a color register.
+ *
+ *     @regno: boolean, 0 copy local, 1 get_user() function
+ *     @red: frame buffer colormap structure
+ *     @green: The green value which can be up to 16 bits wide
+ *     @blue:  The blue value which can be up to 16 bits wide.
+ *     @transp: If supported the alpha value which can be up to 16 bits wide.
+ *     @info: frame buffer info structure
  */
 static int cg6_setcolreg(unsigned regno,
                         unsigned red, unsigned green, unsigned blue,
                         unsigned transp, struct fb_info *info)
 {
-       struct cg6_par *par = (struct cg6_par *) info->par;
+       struct cg6_par *par = (struct cg6_par *)info->par;
        struct bt_regs __iomem *bt = par->bt;
        unsigned long flags;
 
@@ -440,25 +481,24 @@ static int cg6_setcolreg(unsigned regno,
 }
 
 /**
- *      cg6_blank - Optional function.  Blanks the display.
- *      @blank_mode: the blank mode we want.
- *      @info: frame buffer structure that represents a single frame buffer
+ *     cg6_blank - Blanks the display.
+ *
+ *     @blank_mode: the blank mode we want.
+ *     @info: frame buffer structure that represents a single frame buffer
  */
-static int
-cg6_blank(int blank, struct fb_info *info)
+static int cg6_blank(int blank, struct fb_info *info)
 {
-       struct cg6_par *par = (struct cg6_par *) info->par;
+       struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_thc __iomem *thc = par->thc;
        unsigned long flags;
        u32 val;
 
        spin_lock_irqsave(&par->lock, flags);
+       val = sbus_readl(&thc->thc_misc);
 
        switch (blank) {
        case FB_BLANK_UNBLANK: /* Unblanking */
-               val = sbus_readl(&thc->thc_misc);
                val |= CG6_THC_MISC_VIDEO;
-               sbus_writel(val, &thc->thc_misc);
                par->flags &= ~CG6_FLAG_BLANKED;
                break;
 
@@ -466,13 +506,12 @@ cg6_blank(int blank, struct fb_info *info)
        case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
        case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
        case FB_BLANK_POWERDOWN: /* Poweroff */
-               val = sbus_readl(&thc->thc_misc);
                val &= ~CG6_THC_MISC_VIDEO;
-               sbus_writel(val, &thc->thc_misc);
                par->flags |= CG6_FLAG_BLANKED;
                break;
        }
 
+       sbus_writel(val, &thc->thc_misc);
        spin_unlock_irqrestore(&par->lock, flags);
 
        return 0;
@@ -533,7 +572,7 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
 
 static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct cg6_par *par = (struct cg6_par *) info->par;
+       struct cg6_par *par = (struct cg6_par *)info->par;
 
        return sbusfb_ioctl_helper(cmd, arg, info,
                                   FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
@@ -543,15 +582,14 @@ static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  *  Initialisation
  */
 
-static void
-cg6_init_fix(struct fb_info *info, int linebytes)
+static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
 {
        struct cg6_par *par = (struct cg6_par *)info->par;
        const char *cg6_cpu_name, *cg6_card_name;
        u32 conf;
 
        conf = sbus_readl(par->fhc);
-       switch(conf & CG6_FHC_CPU_MASK) {
+       switch (conf & CG6_FHC_CPU_MASK) {
        case CG6_FHC_CPU_SPARC:
                cg6_cpu_name = "sparc";
                break;
@@ -563,21 +601,19 @@ cg6_init_fix(struct fb_info *info, int linebytes)
                break;
        };
        if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
-               if (par->fbsize <= 0x100000) {
+               if (par->fbsize <= 0x100000)
                        cg6_card_name = "TGX";
-               } else {
+               else
                        cg6_card_name = "TGX+";
-               }
        } else {
-               if (par->fbsize <= 0x100000) {
+               if (par->fbsize <= 0x100000)
                        cg6_card_name = "GX";
-               } else {
+               else
                        cg6_card_name = "GX+";
-               }
        }
 
        sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
-       info->fix.id[sizeof(info->fix.id)-1] = 0;
+       info->fix.id[sizeof(info->fix.id) - 1] = 0;
 
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -588,28 +624,28 @@ cg6_init_fix(struct fb_info *info, int linebytes)
 }
 
 /* Initialize Brooktree DAC */
-static void cg6_bt_init(struct cg6_par *par)
+static void __devinit cg6_bt_init(struct cg6_par *par)
 {
        struct bt_regs __iomem *bt = par->bt;
 
-       sbus_writel(0x04 << 24, &bt->addr);         /* color planes */
+       sbus_writel(0x04 << 24, &bt->addr);      /* color planes */
        sbus_writel(0xff << 24, &bt->control);
        sbus_writel(0x05 << 24, &bt->addr);
        sbus_writel(0x00 << 24, &bt->control);
-       sbus_writel(0x06 << 24, &bt->addr);         /* overlay plane */
+       sbus_writel(0x06 << 24, &bt->addr);      /* overlay plane */
        sbus_writel(0x73 << 24, &bt->control);
        sbus_writel(0x07 << 24, &bt->addr);
        sbus_writel(0x00 << 24, &bt->control);
 }
 
-static void cg6_chip_init(struct fb_info *info)
+static void __devinit cg6_chip_init(struct fb_info *info)
 {
-       struct cg6_par *par = (struct cg6_par *) info->par;
+       struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_tec __iomem *tec = par->tec;
        struct cg6_fbc __iomem *fbc = par->fbc;
        u32 rev, conf, mode;
        int i;
-       
+
        /* Turn off stuff in the Transform Engine. */
        sbus_writel(0, &tec->tec_matrix);
        sbus_writel(0, &tec->tec_clip);
@@ -635,13 +671,13 @@ static void cg6_chip_init(struct fb_info *info)
                i = sbus_readl(&fbc->s);
        } while (i & 0x10000000);
        mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
-                      CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
-                      CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
-                      CG6_FBC_BDISP_MASK);
+                 CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+                 CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+                 CG6_FBC_BDISP_MASK);
        mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
-                     CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
-                     CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
-                     CG6_FBC_BDISP_0);
+                CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+                CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+                CG6_FBC_BDISP_0);
        sbus_writel(mode, &fbc->mode);
 
        sbus_writel(0, &fbc->clip);
@@ -671,7 +707,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
                of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
 }
 
-static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit cg6_probe(struct of_device *op,
+                               const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
        struct fb_info *info;
@@ -705,22 +742,23 @@ static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *
                par->fbsize *= 4;
 
        par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
-                                 4096, "cgsix fbc");
+                               4096, "cgsix fbc");
        par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
-                                 sizeof(struct cg6_tec), "cgsix tec");
+                               sizeof(struct cg6_tec), "cgsix tec");
        par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
-                                 sizeof(struct cg6_thc), "cgsix thc");
+                               sizeof(struct cg6_thc), "cgsix thc");
        par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
-                                sizeof(struct bt_regs), "cgsix dac");
+                               sizeof(struct bt_regs), "cgsix dac");
        par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
-                                 sizeof(u32), "cgsix fhc");
+                               sizeof(u32), "cgsix fhc");
 
        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
-                          FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
+                       FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+                       FBINFO_READS_FAST;
        info->fbops = &cg6_ops;
 
-       info->screen_base =  of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
-                                           par->fbsize, "cgsix ram");
+       info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
+                                       par->fbsize, "cgsix ram");
        if (!par->fbc || !par->tec || !par->thc ||
            !par->bt || !par->fhc || !info->screen_base)
                goto out_unmap_regs;
index 4b520b573911f96d617935a2741898204b46b153..d7e24889650e25e83d3b1ebf82bbb3ccd08bb3ff 100644 (file)
@@ -171,17 +171,17 @@ static struct fb_ops ffb_ops = {
 #define FFB_PPC_CS_VAR         0x000002
 #define FFB_PPC_CS_CONST       0x000003
 
-#define FFB_ROP_NEW                  0x83
-#define FFB_ROP_OLD                  0x85
-#define FFB_ROP_NEW_XOR_OLD          0x86
-
-#define FFB_UCSR_FIFO_MASK     0x00000fff
-#define FFB_UCSR_FB_BUSY       0x01000000
-#define FFB_UCSR_RP_BUSY       0x02000000
-#define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
-#define FFB_UCSR_READ_ERR      0x40000000
-#define FFB_UCSR_FIFO_OVFL     0x80000000
-#define FFB_UCSR_ALL_ERRORS    (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
+#define FFB_ROP_NEW            0x83
+#define FFB_ROP_OLD            0x85
+#define FFB_ROP_NEW_XOR_OLD    0x86
+
+#define FFB_UCSR_FIFO_MASK     0x00000fff
+#define FFB_UCSR_FB_BUSY       0x01000000
+#define FFB_UCSR_RP_BUSY       0x02000000
+#define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+#define FFB_UCSR_READ_ERR      0x40000000
+#define FFB_UCSR_FIFO_OVFL     0x80000000
+#define FFB_UCSR_ALL_ERRORS    (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
 
 struct ffb_fbc {
        /* Next vertex registers */
@@ -197,7 +197,7 @@ struct ffb_fbc {
        u32     ryf;
        u32     rxf;
        u32     xxx3[2];
-       
+
        u32     dmyf;
        u32     dmxf;
        u32     xxx4[2];
@@ -211,13 +211,13 @@ struct ffb_fbc {
        u32     bh;
        u32     bw;
        u32     xxx6[2];
-       
+
        u32     xxx7[32];
-       
+
        /* Setup unit vertex state register */
        u32     suvtx;
        u32     xxx8[63];
-       
+
        /* Control registers */
        u32     ppc;
        u32     wid;
@@ -235,7 +235,7 @@ struct ffb_fbc {
        u32     dcsb;
        u32     dczf;
        u32     dczb;
-       
+
        u32     xxx9;
        u32     blendc;
        u32     blendc1;
@@ -252,7 +252,7 @@ struct ffb_fbc {
        u32     fbcfg1;
        u32     fbcfg2;
        u32     fbcfg3;
-       
+
        u32     ppcfg;
        u32     pick;
        u32     fillmode;
@@ -269,7 +269,7 @@ struct ffb_fbc {
        u32     clip2max;
        u32     clip3min;
        u32     clip3max;
-       
+
        /* New 3dRAM III support regs */
        u32     rawblend2;
        u32     rawpreblend;
@@ -287,7 +287,7 @@ struct ffb_fbc {
        u32     rawcmp;
        u32     rawwac;
        u32     fbramid;
-       
+
        u32     drawop;
        u32     xxx10[2];
        u32     fontlpat;
@@ -302,7 +302,7 @@ struct ffb_fbc {
        u32     stencil;
        u32     stencilctl;
 
-       u32     xxx13[4];       
+       u32     xxx13[4];
        u32     dcss1;
        u32     dcss2;
        u32     dcss3;
@@ -315,17 +315,17 @@ struct ffb_fbc {
        u32     dcd3;
        u32     dcd4;
        u32     xxx15;
-       
+
        u32     pattern[32];
-       
+
        u32     xxx16[256];
-       
+
        u32     devid;
        u32     xxx17[63];
-       
+
        u32     ucsr;
        u32     xxx18[31];
-       
+
        u32     mer;
 };
 
@@ -336,20 +336,20 @@ struct ffb_dac {
        u32     value2;
 };
 
-#define FFB_DAC_UCTRL  0x1001 /* User Control */
-#define  FFB_DAC_UCTRL_MANREV  0x00000f00 /* 4-bit Manufacturing Revision */
-#define  FFB_DAC_UCTRL_MANREV_SHIFT 8
-#define FFB_DAC_TGEN   0x6000 /* Timing Generator */
-#define  FFB_DAC_TGEN_VIDE     0x00000001 /* Video Enable */
-#define FFB_DAC_DID    0x8000 /* Device Identification */
-#define  FFB_DAC_DID_PNUM      0x0ffff000 /* Device Part Number */
-#define  FFB_DAC_DID_PNUM_SHIFT 12
-#define  FFB_DAC_DID_REV       0xf0000000 /* Device Revision */
-#define  FFB_DAC_DID_REV_SHIFT 28
+#define FFB_DAC_UCTRL          0x1001 /* User Control */
+#define FFB_DAC_UCTRL_MANREV   0x00000f00 /* 4-bit Manufacturing Revision */
+#define FFB_DAC_UCTRL_MANREV_SHIFT 8
+#define FFB_DAC_TGEN           0x6000 /* Timing Generator */
+#define FFB_DAC_TGEN_VIDE      0x00000001 /* Video Enable */
+#define FFB_DAC_DID            0x8000 /* Device Identification */
+#define FFB_DAC_DID_PNUM       0x0ffff000 /* Device Part Number */
+#define FFB_DAC_DID_PNUM_SHIFT 12
+#define FFB_DAC_DID_REV                0xf0000000 /* Device Revision */
+#define FFB_DAC_DID_REV_SHIFT  28
 
 #define FFB_DAC_CUR_CTRL       0x100
-#define  FFB_DAC_CUR_CTRL_P0   0x00000001
-#define  FFB_DAC_CUR_CTRL_P1   0x00000002
+#define FFB_DAC_CUR_CTRL_P0    0x00000001
+#define FFB_DAC_CUR_CTRL_P1    0x00000002
 
 struct ffb_par {
        spinlock_t              lock;
@@ -382,7 +382,9 @@ static void FFBFifo(struct ffb_par *par, int n)
 
        if (cache - n < 0) {
                fbc = par->fbc;
-               do {    cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
+               do {
+                       cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK);
+                       cache -= 8;
                } while (cache - n < 0);
        }
        par->fifo_cache = cache - n;
@@ -401,12 +403,12 @@ static void FFBWait(struct ffb_par *par)
                        upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
                }
                udelay(10);
-       } while(--limit > 0);
+       } while (--limit > 0);
 }
 
 static int ffb_sync(struct fb_info *p)
 {
-       struct ffb_par *par = (struct ffb_par *) p->par;
+       struct ffb_par *par = (struct ffb_par *)p->par;
 
        FFBWait(par);
        return 0;
@@ -431,8 +433,8 @@ static void ffb_switch_from_graph(struct ffb_par *par)
        FFBWait(par);
        par->fifo_cache = 0;
        FFBFifo(par, 7);
-       upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
-                  FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
+       upa_writel(FFB_PPC_VCE_DISABLE | FFB_PPC_TBE_OPAQUE |
+                  FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
                   &fbc->ppc);
        upa_writel(0x2000707f, &fbc->fbc);
        upa_writel(par->rop_cache, &fbc->rop);
@@ -455,7 +457,7 @@ static void ffb_switch_from_graph(struct ffb_par *par)
 
 static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-       struct ffb_par *par = (struct ffb_par *) info->par;
+       struct ffb_par *par = (struct ffb_par *)info->par;
 
        /* We just use this to catch switches out of
         * graphics mode.
@@ -468,16 +470,14 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 }
 
 /**
- *      ffb_fillrect - REQUIRED function. Can use generic routines if 
- *                     non acclerated hardware and packed pixel based.
- *                     Draws a rectangle on the screen.               
+ *     ffb_fillrect - Draws a rectangle on the screen.
  *
- *      @info: frame buffer structure that represents a single frame buffer
- *      @rect: structure defining the rectagle and operation.
+ *     @info: frame buffer structure that represents a single frame buffer
+ *     @rect: structure defining the rectagle and operation.
  */
 static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
-       struct ffb_par *par = (struct ffb_par *) info->par;
+       struct ffb_par *par = (struct ffb_par *)info->par;
        struct ffb_fbc __iomem *fbc = par->fbc;
        unsigned long flags;
        u32 fg;
@@ -494,9 +494,9 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
                par->fg_cache = fg;
        }
 
-       ffb_rop(par, (rect->rop == ROP_COPY ?
-                     FFB_ROP_NEW :
-                     FFB_ROP_NEW_XOR_OLD));
+       ffb_rop(par, rect->rop == ROP_COPY ?
+                    FFB_ROP_NEW :
+                    FFB_ROP_NEW_XOR_OLD);
 
        FFBFifo(par, 5);
        upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
@@ -509,18 +509,15 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 }
 
 /**
- *      ffb_copyarea - REQUIRED function. Can use generic routines if
- *                     non acclerated hardware and packed pixel based.
- *                     Copies on area of the screen to another area.
+ *     ffb_copyarea - Copies on area of the screen to another area.
  *
- *      @info: frame buffer structure that represents a single frame buffer
- *      @area: structure defining the source and destination.
+ *     @info: frame buffer structure that represents a single frame buffer
+ *     @area: structure defining the source and destination.
  */
 
-static void
-ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
+static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
-       struct ffb_par *par = (struct ffb_par *) info->par;
+       struct ffb_par *par = (struct ffb_par *)info->par;
        struct ffb_fbc __iomem *fbc = par->fbc;
        unsigned long flags;
 
@@ -547,16 +544,14 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 }
 
 /**
- *      ffb_imageblit - REQUIRED function. Can use generic routines if
- *                      non acclerated hardware and packed pixel based.
- *                      Copies a image from system memory to the screen. 
+ *     ffb_imageblit - Copies a image from system memory to the screen.
  *
- *      @info: frame buffer structure that represents a single frame buffer
- *      @image: structure defining the image.
+ *     @info: frame buffer structure that represents a single frame buffer
+ *     @image: structure defining the image.
  */
 static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
-       struct ffb_par *par = (struct ffb_par *) info->par;
+       struct ffb_par *par = (struct ffb_par *)info->par;
        struct ffb_fbc __iomem *fbc = par->fbc;
        const u8 *data = image->data;
        unsigned long flags;
@@ -644,13 +639,14 @@ static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
 }
 
 /**
- *      ffb_setcolreg - Optional function. Sets a color register.
- *      @regno: boolean, 0 copy local, 1 get_user() function
- *      @red: frame buffer colormap structure
- *      @green: The green value which can be up to 16 bits wide
- *      @blue:  The blue value which can be up to 16 bits wide.
- *      @transp: If supported the alpha value which can be up to 16 bits wide.
- *      @info: frame buffer info structure
+ *     ffb_setcolreg - Sets a color register.
+ *
+ *     @regno: boolean, 0 copy local, 1 get_user() function
+ *     @red: frame buffer colormap structure
+ *     @green: The green value which can be up to 16 bits wide
+ *     @blue:  The blue value which can be up to 16 bits wide.
+ *     @transp: If supported the alpha value which can be up to 16 bits wide.
+ *     @info: frame buffer info structure
  */
 static int ffb_setcolreg(unsigned regno,
                         unsigned red, unsigned green, unsigned blue,
@@ -672,14 +668,13 @@ static int ffb_setcolreg(unsigned regno,
 }
 
 /**
- *      ffb_blank - Optional function.  Blanks the display.
- *      @blank_mode: the blank mode we want.
- *      @info: frame buffer structure that represents a single frame buffer
+ *     ffb_blank - Optional function.  Blanks the display.
+ *     @blank_mode: the blank mode we want.
+ *     @info: frame buffer structure that represents a single frame buffer
  */
-static int
-ffb_blank(int blank, struct fb_info *info)
+static int ffb_blank(int blank, struct fb_info *info)
 {
-       struct ffb_par *par = (struct ffb_par *) info->par;
+       struct ffb_par *par = (struct ffb_par *)info->par;
        struct ffb_dac __iomem *dac = par->dac;
        unsigned long flags;
        u32 val;
@@ -867,7 +862,7 @@ static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 
 static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct ffb_par *par = (struct ffb_par *) info->par;
+       struct ffb_par *par = (struct ffb_par *)info->par;
 
        return sbusfb_ioctl_helper(cmd, arg, info,
                                   FBTYPE_CREATOR, 24, par->fbsize);
@@ -877,8 +872,7 @@ static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  *  Initialisation
  */
 
-static void
-ffb_init_fix(struct fb_info *info)
+static void ffb_init_fix(struct fb_info *info)
 {
        struct ffb_par *par = (struct ffb_par *)info->par;
        const char *ffb_type_name;
@@ -902,7 +896,8 @@ ffb_init_fix(struct fb_info *info)
        info->fix.accel = FB_ACCEL_SUN_CREATOR;
 }
 
-static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit ffb_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
        struct ffb_fbc __iomem *fbc;
index 7d6c29800d14fd64ed6d0c7077308311b0c0f950..06805c9b237b74051f76ab1f30a09e67e8287edf 100644 (file)
@@ -667,6 +667,8 @@ static int pvr2_init_cable(void)
          related */
        if (cable_type == CT_COMPOSITE)
                fb_writel(3 << 8, VOUTC);
+       else if (cable_type == CT_RGB)
+               fb_writel(1 << 9, VOUTC);
        else
                fb_writel(0, VOUTC);
 
@@ -890,7 +892,7 @@ static int __init pvr2fb_dc_init(void)
        pvr2_fix.mmio_start     = 0xa05f8000;   /* registers start here */
        pvr2_fix.mmio_len       = 0x2000;
 
-       if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
+       if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, IRQF_SHARED,
                        "pvr2 VBL handler", fb_info)) {
                return -EBUSY;
        }
index 6ef99b2d13ca6f8a4809d5914cbab6309255b3e3..e38d3b7c3ad7b28e5b63909a83885ff535d17f17 100644 (file)
@@ -84,7 +84,7 @@ static struct xilinxfb_platform_data xilinx_fb_default_pdata = {
        .xres = 640,
        .yres = 480,
        .xvirt = 1024,
-       .yvirt = 480;
+       .yvirt = 480,
 };
 
 /*
index f9eed6d790669e003b71680af254d05c3eab9eee..815d201d86008edec9c2004a4f25886d2988a84f 100644 (file)
@@ -1225,6 +1225,14 @@ config JFFS2_FS_WRITEBUFFER
            - NOR flash with transparent ECC
            - DataFlash
 
+config JFFS2_FS_WBUF_VERIFY
+       bool "Verify JFFS2 write-buffer reads"
+       depends on JFFS2_FS_WRITEBUFFER
+       default n
+       help
+         This causes JFFS2 to read back every page written through the
+         write-buffer, and check for errors.
+
 config JFFS2_SUMMARY
        bool "JFFS2 summary support (EXPERIMENTAL)"
        depends on JFFS2_FS && EXPERIMENTAL
@@ -1295,52 +1303,71 @@ config JFFS2_ZLIB
        select ZLIB_DEFLATE
        depends on JFFS2_FS
        default y
-        help
-          Zlib is designed to be a free, general-purpose, legally unencumbered,
-          lossless data-compression library for use on virtually any computer
-          hardware and operating system. See <http://www.gzip.org/zlib/> for
-          further information.
+       help
+         Zlib is designed to be a free, general-purpose, legally unencumbered,
+         lossless data-compression library for use on virtually any computer
+         hardware and operating system. See <http://www.gzip.org/zlib/> for
+         further information.
+
+         Say 'Y' if unsure.
+
+config JFFS2_LZO
+       bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS
+       select LZO_COMPRESS
+       select LZO_DECOMPRESS
+       depends on JFFS2_FS
+       default n
+       help
+         minilzo-based compression. Generally works better than Zlib.
 
-          Say 'Y' if unsure.
+         This feature was added in July, 2007. Say 'N' if you need
+         compatibility with older bootloaders or kernels.
 
 config JFFS2_RTIME
        bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
        depends on JFFS2_FS
        default y
-        help
-          Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
+       help
+         Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
 
 config JFFS2_RUBIN
        bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS
        depends on JFFS2_FS
        default n
-        help
-          RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
+       help
+         RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
 
 choice
-        prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
-        default JFFS2_CMODE_PRIORITY
-        depends on JFFS2_FS
-        help
-          You can set here the default compression mode of JFFS2 from
-          the available compression modes. Don't touch if unsure.
+       prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
+       default JFFS2_CMODE_PRIORITY
+       depends on JFFS2_FS
+       help
+         You can set here the default compression mode of JFFS2 from
+         the available compression modes. Don't touch if unsure.
 
 config JFFS2_CMODE_NONE
-        bool "no compression"
-        help
-          Uses no compression.
+       bool "no compression"
+       help
+         Uses no compression.
 
 config JFFS2_CMODE_PRIORITY
-        bool "priority"
-        help
-          Tries the compressors in a predefined order and chooses the first
-          successful one.
+       bool "priority"
+       help
+         Tries the compressors in a predefined order and chooses the first
+         successful one.
 
 config JFFS2_CMODE_SIZE
-        bool "size (EXPERIMENTAL)"
-        help
-          Tries all compressors and chooses the one which has the smallest
-          result.
+       bool "size (EXPERIMENTAL)"
+       help
+         Tries all compressors and chooses the one which has the smallest
+         result.
+
+config JFFS2_CMODE_FAVOURLZO
+       bool "Favour LZO"
+       help
+         Tries all compressors and chooses the one which has the smallest
+         result but gives some preference to LZO (which has faster
+         decompression) at the expense of size.
 
 endchoice
 
@@ -1728,6 +1755,14 @@ config SUNRPC
 config SUNRPC_GSS
        tristate
 
+config SUNRPC_XPRT_RDMA
+       tristate "RDMA transport for sunrpc (EXPERIMENTAL)"
+       depends on SUNRPC && INFINIBAND && EXPERIMENTAL
+       default m
+       help
+         Adds a client RPC transport for supporting kernel NFS over RDMA
+         mounts, including Infiniband and iWARP. Experimental.
+
 config SUNRPC_BIND34
        bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
        depends on SUNRPC && EXPERIMENTAL
index 29f5068f819b604b61a8a5b542ff3acbe70cc200..f97de0aeb3b69dcd320668ccbf6bbeb6e9d57932 100644 (file)
@@ -142,6 +142,15 @@ static struct inode *alloc_inode(struct super_block *sb)
                        return NULL;
                }
 
+               spin_lock_init(&inode->i_lock);
+               lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
+
+               mutex_init(&inode->i_mutex);
+               lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
+
+               init_rwsem(&inode->i_alloc_sem);
+               lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
+
                mapping->a_ops = &empty_aops;
                mapping->host = inode;
                mapping->flags = 0;
@@ -190,8 +199,6 @@ void inode_init_once(struct inode *inode)
        INIT_HLIST_NODE(&inode->i_hash);
        INIT_LIST_HEAD(&inode->i_dentry);
        INIT_LIST_HEAD(&inode->i_devices);
-       mutex_init(&inode->i_mutex);
-       init_rwsem(&inode->i_alloc_sem);
        INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
        rwlock_init(&inode->i_data.tree_lock);
        spin_lock_init(&inode->i_data.i_mmap_lock);
@@ -199,7 +206,6 @@ void inode_init_once(struct inode *inode)
        spin_lock_init(&inode->i_data.private_lock);
        INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
        INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
-       spin_lock_init(&inode->i_lock);
        i_size_ordered_init(inode);
 #ifdef CONFIG_INOTIFY
        INIT_LIST_HEAD(&inode->inotify_watches);
@@ -561,6 +567,18 @@ EXPORT_SYMBOL(new_inode);
 
 void unlock_new_inode(struct inode *inode)
 {
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct file_system_type *type = inode->i_sb->s_type;
+       /*
+        * ensure nobody is actually holding i_mutex
+        */
+       mutex_destroy(&inode->i_mutex);
+       mutex_init(&inode->i_mutex);
+       if (inode->i_mode & S_IFDIR)
+               lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key);
+       else
+               lockdep_set_class(&inode->i_mutex, &type->i_mutex_key);
+#endif
        /*
         * This is special!  We do not need the spinlock
         * when clearing I_LOCK, because we're guaranteed
index 772b6531a2a25fe09f5499dd9d2b359e8edf18bc..8df5bac0b7a52a5402116745ce3eb341e89e8a3f 100644 (file)
@@ -233,6 +233,8 @@ out:
        return ret;
 }
 
+static struct lock_class_key jbd_handle_key;
+
 /* Allocate a new handle.  This should probably be in a slab... */
 static handle_t *new_handle(int nblocks)
 {
@@ -243,6 +245,8 @@ static handle_t *new_handle(int nblocks)
        handle->h_buffer_credits = nblocks;
        handle->h_ref = 1;
 
+       lockdep_init_map(&handle->h_lockdep_map, "jbd_handle", &jbd_handle_key, 0);
+
        return handle;
 }
 
@@ -286,6 +290,9 @@ handle_t *journal_start(journal_t *journal, int nblocks)
                current->journal_info = NULL;
                handle = ERR_PTR(err);
        }
+
+       lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_);
+
        return handle;
 }
 
@@ -1411,6 +1418,8 @@ int journal_stop(handle_t *handle)
                spin_unlock(&journal->j_state_lock);
        }
 
+       lock_release(&handle->h_lockdep_map, 1, _THIS_IP_);
+
        jbd_free_handle(handle);
        return err;
 }
index c32b241e3d91790dab5cfa7941f9d51a562ca357..60e5d49ca03e774fd3d02c72cdddebe7fb9eeb56 100644 (file)
@@ -17,4 +17,5 @@ jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL)    += acl.o
 jffs2-$(CONFIG_JFFS2_RUBIN)    += compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)    += compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)     += compr_zlib.o
+jffs2-$(CONFIG_JFFS2_LZO)      += compr_lzo.o
 jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
index 65b3a1b5b88dd0fc009ee4fc425f65d1ceda803e..8ec9323e830a810eef5a0833f5e365d02ca7c9ee 100644 (file)
@@ -176,7 +176,7 @@ static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct
        spin_unlock(&inode->i_lock);
 }
 
-static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
+struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        struct posix_acl *acl;
@@ -247,8 +247,13 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                        if (rc < 0)
                                return rc;
                        if (inode->i_mode != mode) {
-                               inode->i_mode = mode;
-                               jffs2_dirty_inode(inode);
+                               struct iattr attr;
+
+                               attr.ia_valid = ATTR_MODE;
+                               attr.ia_mode = mode;
+                               rc = jffs2_do_setattr(inode, &attr);
+                               if (rc < 0)
+                                       return rc;
                        }
                        if (rc == 0)
                                acl = NULL;
@@ -307,22 +312,16 @@ int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
        return generic_permission(inode, mask, jffs2_check_acl);
 }
 
-int jffs2_init_acl(struct inode *inode, struct inode *dir)
+int jffs2_init_acl(struct inode *inode, struct posix_acl *acl)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-       struct posix_acl *acl = NULL, *clone;
+       struct posix_acl *clone;
        mode_t mode;
        int rc = 0;
 
        f->i_acl_access = JFFS2_ACL_NOT_CACHED;
        f->i_acl_default = JFFS2_ACL_NOT_CACHED;
-       if (!S_ISLNK(inode->i_mode)) {
-               acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               if (!acl)
-                       inode->i_mode &= ~current->fs->umask;
-       }
+
        if (acl) {
                if (S_ISDIR(inode->i_mode)) {
                        rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
index c84378cee82ab44a8617bf77b58c7480f52fbaa1..90a2dbf590519028ee893ed6b8587e2f6682463f 100644 (file)
@@ -28,9 +28,10 @@ struct jffs2_acl_header {
 
 #define JFFS2_ACL_NOT_CACHED ((void *)-1)
 
+extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type);
 extern int jffs2_permission(struct inode *, int, struct nameidata *);
 extern int jffs2_acl_chmod(struct inode *);
-extern int jffs2_init_acl(struct inode *, struct inode *);
+extern int jffs2_init_acl(struct inode *, struct posix_acl *);
 extern void jffs2_clear_acl(struct jffs2_inode_info *);
 
 extern struct xattr_handler jffs2_acl_access_xattr_handler;
@@ -38,6 +39,7 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler;
 
 #else
 
+#define jffs2_get_acl(inode, type)     (NULL)
 #define jffs2_permission NULL
 #define jffs2_acl_chmod(inode)         (0)
 #define jffs2_init_acl(inode,dir)      (0)
index 504643f2e98b7c39817cbcea2f944332ccba459d..d568ae846741a7a89729794404958d969c98507e 100644 (file)
@@ -23,8 +23,8 @@ static int jffs2_garbage_collect_thread(void *);
 void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
 {
        spin_lock(&c->erase_completion_lock);
-        if (c->gc_task && jffs2_thread_should_wake(c))
-                send_sig(SIGHUP, c->gc_task, 1);
+       if (c->gc_task && jffs2_thread_should_wake(c))
+               send_sig(SIGHUP, c->gc_task, 1);
        spin_unlock(&c->erase_completion_lock);
 }
 
index 0ca2fff2617fa4e679860d9358a0edb1414b49d4..722a6b682951b8bcdecac8107171c2d06f5d60be 100644 (file)
@@ -285,6 +285,14 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
           than actually making progress? */
        c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
 
+       /* What number of 'very dirty' eraseblocks do we allow before we
+          trigger the GC thread even if we don't _need_ the space. When we
+          can't mark nodes obsolete on the medium, the old dirty nodes cause
+          performance problems because we have to inspect and discard them. */
+       c->vdirty_blocks_gctrigger = c->resv_blocks_gctrigger;
+       if (jffs2_can_mark_obsolete(c))
+               c->vdirty_blocks_gctrigger *= 10;
+
        /* If there's less than this amount of dirty space, don't bother
           trying to GC to make more space. It'll be a fruitless task */
        c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
@@ -303,6 +311,8 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
                  c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
        dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
                  c->nospc_dirty_size);
+       dbg_fsbuild("Very dirty blocks before GC triggered: %d\n",
+                 c->vdirty_blocks_gctrigger);
 }
 
 int jffs2_do_mount_fs(struct jffs2_sb_info *c)
index 485d065de41f0061e63d4c9e0833dd41089c0e19..86739ee53b37336c15cbc341180c47d195d9081a 100644 (file)
@@ -5,7 +5,7 @@
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
  * Copyright Â© 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
+ *                 University of Szeged, Hungary
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
@@ -24,6 +24,34 @@ static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
 /* Statistics for blocks stored without compression */
 static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
 
+
+/*
+ * Return 1 to use this compression
+ */
+static int jffs2_is_best_compression(struct jffs2_compressor *this,
+               struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
+{
+       switch (jffs2_compression_mode) {
+       case JFFS2_COMPR_MODE_SIZE:
+               if (bestsize > size)
+                       return 1;
+               return 0;
+       case JFFS2_COMPR_MODE_FAVOURLZO:
+               if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
+                       return 1;
+               if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
+                       return 1;
+               if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
+                       return 1;
+               if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
+                       return 1;
+
+               return 0;
+       }
+       /* Shouldn't happen */
+       return 0;
+}
+
 /* jffs2_compress:
  * @data: Pointer to uncompressed data
  * @cdata: Pointer to returned pointer to buffer for compressed data
@@ -43,121 +71,124 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co
  * *datalen accordingly to show the amount of data which were compressed.
  */
 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                            unsigned char *data_in, unsigned char **cpage_out,
-                            uint32_t *datalen, uint32_t *cdatalen)
+                       unsigned char *data_in, unsigned char **cpage_out,
+                       uint32_t *datalen, uint32_t *cdatalen)
 {
        int ret = JFFS2_COMPR_NONE;
-        int compr_ret;
-        struct jffs2_compressor *this, *best=NULL;
-        unsigned char *output_buf = NULL, *tmp_buf;
-        uint32_t orig_slen, orig_dlen;
-        uint32_t best_slen=0, best_dlen=0;
+       int compr_ret;
+       struct jffs2_compressor *this, *best=NULL;
+       unsigned char *output_buf = NULL, *tmp_buf;
+       uint32_t orig_slen, orig_dlen;
+       uint32_t best_slen=0, best_dlen=0;
 
-        switch (jffs2_compression_mode) {
-        case JFFS2_COMPR_MODE_NONE:
-                break;
-        case JFFS2_COMPR_MODE_PRIORITY:
-                output_buf = kmalloc(*cdatalen,GFP_KERNEL);
-                if (!output_buf) {
-                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
-                        goto out;
-                }
-                orig_slen = *datalen;
-                orig_dlen = *cdatalen;
-                spin_lock(&jffs2_compressor_list_lock);
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        /* Skip decompress-only backwards-compatibility and disabled modules */
-                        if ((!this->compress)||(this->disabled))
-                                continue;
+       switch (jffs2_compression_mode) {
+       case JFFS2_COMPR_MODE_NONE:
+               break;
+       case JFFS2_COMPR_MODE_PRIORITY:
+               output_buf = kmalloc(*cdatalen,GFP_KERNEL);
+               if (!output_buf) {
+                       printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
+                       goto out;
+               }
+               orig_slen = *datalen;
+               orig_dlen = *cdatalen;
+               spin_lock(&jffs2_compressor_list_lock);
+               list_for_each_entry(this, &jffs2_compressor_list, list) {
+                       /* Skip decompress-only backwards-compatibility and disabled modules */
+                       if ((!this->compress)||(this->disabled))
+                               continue;
 
-                        this->usecount++;
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        *datalen  = orig_slen;
-                        *cdatalen = orig_dlen;
-                        compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
-                        spin_lock(&jffs2_compressor_list_lock);
-                        this->usecount--;
-                        if (!compr_ret) {
-                                ret = this->compr;
-                                this->stat_compr_blocks++;
-                                this->stat_compr_orig_size += *datalen;
-                                this->stat_compr_new_size  += *cdatalen;
-                                break;
-                        }
-                }
-                spin_unlock(&jffs2_compressor_list_lock);
-                if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
-                break;
-        case JFFS2_COMPR_MODE_SIZE:
-                orig_slen = *datalen;
-                orig_dlen = *cdatalen;
-                spin_lock(&jffs2_compressor_list_lock);
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        /* Skip decompress-only backwards-compatibility and disabled modules */
-                        if ((!this->compress)||(this->disabled))
-                                continue;
-                        /* Allocating memory for output buffer if necessary */
-                        if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                kfree(this->compr_buf);
-                                spin_lock(&jffs2_compressor_list_lock);
-                                this->compr_buf_size=0;
-                                this->compr_buf=NULL;
-                        }
-                        if (!this->compr_buf) {
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
-                                spin_lock(&jffs2_compressor_list_lock);
-                                if (!tmp_buf) {
-                                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
-                                        continue;
-                                }
-                                else {
-                                        this->compr_buf = tmp_buf;
-                                        this->compr_buf_size = orig_dlen;
-                                }
-                        }
-                        this->usecount++;
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        *datalen  = orig_slen;
-                        *cdatalen = orig_dlen;
-                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
-                        spin_lock(&jffs2_compressor_list_lock);
-                        this->usecount--;
-                        if (!compr_ret) {
-                                if ((!best_dlen)||(best_dlen>*cdatalen)) {
-                                        best_dlen = *cdatalen;
-                                        best_slen = *datalen;
-                                        best = this;
-                                }
-                        }
-                }
-                if (best_dlen) {
-                        *cdatalen = best_dlen;
-                        *datalen  = best_slen;
-                        output_buf = best->compr_buf;
-                        best->compr_buf = NULL;
-                        best->compr_buf_size = 0;
-                        best->stat_compr_blocks++;
-                        best->stat_compr_orig_size += best_slen;
-                        best->stat_compr_new_size  += best_dlen;
-                        ret = best->compr;
-                }
-                spin_unlock(&jffs2_compressor_list_lock);
-                break;
-        default:
-                printk(KERN_ERR "JFFS2: unknow compression mode.\n");
-        }
+                       this->usecount++;
+                       spin_unlock(&jffs2_compressor_list_lock);
+                       *datalen  = orig_slen;
+                       *cdatalen = orig_dlen;
+                       compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
+                       spin_lock(&jffs2_compressor_list_lock);
+                       this->usecount--;
+                       if (!compr_ret) {
+                               ret = this->compr;
+                               this->stat_compr_blocks++;
+                               this->stat_compr_orig_size += *datalen;
+                               this->stat_compr_new_size  += *cdatalen;
+                               break;
+                       }
+               }
+               spin_unlock(&jffs2_compressor_list_lock);
+               if (ret == JFFS2_COMPR_NONE)
+                       kfree(output_buf);
+               break;
+       case JFFS2_COMPR_MODE_SIZE:
+       case JFFS2_COMPR_MODE_FAVOURLZO:
+               orig_slen = *datalen;
+               orig_dlen = *cdatalen;
+               spin_lock(&jffs2_compressor_list_lock);
+               list_for_each_entry(this, &jffs2_compressor_list, list) {
+                       /* Skip decompress-only backwards-compatibility and disabled modules */
+                       if ((!this->compress)||(this->disabled))
+                               continue;
+                       /* Allocating memory for output buffer if necessary */
+                       if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
+                               spin_unlock(&jffs2_compressor_list_lock);
+                               kfree(this->compr_buf);
+                               spin_lock(&jffs2_compressor_list_lock);
+                               this->compr_buf_size=0;
+                               this->compr_buf=NULL;
+                       }
+                       if (!this->compr_buf) {
+                               spin_unlock(&jffs2_compressor_list_lock);
+                               tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
+                               spin_lock(&jffs2_compressor_list_lock);
+                               if (!tmp_buf) {
+                                       printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen);
+                                       continue;
+                               }
+                               else {
+                                       this->compr_buf = tmp_buf;
+                                       this->compr_buf_size = orig_slen;
+                               }
+                       }
+                       this->usecount++;
+                       spin_unlock(&jffs2_compressor_list_lock);
+                       *datalen  = orig_slen;
+                       *cdatalen = orig_dlen;
+                       compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
+                       spin_lock(&jffs2_compressor_list_lock);
+                       this->usecount--;
+                       if (!compr_ret) {
+                               if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
+                                               && (*cdatalen < *datalen)) {
+                                       best_dlen = *cdatalen;
+                                       best_slen = *datalen;
+                                       best = this;
+                               }
+                       }
+               }
+               if (best_dlen) {
+                       *cdatalen = best_dlen;
+                       *datalen  = best_slen;
+                       output_buf = best->compr_buf;
+                       best->compr_buf = NULL;
+                       best->compr_buf_size = 0;
+                       best->stat_compr_blocks++;
+                       best->stat_compr_orig_size += best_slen;
+                       best->stat_compr_new_size  += best_dlen;
+                       ret = best->compr;
+               }
+               spin_unlock(&jffs2_compressor_list_lock);
+               break;
+       default:
+               printk(KERN_ERR "JFFS2: unknow compression mode.\n");
+       }
  out:
-        if (ret == JFFS2_COMPR_NONE) {
-               *cpage_out = data_in;
-               *datalen = *cdatalen;
-                none_stat_compr_blocks++;
-                none_stat_compr_size += *datalen;
-        }
-        else {
-                *cpage_out = output_buf;
-        }
+       if (ret == JFFS2_COMPR_NONE) {
+               *cpage_out = data_in;
+               *datalen = *cdatalen;
+               none_stat_compr_blocks++;
+               none_stat_compr_size += *datalen;
+       }
+       else {
+               *cpage_out = output_buf;
+       }
        return ret;
 }
 
@@ -165,8 +196,8 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                     uint16_t comprtype, unsigned char *cdata_in,
                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
 {
-        struct jffs2_compressor *this;
-        int ret;
+       struct jffs2_compressor *this;
+       int ret;
 
        /* Older code had a bug where it would write non-zero 'usercompr'
           fields. Deal with it. */
@@ -177,32 +208,32 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
        case JFFS2_COMPR_NONE:
                /* This should be special-cased elsewhere, but we might as well deal with it */
                memcpy(data_out, cdata_in, datalen);
-                none_stat_decompr_blocks++;
+               none_stat_decompr_blocks++;
                break;
        case JFFS2_COMPR_ZERO:
                memset(data_out, 0, datalen);
                break;
        default:
-                spin_lock(&jffs2_compressor_list_lock);
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        if (comprtype == this->compr) {
-                                this->usecount++;
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
-                                spin_lock(&jffs2_compressor_list_lock);
-                                if (ret) {
-                                        printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
-                                }
-                                else {
-                                        this->stat_decompr_blocks++;
-                                }
-                                this->usecount--;
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                return ret;
-                        }
-                }
+               spin_lock(&jffs2_compressor_list_lock);
+               list_for_each_entry(this, &jffs2_compressor_list, list) {
+                       if (comprtype == this->compr) {
+                               this->usecount++;
+                               spin_unlock(&jffs2_compressor_list_lock);
+                               ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
+                               spin_lock(&jffs2_compressor_list_lock);
+                               if (ret) {
+                                       printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
+                               }
+                               else {
+                                       this->stat_decompr_blocks++;
+                               }
+                               this->usecount--;
+                               spin_unlock(&jffs2_compressor_list_lock);
+                               return ret;
+                       }
+               }
                printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
-                spin_unlock(&jffs2_compressor_list_lock);
+               spin_unlock(&jffs2_compressor_list_lock);
                return -EIO;
        }
        return 0;
@@ -210,108 +241,119 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 
 int jffs2_register_compressor(struct jffs2_compressor *comp)
 {
-        struct jffs2_compressor *this;
+       struct jffs2_compressor *this;
 
-        if (!comp->name) {
-                printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
-                return -1;
-        }
-        comp->compr_buf_size=0;
-        comp->compr_buf=NULL;
-        comp->usecount=0;
-        comp->stat_compr_orig_size=0;
-        comp->stat_compr_new_size=0;
-        comp->stat_compr_blocks=0;
-        comp->stat_decompr_blocks=0;
-        D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
+       if (!comp->name) {
+               printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
+               return -1;
+       }
+       comp->compr_buf_size=0;
+       comp->compr_buf=NULL;
+       comp->usecount=0;
+       comp->stat_compr_orig_size=0;
+       comp->stat_compr_new_size=0;
+       comp->stat_compr_blocks=0;
+       comp->stat_decompr_blocks=0;
+       D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
 
-        spin_lock(&jffs2_compressor_list_lock);
+       spin_lock(&jffs2_compressor_list_lock);
 
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (this->priority < comp->priority) {
-                        list_add(&comp->list, this->list.prev);
-                        goto out;
-                }
-        }
-        list_add_tail(&comp->list, &jffs2_compressor_list);
+       list_for_each_entry(this, &jffs2_compressor_list, list) {
+               if (this->priority < comp->priority) {
+                       list_add(&comp->list, this->list.prev);
+                       goto out;
+               }
+       }
+       list_add_tail(&comp->list, &jffs2_compressor_list);
 out:
-        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-        })
+       D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+               printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+       })
 
-        spin_unlock(&jffs2_compressor_list_lock);
+       spin_unlock(&jffs2_compressor_list_lock);
 
-        return 0;
+       return 0;
 }
 
 int jffs2_unregister_compressor(struct jffs2_compressor *comp)
 {
-        D2(struct jffs2_compressor *this;)
+       D2(struct jffs2_compressor *this;)
 
-        D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
+       D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
 
-        spin_lock(&jffs2_compressor_list_lock);
+       spin_lock(&jffs2_compressor_list_lock);
 
-        if (comp->usecount) {
-                spin_unlock(&jffs2_compressor_list_lock);
-                printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
-                return -1;
-        }
-        list_del(&comp->list);
+       if (comp->usecount) {
+               spin_unlock(&jffs2_compressor_list_lock);
+               printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
+               return -1;
+       }
+       list_del(&comp->list);
 
-        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-        })
-        spin_unlock(&jffs2_compressor_list_lock);
-        return 0;
+       D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+               printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+       })
+       spin_unlock(&jffs2_compressor_list_lock);
+       return 0;
 }
 
 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
 {
-        if (orig != comprbuf)
-                kfree(comprbuf);
+       if (orig != comprbuf)
+               kfree(comprbuf);
 }
 
 int __init jffs2_compressors_init(void)
 {
 /* Registering compressors */
 #ifdef CONFIG_JFFS2_ZLIB
-        jffs2_zlib_init();
+       jffs2_zlib_init();
 #endif
 #ifdef CONFIG_JFFS2_RTIME
-        jffs2_rtime_init();
+       jffs2_rtime_init();
 #endif
 #ifdef CONFIG_JFFS2_RUBIN
-        jffs2_rubinmips_init();
-        jffs2_dynrubin_init();
+       jffs2_rubinmips_init();
+       jffs2_dynrubin_init();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+       jffs2_lzo_init();
 #endif
 /* Setting default compression mode */
 #ifdef CONFIG_JFFS2_CMODE_NONE
-        jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-        D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
+       jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+       D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
 #else
 #ifdef CONFIG_JFFS2_CMODE_SIZE
-        jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-        D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
+       jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+       D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
+#else
+#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
+       jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
+       D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");)
 #else
-        D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
+       D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
+#endif
 #endif
 #endif
-        return 0;
+       return 0;
 }
 
 int jffs2_compressors_exit(void)
 {
 /* Unregistering compressors */
+#ifdef CONFIG_JFFS2_LZO
+       jffs2_lzo_exit();
+#endif
 #ifdef CONFIG_JFFS2_RUBIN
-        jffs2_dynrubin_exit();
-        jffs2_rubinmips_exit();
+       jffs2_dynrubin_exit();
+       jffs2_rubinmips_exit();
 #endif
 #ifdef CONFIG_JFFS2_RTIME
-        jffs2_rtime_exit();
+       jffs2_rtime_exit();
 #endif
 #ifdef CONFIG_JFFS2_ZLIB
-        jffs2_zlib_exit();
+       jffs2_zlib_exit();
 #endif
-        return 0;
+       return 0;
 }
index 68cc7010dbdfa57240e7b333f5e4661759901098..7d1d72faa7745498a6e3667ec18203154d6b2417 100644 (file)
@@ -2,7 +2,7 @@
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright Â© 2004   Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
+ *                   University of Szeged, Hungary
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
 #define JFFS2_RUBINMIPS_PRIORITY 10
 #define JFFS2_DYNRUBIN_PRIORITY  20
 #define JFFS2_LZARI_PRIORITY     30
-#define JFFS2_LZO_PRIORITY       40
 #define JFFS2_RTIME_PRIORITY     50
 #define JFFS2_ZLIB_PRIORITY      60
+#define JFFS2_LZO_PRIORITY       80
+
 
 #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
-#define JFFS2_DYNRUBIN_DISABLED  /*        for decompression */
+#define JFFS2_DYNRUBIN_DISABLED  /*       for decompression */
 
 #define JFFS2_COMPR_MODE_NONE       0
 #define JFFS2_COMPR_MODE_PRIORITY   1
 #define JFFS2_COMPR_MODE_SIZE       2
+#define JFFS2_COMPR_MODE_FAVOURLZO  3
+
+#define FAVOUR_LZO_PERCENT 80
 
 struct jffs2_compressor {
-        struct list_head list;
-        int priority;              /* used by prirority comr. mode */
-        char *name;
-        char compr;                /* JFFS2_COMPR_XXX */
-        int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
-                        uint32_t *srclen, uint32_t *destlen, void *model);
-        int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
-                        uint32_t cdatalen, uint32_t datalen, void *model);
-        int usecount;
-        int disabled;              /* if seted the compressor won't compress */
-        unsigned char *compr_buf;  /* used by size compr. mode */
-        uint32_t compr_buf_size;   /* used by size compr. mode */
-        uint32_t stat_compr_orig_size;
-        uint32_t stat_compr_new_size;
-        uint32_t stat_compr_blocks;
-        uint32_t stat_decompr_blocks;
+       struct list_head list;
+       int priority;                   /* used by prirority comr. mode */
+       char *name;
+       char compr;                     /* JFFS2_COMPR_XXX */
+       int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+                       uint32_t *srclen, uint32_t *destlen, void *model);
+       int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+                         uint32_t cdatalen, uint32_t datalen, void *model);
+       int usecount;
+       int disabled;           /* if set the compressor won't compress */
+       unsigned char *compr_buf;       /* used by size compr. mode */
+       uint32_t compr_buf_size;        /* used by size compr. mode */
+       uint32_t stat_compr_orig_size;
+       uint32_t stat_compr_new_size;
+       uint32_t stat_compr_blocks;
+       uint32_t stat_decompr_blocks;
 };
 
 int jffs2_register_compressor(struct jffs2_compressor *comp);
@@ -64,12 +68,12 @@ int jffs2_compressors_init(void);
 int jffs2_compressors_exit(void);
 
 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                             unsigned char *data_in, unsigned char **cpage_out,
-                             uint32_t *datalen, uint32_t *cdatalen);
+                       unsigned char *data_in, unsigned char **cpage_out,
+                       uint32_t *datalen, uint32_t *cdatalen);
 
 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                     uint16_t comprtype, unsigned char *cdata_in,
-                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
+                    uint16_t comprtype, unsigned char *cdata_in,
+                    unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
 
 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
 
@@ -90,5 +94,9 @@ void jffs2_rtime_exit(void);
 int jffs2_zlib_init(void);
 void jffs2_zlib_exit(void);
 #endif
+#ifdef CONFIG_JFFS2_LZO
+int jffs2_lzo_init(void);
+void jffs2_lzo_exit(void);
+#endif
 
 #endif /* __JFFS2_COMPR_H__ */
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c
new file mode 100644 (file)
index 0000000..47b0457
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright Â© 2007 Nokia Corporation. All rights reserved.
+ *
+ * Created by Richard Purdie <rpurdie@openedhand.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/lzo.h>
+#include "compr.h"
+
+static void *lzo_mem;
+static void *lzo_compress_buf;
+static DEFINE_MUTEX(deflate_mutex);
+
+static void free_workspace(void)
+{
+       vfree(lzo_mem);
+       vfree(lzo_compress_buf);
+}
+
+static int __init alloc_workspace(void)
+{
+       lzo_mem = vmalloc(LZO1X_MEM_COMPRESS);
+       lzo_compress_buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE));
+
+       if (!lzo_mem || !lzo_compress_buf) {
+               printk(KERN_WARNING "Failed to allocate lzo deflate workspace\n");
+               free_workspace();
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out,
+                             uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+       size_t compress_size;
+       int ret;
+
+       mutex_lock(&deflate_mutex);
+       ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
+       mutex_unlock(&deflate_mutex);
+
+       if (ret != LZO_E_OK)
+               return -1;
+
+       if (compress_size > *dstlen)
+               return -1;
+
+       memcpy(cpage_out, lzo_compress_buf, compress_size);
+       *dstlen = compress_size;
+
+       return 0;
+}
+
+static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
+                                uint32_t srclen, uint32_t destlen, void *model)
+{
+       size_t dl = destlen;
+       int ret;
+
+       ret = lzo1x_decompress_safe(data_in, srclen, cpage_out, &dl);
+
+       if (ret != LZO_E_OK || dl != destlen)
+               return -1;
+
+       return 0;
+}
+
+static struct jffs2_compressor jffs2_lzo_comp = {
+       .priority = JFFS2_LZO_PRIORITY,
+       .name = "lzo",
+       .compr = JFFS2_COMPR_LZO,
+       .compress = &jffs2_lzo_compress,
+       .decompress = &jffs2_lzo_decompress,
+       .disabled = 0,
+};
+
+int __init jffs2_lzo_init(void)
+{
+       int ret;
+
+       ret = alloc_workspace();
+       if (ret < 0)
+               return ret;
+
+       ret = jffs2_register_compressor(&jffs2_lzo_comp);
+       if (ret)
+               free_workspace();
+
+       return ret;
+}
+
+void jffs2_lzo_exit(void)
+{
+       jffs2_unregister_compressor(&jffs2_lzo_comp);
+       free_workspace();
+}
index 0d0bfd2e4e0de7addde1bd6e580693311fffe4ad..546d1538d0762eaf61007fd9d0efbc2f6b57933c 100644 (file)
@@ -104,7 +104,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in,
                        }
                }
        }
-        return 0;
+       return 0;
 }
 
 static struct jffs2_compressor jffs2_rtime_comp = {
index ea0431e047d5389aeb55ee8f54d904d1382cfd27..c73fa89b5f8a66507e59a30a0d3539673515dc8c 100644 (file)
@@ -384,7 +384,7 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in,
                                      void *model)
 {
        rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
-        return 0;
+       return 0;
 }
 
 static int jffs2_dynrubin_decompress(unsigned char *data_in,
@@ -399,7 +399,7 @@ static int jffs2_dynrubin_decompress(unsigned char *data_in,
                bits[c] = data_in[c];
 
        rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
-        return 0;
+       return 0;
 }
 
 static struct jffs2_compressor jffs2_rubinmips_comp = {
index 2b87fccc1557a879e93d8fd36fd689ab5ce86d1b..cfd301a5edfc2db804cb1b3ab008543211c0c4aa 100644 (file)
@@ -181,7 +181,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in,
        }
        zlib_inflateEnd(&inf_strm);
        mutex_unlock(&inflate_mutex);
-        return 0;
+       return 0;
 }
 
 static struct jffs2_compressor jffs2_zlib_comp = {
@@ -203,11 +203,11 @@ int __init jffs2_zlib_init(void)
 
     ret = alloc_workspaces();
     if (ret)
-        return ret;
+           return ret;
 
     ret = jffs2_register_compressor(&jffs2_zlib_comp);
     if (ret)
-        free_workspaces();
+           free_workspaces();
 
     return ret;
 }
index c1dfca310dd6089341628d17513fb9efb9f70c1e..8353eb9c179955a8a9b54ec0d461560f2ae217b3 100644 (file)
@@ -32,7 +32,7 @@ static int jffs2_mkdir (struct inode *,struct dentry *,int);
 static int jffs2_rmdir (struct inode *,struct dentry *);
 static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
 static int jffs2_rename (struct inode *, struct dentry *,
-                        struct inode *, struct dentry *);
+                        struct inode *, struct dentry *);
 
 const struct file_operations jffs2_dir_operations =
 {
@@ -182,6 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        struct jffs2_inode_info *f, *dir_f;
        struct jffs2_sb_info *c;
        struct inode *inode;
+       struct posix_acl *acl;
        int ret;
 
        ri = jffs2_alloc_raw_inode();
@@ -192,7 +193,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
 
        D1(printk(KERN_DEBUG "jffs2_create()\n"));
 
-       inode = jffs2_new_inode(dir_i, mode, ri);
+       inode = jffs2_new_inode(dir_i, mode, ri, &acl);
 
        if (IS_ERR(inode)) {
                D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
@@ -212,12 +213,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
                              dentry->d_name.name, dentry->d_name.len);
 
        if (ret)
-               goto fail;
+               goto fail_acl;
 
        ret = jffs2_init_security(inode, dir_i);
        if (ret)
-               goto fail;
-       ret = jffs2_init_acl(inode, dir_i);
+               goto fail_acl;
+       ret = jffs2_init_acl(inode, acl);
        if (ret)
                goto fail;
 
@@ -230,6 +231,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
                  inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
        return 0;
 
+ fail_acl:
+       posix_acl_release(acl);
  fail:
        make_bad_inode(inode);
        iput(inode);
@@ -306,6 +309,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        struct jffs2_full_dirent *fd;
        int namelen;
        uint32_t alloclen;
+       struct posix_acl *acl;
        int ret, targetlen = strlen(target);
 
        /* FIXME: If you care. We'd need to use frags for the target
@@ -332,7 +336,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                return ret;
        }
 
-       inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
+       inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri, &acl);
 
        if (IS_ERR(inode)) {
                jffs2_free_raw_inode(ri);
@@ -362,6 +366,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
+               posix_acl_release(acl);
                return PTR_ERR(fn);
        }
 
@@ -372,6 +377,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
+               posix_acl_release(acl);
                return -ENOMEM;
        }
 
@@ -389,9 +395,10 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        ret = jffs2_init_security(inode, dir_i);
        if (ret) {
                jffs2_clear_inode(inode);
+               posix_acl_release(acl);
                return ret;
        }
-       ret = jffs2_init_acl(inode, dir_i);
+       ret = jffs2_init_acl(inode, acl);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -469,6 +476,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
        struct jffs2_full_dirent *fd;
        int namelen;
        uint32_t alloclen;
+       struct posix_acl *acl;
        int ret;
 
        mode |= S_IFDIR;
@@ -491,7 +499,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
                return ret;
        }
 
-       inode = jffs2_new_inode(dir_i, mode, ri);
+       inode = jffs2_new_inode(dir_i, mode, ri, &acl);
 
        if (IS_ERR(inode)) {
                jffs2_free_raw_inode(ri);
@@ -518,6 +526,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
+               posix_acl_release(acl);
                return PTR_ERR(fn);
        }
        /* No data here. Only a metadata node, which will be
@@ -531,9 +540,10 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
        ret = jffs2_init_security(inode, dir_i);
        if (ret) {
                jffs2_clear_inode(inode);
+               posix_acl_release(acl);
                return ret;
        }
-       ret = jffs2_init_acl(inode, dir_i);
+       ret = jffs2_init_acl(inode, acl);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -629,6 +639,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        union jffs2_device_node dev;
        int devlen = 0;
        uint32_t alloclen;
+       struct posix_acl *acl;
        int ret;
 
        if (!new_valid_dev(rdev))
@@ -655,7 +666,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
                return ret;
        }
 
-       inode = jffs2_new_inode(dir_i, mode, ri);
+       inode = jffs2_new_inode(dir_i, mode, ri, &acl);
 
        if (IS_ERR(inode)) {
                jffs2_free_raw_inode(ri);
@@ -684,6 +695,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
+               posix_acl_release(acl);
                return PTR_ERR(fn);
        }
        /* No data here. Only a metadata node, which will be
@@ -697,9 +709,10 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        ret = jffs2_init_security(inode, dir_i);
        if (ret) {
                jffs2_clear_inode(inode);
+               posix_acl_release(acl);
                return ret;
        }
-       ret = jffs2_init_acl(inode, dir_i);
+       ret = jffs2_init_acl(inode, acl);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -770,7 +783,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
 }
 
 static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
-                        struct inode *new_dir_i, struct dentry *new_dentry)
+                        struct inode *new_dir_i, struct dentry *new_dentry)
 {
        int ret;
        struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
index 66e7c2f1e644229d49d6cb9d33517f55e31b3495..a1db9180633fcb3476757af80f22b3e6621f06d2 100644 (file)
@@ -38,8 +38,8 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
 #ifdef __ECOS
        ret = jffs2_flash_erase(c, jeb);
        if (!ret) {
-               jffs2_erase_succeeded(c, jeb);
-               return;
+              jffs2_erase_succeeded(c, jeb);
+              return;
        }
        bad_offset = jeb->offset;
 #else /* Linux */
@@ -50,12 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
        instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
        if (!instr) {
                printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
+               down(&c->erase_free_sem);
                spin_lock(&c->erase_completion_lock);
                list_move(&jeb->list, &c->erase_pending_list);
                c->erasing_size -= c->sector_size;
                c->dirty_size += c->sector_size;
                jeb->dirty_size = c->sector_size;
                spin_unlock(&c->erase_completion_lock);
+               up(&c->erase_free_sem);
                return;
        }
 
@@ -82,12 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
        if (ret == -ENOMEM || ret == -EAGAIN) {
                /* Erase failed immediately. Refile it on the list */
                D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
+               down(&c->erase_free_sem);
                spin_lock(&c->erase_completion_lock);
                list_move(&jeb->list, &c->erase_pending_list);
                c->erasing_size -= c->sector_size;
                c->dirty_size += c->sector_size;
                jeb->dirty_size = c->sector_size;
                spin_unlock(&c->erase_completion_lock);
+               up(&c->erase_free_sem);
                return;
        }
 
@@ -114,6 +118,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
                        jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
                        list_del(&jeb->list);
                        spin_unlock(&c->erase_completion_lock);
+                       up(&c->erase_free_sem);
                        jffs2_mark_erased_block(c, jeb);
 
                        if (!--count) {
@@ -134,6 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
                        jffs2_free_jeb_node_refs(c, jeb);
                        list_add(&jeb->list, &c->erasing_list);
                        spin_unlock(&c->erase_completion_lock);
+                       up(&c->erase_free_sem);
 
                        jffs2_erase_block(c, jeb);
 
@@ -142,23 +148,25 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
                }
 
                /* Be nice */
-               cond_resched();
+               yield();
+               down(&c->erase_free_sem);
                spin_lock(&c->erase_completion_lock);
        }
 
        spin_unlock(&c->erase_completion_lock);
+       up(&c->erase_free_sem);
  done:
        D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
-
-       up(&c->erase_free_sem);
 }
 
 static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
        D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
+       down(&c->erase_free_sem);
        spin_lock(&c->erase_completion_lock);
        list_move_tail(&jeb->list, &c->erase_complete_list);
        spin_unlock(&c->erase_completion_lock);
+       up(&c->erase_free_sem);
        /* Ensure that kupdated calls us again to mark them clean */
        jffs2_erase_pending_trigger(c);
 }
@@ -172,22 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock
                   failed too many times. */
                if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
                        /* We'd like to give this block another try. */
+                       down(&c->erase_free_sem);
                        spin_lock(&c->erase_completion_lock);
                        list_move(&jeb->list, &c->erase_pending_list);
                        c->erasing_size -= c->sector_size;
                        c->dirty_size += c->sector_size;
                        jeb->dirty_size = c->sector_size;
                        spin_unlock(&c->erase_completion_lock);
+                       up(&c->erase_free_sem);
                        return;
                }
        }
 
+       down(&c->erase_free_sem);
        spin_lock(&c->erase_completion_lock);
        c->erasing_size -= c->sector_size;
        c->bad_size += c->sector_size;
        list_move(&jeb->list, &c->bad_list);
        c->nr_erasing_blocks--;
        spin_unlock(&c->erase_completion_lock);
+       up(&c->erase_free_sem);
        wake_up(&c->erase_wait);
 }
 
@@ -317,6 +329,33 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
        size_t retlen;
        int ret = -EIO;
 
+       if (c->mtd->point) {
+               unsigned long *wordebuf;
+
+               ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf);
+               if (ret) {
+                       D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
+                       goto do_flash_read;
+               }
+               if (retlen < c->sector_size) {
+                       /* Don't muck about if it won't let us point to the whole erase sector */
+                       D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
+                       c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen);
+                       goto do_flash_read;
+               }
+               wordebuf = ebuf-sizeof(*wordebuf);
+               retlen /= sizeof(*wordebuf);
+               do {
+                  if (*++wordebuf != ~0)
+                          break;
+               } while(--retlen);
+               c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size);
+               if (retlen)
+                       printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
+                              *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
+               return 0;
+       }
+ do_flash_read:
        ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!ebuf) {
                printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
@@ -362,7 +401,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
 {
        size_t retlen;
        int ret;
-       uint32_t bad_offset;
+       uint32_t uninitialized_var(bad_offset);
 
        switch (jffs2_block_check_erase(c, jeb, &bad_offset)) {
        case -EAGAIN:   goto refile;
@@ -417,6 +456,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
        }
 
+       down(&c->erase_free_sem);
        spin_lock(&c->erase_completion_lock);
        c->erasing_size -= c->sector_size;
        c->free_size += jeb->free_size;
@@ -429,23 +469,28 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
        c->nr_erasing_blocks--;
        c->nr_free_blocks++;
        spin_unlock(&c->erase_completion_lock);
+       up(&c->erase_free_sem);
        wake_up(&c->erase_wait);
        return;
 
 filebad:
+       down(&c->erase_free_sem);
        spin_lock(&c->erase_completion_lock);
        /* Stick it on a list (any list) so erase_failed can take it
           right off again.  Silly, but shouldn't happen often. */
        list_add(&jeb->list, &c->erasing_list);
        spin_unlock(&c->erase_completion_lock);
+       up(&c->erase_free_sem);
        jffs2_erase_failed(c, jeb, bad_offset);
        return;
 
 refile:
        /* Stick it back on the list from whence it came and come back later */
        jffs2_erase_pending_trigger(c);
+       down(&c->erase_free_sem);
        spin_lock(&c->erase_completion_lock);
        list_add(&jeb->list, &c->erase_complete_list);
        spin_unlock(&c->erase_completion_lock);
+       up(&c->erase_free_sem);
        return;
 }
index 8bc727b7169627713dd3fa89c5ee38d50cb521d9..ed85f9afdbc8ae4dfb5c65541c89a526d9a6f400 100644 (file)
@@ -24,7 +24,7 @@
 
 static int jffs2_flash_setup(struct jffs2_sb_info *c);
 
-static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
+int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
 {
        struct jffs2_full_dnode *old_metadata, *new_metadata;
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
@@ -36,10 +36,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        unsigned int ivalid;
        uint32_t alloclen;
        int ret;
+
        D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
-       ret = inode_change_ok(inode, iattr);
-       if (ret)
-               return ret;
 
        /* Special cases - we don't want more than one data node
           for these types on the medium at any time. So setattr
@@ -183,9 +181,14 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        int rc;
 
+       rc = inode_change_ok(dentry->d_inode, iattr);
+       if (rc)
+               return rc;
+
        rc = jffs2_do_setattr(dentry->d_inode, iattr);
        if (!rc && (iattr->ia_valid & ATTR_MODE))
                rc = jffs2_acl_chmod(dentry->d_inode);
+
        return rc;
 }
 
@@ -399,7 +402,8 @@ void jffs2_write_super (struct super_block *sb)
 
 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
    fill in the raw_inode while you're at it. */
-struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
+struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri,
+                              struct posix_acl **acl)
 {
        struct inode *inode;
        struct super_block *sb = dir_i->i_sb;
@@ -431,7 +435,23 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
        } else {
                ri->gid = cpu_to_je16(current->fsgid);
        }
-       ri->mode =  cpu_to_jemode(mode);
+
+       /* POSIX ACLs have to be processed now, at least partly.
+          The umask is only applied if there's no default ACL */
+       if (!S_ISLNK(mode)) {
+               *acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT);
+               if (IS_ERR(*acl)) {
+                       make_bad_inode(inode);
+                       iput(inode);
+                       inode = (void *)*acl;
+                       *acl = NULL;
+                       return inode;
+               }
+               if (!(*acl))
+                       mode &= ~current->fs->umask;
+       } else {
+               *acl = NULL;
+       }
        ret = jffs2_do_new_inode (c, f, mode, ri);
        if (ret) {
                make_bad_inode(inode);
index 2d99e06ab223407a400cb31f3eeefae5f0d5bf7e..32ff0373aa04d0c9f709ec22c64ad9086c343448 100644 (file)
@@ -122,6 +122,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
        struct jffs2_inode_cache *ic;
        struct jffs2_eraseblock *jeb;
        struct jffs2_raw_node_ref *raw;
+       uint32_t gcblock_dirty;
        int ret = 0, inum, nlink;
        int xattr = 0;
 
@@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
        }
 
        raw = jeb->gc_node;
+       gcblock_dirty = jeb->dirty_size;
 
        while(ref_obsolete(raw)) {
                D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
@@ -282,7 +284,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                } else {
                        ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
                }
-               goto release_sem;
+               goto test_gcnode;
        }
 #endif
 
@@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 
                if (ret != -EBADFD) {
                        spin_unlock(&c->inocache_lock);
-                       goto release_sem;
+                       goto test_gcnode;
                }
 
                /* Fall through if it wanted us to, with inocache_lock held */
@@ -407,6 +409,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 
        jffs2_gc_release_inode(c, f);
 
+ test_gcnode:
+       if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) {
+               /* Eep. This really should never happen. GC is broken */
+               printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node));
+               ret = -ENOSPC;
+       }
  release_sem:
        up(&c->alloc_sem);
 
@@ -556,7 +564,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
 
        node = kmalloc(rawlen, GFP_KERNEL);
        if (!node)
-               return -ENOMEM;
+               return -ENOMEM;
 
        ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);
        if (!ret && retlen != rawlen)
@@ -598,10 +606,15 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
                        goto bail;
                }
 
+               if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) {
+                       printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw));
+                       goto bail;
+               }
+
                if (node->d.nsize) {
                        crc = crc32(0, node->d.name, node->d.nsize);
                        if (je32_to_cpu(node->d.name_crc) != crc) {
-                               printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+                               printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
                                       ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);
                                goto bail;
                        }
@@ -624,7 +637,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
 
        if (ret || (retlen != rawlen)) {
                printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
-                       rawlen, phys_ofs, ret, retlen);
+                      rawlen, phys_ofs, ret, retlen);
                if (retlen) {
                        jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL);
                } else {
index b13298a824eddb95b14b54eaa64dda73fa1364d6..3a2197f3c812727a06fafdbb552fa9218e2058f7 100644 (file)
@@ -69,6 +69,8 @@ struct jffs2_sb_info {
        uint8_t resv_blocks_gctrigger;  /* ... wake up the GC thread */
        uint8_t resv_blocks_gcbad;      /* ... pick a block from the bad_list to GC */
        uint8_t resv_blocks_gcmerge;    /* ... merge pages when garbage collecting */
+       /* Number of 'very dirty' blocks before we trigger immediate GC */
+       uint8_t vdirty_blocks_gctrigger;
 
        uint32_t nospc_dirty_size;
 
@@ -106,6 +108,9 @@ struct jffs2_sb_info {
 
        uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
 
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+       unsigned char *wbuf_verify; /* read-back buffer for verification */
+#endif
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        unsigned char *wbuf; /* Write-behind buffer for NAND flash */
        uint32_t wbuf_ofs;
index bc5509fe577b878f542ccf3334a412c1a375d258..ec1aae9e695e9fc8955889659b59649a3fe45135 100644 (file)
@@ -127,7 +127,7 @@ static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_nod
        return ((struct jffs2_inode_cache *)raw);
 }
 
-        /* flash_offset & 3 always has to be zero, because nodes are
+       /* flash_offset & 3 always has to be zero, because nodes are
           always aligned at 4 bytes. So we have a couple of extra bits
           to play with, which indicate the node's status; see below: */
 #define REF_UNCHECKED  0       /* We haven't yet checked the CRC or built its inode */
index dbc908ad622b10d89c3e6b740ec4b063fd6c60e9..a0313fa8748e375d5ee1c2438794e5052faa360f 100644 (file)
@@ -154,7 +154,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize,
        while(ret == -EAGAIN) {
                ret = jffs2_do_reserve_space(c, minsize, len, sumsize);
                if (ret) {
-                       D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
+                       D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
                }
        }
        spin_unlock(&c->erase_completion_lock);
@@ -423,7 +423,12 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c,
           even after refiling c->nextblock */
        if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE))
            && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) {
-               printk(KERN_WARNING "argh. node added in wrong place\n");
+               printk(KERN_WARNING "argh. node added in wrong place at 0x%08x(%d)\n", ofs & ~3, ofs & 3);
+               if (c->nextblock)
+                       printk(KERN_WARNING "nextblock 0x%08x", c->nextblock->offset);
+               else
+                       printk(KERN_WARNING "No nextblock");
+               printk(", expected at %08x\n", jeb->offset + (c->sector_size - jeb->free_size));
                return ERR_PTR(-EINVAL);
        }
 #endif
@@ -717,6 +722,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
 {
        int ret = 0;
        uint32_t dirty;
+       int nr_very_dirty = 0;
+       struct jffs2_eraseblock *jeb;
 
        if (c->unchecked_size) {
                D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
@@ -738,8 +745,18 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
                        (dirty > c->nospc_dirty_size))
                ret = 1;
 
-       D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
-                 c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
+       list_for_each_entry(jeb, &c->very_dirty_list, list) {
+               nr_very_dirty++;
+               if (nr_very_dirty == c->vdirty_blocks_gctrigger) {
+                       ret = 1;
+                       /* In debug mode, actually go through and count them all */
+                       D1(continue);
+                       break;
+               }
+       }
+
+       D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n",
+                 c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no"));
 
        return ret;
 }
index 80daea96bbc29207ceae517787b1c670c47b6034..f6743a915cf389abb8df8dfad0873e1c4a3bc431 100644 (file)
@@ -173,12 +173,15 @@ int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 extern const struct inode_operations jffs2_symlink_inode_operations;
 
 /* fs.c */
+struct posix_acl;
+
 int jffs2_setattr (struct dentry *, struct iattr *);
+int jffs2_do_setattr (struct inode *, struct iattr *);
 void jffs2_read_inode (struct inode *);
 void jffs2_clear_inode (struct inode *);
 void jffs2_dirty_inode(struct inode *inode);
 struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
-                              struct jffs2_raw_inode *ri);
+                              struct jffs2_raw_inode *ri, struct posix_acl **acl);
 int jffs2_statfs (struct dentry *, struct kstatfs *);
 void jffs2_write_super (struct super_block *);
 int jffs2_remount_fs (struct super_block *, int *, char *);
index b5baa356fed2425317fe5f9616744e122f542948..2eae5d2dbebed3707bf9805675822527a922045e 100644 (file)
@@ -65,7 +65,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
                err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
                if (!err && retlen < tn->csize) {
                        JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
-                       c->mtd->unpoint(c->mtd, buffer, ofs, len);
+                       c->mtd->unpoint(c->mtd, buffer, ofs, retlen);
                } else if (err)
                        JFFS2_WARNING("MTD point failed: error code %d.\n", err);
                else
@@ -211,7 +211,7 @@ static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *
  * ordering.
  *
  * Returns 0 if the node was handled (including marking it obsolete)
- *         < 0 an if error occurred
+ *      < 0 an if error occurred
  */
 static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                struct jffs2_readinode_info *rii,
@@ -862,8 +862,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re
                JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n",
                            ref_offset(ref));
                JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n",
-                            je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
-                            je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc));
+                           je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
+                           je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc));
                jffs2_mark_node_obsolete(c, ref);
                return 0;
        }
index 6c75cd4333424347c0f37b410d7ef9e621ddb8c4..272872d27fd53242cf50b487c330e112c4b59d06 100644 (file)
@@ -101,7 +101,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                if (!ret && pointlen < c->mtd->size) {
                        /* Don't muck about if it won't let us point to the whole flash */
                        D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
-                       c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
+                       c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen);
                        flashbuf = NULL;
                }
                if (ret)
@@ -863,7 +863,7 @@ scan_more:
                        switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
                        case JFFS2_FEATURE_ROCOMPAT:
                                printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
-                               c->flags |= JFFS2_SB_FLAG_RO;
+                               c->flags |= JFFS2_SB_FLAG_RO;
                                if (!(jffs2_is_readonly(c)))
                                        return -EROFS;
                                if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
@@ -1004,6 +1004,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
 {
        struct jffs2_full_dirent *fd;
        struct jffs2_inode_cache *ic;
+       uint32_t checkedlen;
        uint32_t crc;
        int err;
 
@@ -1024,12 +1025,18 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
 
        pseudo_random += je32_to_cpu(rd->version);
 
-       fd = jffs2_alloc_full_dirent(rd->nsize+1);
+       /* Should never happen. Did. (OLPC trac #4184)*/
+       checkedlen = strnlen(rd->name, rd->nsize);
+       if (checkedlen < rd->nsize) {
+               printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
+                      ofs, checkedlen);
+       }
+       fd = jffs2_alloc_full_dirent(checkedlen+1);
        if (!fd) {
                return -ENOMEM;
        }
-       memcpy(&fd->name, rd->name, rd->nsize);
-       fd->name[rd->nsize] = 0;
+       memcpy(&fd->name, rd->name, checkedlen);
+       fd->name[checkedlen] = 0;
 
        crc = crc32(0, fd->name, rd->nsize);
        if (crc != je32_to_cpu(rd->name_crc)) {
@@ -1055,7 +1062,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
        fd->next = NULL;
        fd->version = je32_to_cpu(rd->version);
        fd->ino = je32_to_cpu(rd->ino);
-       fd->nhash = full_name_hash(fd->name, rd->nsize);
+       fd->nhash = full_name_hash(fd->name, checkedlen);
        fd->type = rd->type;
        jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 
index bc9f6ba10823b7c5dc4092840d4cfc8c246148ad..02c39c64ecb391e734d18362aa074b5ea2a401db 100644 (file)
@@ -38,9 +38,9 @@ int jffs2_init_security(struct inode *inode, struct inode *dir)
        }
        rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0);
 
-        kfree(name);
-        kfree(value);
-        return rc;
+       kfree(name);
+       kfree(value);
+       return rc;
 }
 
 /* ---- XATTR Handler for "security.*" ----------------- */
index d828b296392a00ae500c841596d7e8dda79b8670..629af01e5ade432c33c3c06506e6bc557125da08 100644 (file)
@@ -2,10 +2,10 @@
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright Â© 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                   Zoltan Sogor <weth@inf.u-szeged.hu>,
- *                   Patrik Kluba <pajko@halom.u-szeged.hu>,
- *                   University of Szeged, Hungary
- *             2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *                  Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                  Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                  University of Szeged, Hungary
+ *            2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
@@ -429,6 +429,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
 
                        case JFFS2_NODETYPE_DIRENT: {
                                struct jffs2_sum_dirent_flash *spd;
+                               int checkedlen;
                                spd = sp;
 
                                dbg_summary("Dirent at 0x%08x-0x%08x\n",
@@ -436,12 +437,25 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                            jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen));
 
 
-                               fd = jffs2_alloc_full_dirent(spd->nsize+1);
+                               /* This should never happen, but https://dev.laptop.org/ticket/4184 */
+                               checkedlen = strnlen(spd->name, spd->nsize);
+                               if (!checkedlen) {
+                                       printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n",
+                                              jeb->offset + je32_to_cpu(spd->offset));
+                                       return -EIO;
+                               }
+                               if (checkedlen < spd->nsize) {
+                                       printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
+                                              jeb->offset + je32_to_cpu(spd->offset), checkedlen);
+                               }
+
+
+                               fd = jffs2_alloc_full_dirent(checkedlen+1);
                                if (!fd)
                                        return -ENOMEM;
 
-                               memcpy(&fd->name, spd->name, spd->nsize);
-                               fd->name[spd->nsize] = 0;
+                               memcpy(&fd->name, spd->name, checkedlen);
+                               fd->name[checkedlen] = 0;
 
                                ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
                                if (!ic) {
@@ -455,7 +469,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                fd->next = NULL;
                                fd->version = je32_to_cpu(spd->version);
                                fd->ino = je32_to_cpu(spd->ino);
-                               fd->nhash = full_name_hash(fd->name, spd->nsize);
+                               fd->nhash = full_name_hash(fd->name, checkedlen);
                                fd->type = spd->type;
 
                                jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
index 0c6669e21390bd5856ae9eea29c6e9664d4361fc..8bf34f2fa5ce30b6f50f9d16de3ad5b9df31195e 100644 (file)
@@ -2,9 +2,9 @@
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright Â© 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                   Zoltan Sogor <weth@inf.u-szeged.hu>,
- *                   Patrik Kluba <pajko@halom.u-szeged.hu>,
- *                   University of Szeged, Hungary
+ *                  Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                  Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                  University of Szeged, Hungary
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
index 91d1d0f1c66c72c1d0c925d383f8e2a02973e2c4..d1d4f27464baf879825eb72ac4ad4812acfaa0fd 100644 (file)
@@ -220,6 +220,47 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info
        return NULL;
 }
 
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
+                             uint32_t ofs)
+{
+       int ret;
+       size_t retlen;
+       char *eccstr;
+
+       ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
+       if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
+               printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret);
+               return ret;
+       } else if (retlen != c->wbuf_pagesize) {
+               printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize);
+               return -EIO;
+       }
+       if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
+               return 0;
+
+       if (ret == -EUCLEAN)
+               eccstr = "corrected";
+       else if (ret == -EBADMSG)
+               eccstr = "correction failed";
+       else
+               eccstr = "OK or unused";
+
+       printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
+              eccstr, c->wbuf_ofs);
+       print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+                      c->wbuf, c->wbuf_pagesize, 0);
+
+       printk(KERN_WARNING "Read back:\n");
+       print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+                      c->wbuf_verify, c->wbuf_pagesize, 0);
+
+       return -EIO;
+}
+#else
+#define jffs2_verify_write(c,b,o) (0)
+#endif
+
 /* Recover from failure to write wbuf. Recover the nodes up to the
  * wbuf, not the one which we were starting to try to write. */
 
@@ -380,7 +421,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
                        ret = c->mtd->write(c->mtd, ofs, towrite, &retlen,
                                            rewrite_buf);
 
-               if (ret || retlen != towrite) {
+               if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
                        /* Argh. We tried. Really we did. */
                        printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
                        kfree(buf);
@@ -587,15 +628,16 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
 
                ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
 
-       if (ret || retlen != c->wbuf_pagesize) {
-               if (ret)
-                       printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
-               else {
-                       printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
-                               retlen, c->wbuf_pagesize);
-                       ret = -EIO;
-               }
-
+       if (ret) {
+               printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);
+               goto wfail;
+       } else if (retlen != c->wbuf_pagesize) {
+               printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+                      retlen, c->wbuf_pagesize);
+               ret = -EIO;
+               goto wfail;
+       } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
+       wfail:
                jffs2_wbuf_recover(c);
 
                return ret;
@@ -966,8 +1008,8 @@ exit:
 
 #define NR_OOB_SCAN_PAGES 4
 
-/* For historical reasons we use only 12 bytes for OOB clean marker */
-#define OOB_CM_SIZE 12
+/* For historical reasons we use only 8 bytes for OOB clean marker */
+#define OOB_CM_SIZE 8
 
 static const struct jffs2_unknown_node oob_cleanmarker =
 {
@@ -1021,8 +1063,8 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
 /*
  * Check for a valid cleanmarker.
  * Returns: 0 if a valid cleanmarker was found
- *          1 if no cleanmarker was found
- *          negative error code if an error occurred
+ *         1 if no cleanmarker was found
+ *         negative error code if an error occurred
  */
 int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
                                 struct jffs2_eraseblock *jeb)
@@ -1138,11 +1180,22 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
                return -ENOMEM;
        }
 
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+       c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+       if (!c->wbuf_verify) {
+               kfree(c->oobbuf);
+               kfree(c->wbuf);
+               return -ENOMEM;
+       }
+#endif
        return 0;
 }
 
 void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
 {
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+       kfree(c->wbuf_verify);
+#endif
        kfree(c->wbuf);
        kfree(c->oobbuf);
 }
index 664c164aa67c19bef7583ce6fa7014cc715ffef5..2f5695446d0f56eb92d0e2b8f26e90a7ed2938c3 100644 (file)
@@ -215,6 +215,17 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
                BUG();
           });
 
+       if (strnlen(name, namelen) != namelen) {
+               /* This should never happen, but seems to have done on at least one
+                  occasion: https://dev.laptop.org/ticket/4184 */
+               printk(KERN_CRIT "Error in jffs2_write_dirent() -- name contains zero bytes!\n");
+               printk(KERN_CRIT "Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n",
+                      je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
+                      je32_to_cpu(rd->name_crc));
+               WARN_ON(1);
+               return ERR_PTR(-EIO);
+       }
+
        vecs[0].iov_base = rd;
        vecs[0].iov_len = sizeof(*rd);
        vecs[1].iov_base = (unsigned char *)name;
@@ -226,7 +237,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
 
        fd->version = je32_to_cpu(rd->version);
        fd->ino = je32_to_cpu(rd->ino);
-       fd->nhash = full_name_hash(name, strlen(name));
+       fd->nhash = full_name_hash(name, namelen);
        fd->type = rd->type;
        memcpy(fd->name, name, namelen);
        fd->name[namelen]=0;
index 3b0ff292593717a9c5258390a92a385d8169d23a..6e3b5ddfb7ab01c0f3c133198dda659675a4654d 100644 (file)
@@ -75,7 +75,7 @@ extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c);
 extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c);
 
 extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
-                                                  uint32_t xid, uint32_t version);
+                                                        uint32_t xid, uint32_t version);
 
 extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
index 40942bc516bb0d1ae603d938f77e4fbf86ac5825..8bbeab90ada130981737ae6c4a0032c74556c007 100644 (file)
@@ -17,7 +17,7 @@
 #include "nodelist.h"
 
 static int jffs2_user_getxattr(struct inode *inode, const char *name,
-                               void *buffer, size_t size)
+                              void *buffer, size_t size)
 {
        if (!strcmp(name, ""))
                return -EINVAL;
@@ -25,7 +25,7 @@ static int jffs2_user_getxattr(struct inode *inode, const char *name,
 }
 
 static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer,
-                               size_t size, int flags)
+                              size_t size, int flags)
 {
        if (!strcmp(name, ""))
                return -EINVAL;
index c14ba3cfa8189f04910b02ebb305601ffef0a853..df0b8535de849f5d26d732c7da5eb66e35bfd762 100644 (file)
@@ -520,7 +520,7 @@ static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
  *     Changes an entry in the directory index table
  */
 static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
-                        int slot, struct metapage ** mp, u64 *lblock)
+                        int slot, struct metapage ** mp, s64 *lblock)
 {
        struct dir_table_slot *dirtab_slot;
 
index cb8f30985ad160e38f244e3cb45ab9b377240865..439901d205feaf1b1a0243ea6141490267f1be30 100644 (file)
@@ -49,7 +49,7 @@ struct jfs_inode_info {
        short   btorder;        /* access order */
        short   btindex;        /* btpage entry index*/
        struct inode *ipimap;   /* inode map                    */
-       long    cflag;          /* commit flags         */
+       unsigned long cflag;    /* commit flags         */
        u16     bxflag;         /* xflag of pseudo buffer?      */
        unchar  agno;           /* ag number                    */
        signed char active_ag;  /* ag currently allocating from */
index ccfd02944053b3178c4cbcab5604ef4621e6a2e4..15a3974cdeeb1f478cb4040e47b80a61994a6ca5 100644 (file)
@@ -2234,6 +2234,8 @@ static void lbmIODone(struct bio *bio, int error)
 
                /* wakeup I/O initiator */
                LCACHE_WAKEUP(&bp->l_ioevent);
+
+               return;
        }
 
        /*
@@ -2258,6 +2260,7 @@ static void lbmIODone(struct bio *bio, int error)
        if (bp->l_flag & lbmDIRECT) {
                LCACHE_WAKEUP(&bp->l_ioevent);
                LCACHE_UNLOCK(flags);
+               return;
        }
 
        tail = log->wqueue;
index 1f85ef0ec0456afbe937be2b03ac215473ceb3fa..9236bc49ae7ff1aed9cad81a2b22c2c54e433ba0 100644 (file)
@@ -376,7 +376,7 @@ struct jfs_log {
        int size;               /* 4: log size in log page (in page) */
        int l2bsize;            /* 4: log2 of bsize */
 
-       long flag;              /* 4: flag */
+       unsigned long flag;     /* 4: flag */
 
        struct lbuf *lbuf_free; /* 4: free lbufs */
        wait_queue_head_t free_wait;    /* 4: */
index 3353ed8421a7af49e69e98758860d7d7754f7185..908b23fadd05a98d28c533ab6bd7cfba3e859e8a 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/utsname.h>
 #include <linux/kernel.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprtsock.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/sm_inter.h>
@@ -132,7 +133,7 @@ nsm_create(void)
                .sin_port       = 0,
        };
        struct rpc_create_args args = {
-               .protocol       = IPPROTO_UDP,
+               .protocol       = XPRT_TRANSPORT_UDP,
                .address        = (struct sockaddr *)&sin,
                .addrsize       = sizeof(sin),
                .servername     = "localhost",
index 5316e307a49d3a17156cbced0828558c37eb9cb7..633653bff9440632417dc8aaba3491e62265416c 100644 (file)
@@ -62,8 +62,9 @@ static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
        }
        else 
        {
-               printk(KERN_NOTICE
-                       "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN);
+               dprintk("lockd: bad cookie size %d (only cookies under "
+                       "%d bytes are supported.)\n",
+                               len, NLM_MAXCOOKIELEN);
                return NULL;
        }
        return p;
@@ -84,8 +85,7 @@ nlm_decode_fh(__be32 *p, struct nfs_fh *f)
        unsigned int    len;
 
        if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
-               printk(KERN_NOTICE
-                       "lockd: bad fhandle size %d (should be %d)\n",
+               dprintk("lockd: bad fhandle size %d (should be %d)\n",
                        len, NFS2_FHSIZE);
                return NULL;
        }
index 846fc1d639ddf94b72e7f793f49d835140c9c43e..43ff9397e6c67fee3504dda5e5c3579c04212cf2 100644 (file)
@@ -64,8 +64,9 @@ nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
        }
        else 
        {
-               printk(KERN_NOTICE
-                       "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN);
+               dprintk("lockd: bad cookie size %d (only cookies under "
+                       "%d bytes are supported.)\n",
+                               len, NLM_MAXCOOKIELEN);
                return NULL;
        }
        return p;
@@ -86,8 +87,7 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
        memset(f->data, 0, sizeof(f->data));
        f->size = ntohl(*p++);
        if (f->size > NFS_MAXFHSIZE) {
-               printk(KERN_NOTICE
-                       "lockd: bad fhandle size %d (should be <=%d)\n",
+               dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
                        f->size, NFS_MAXFHSIZE);
                return NULL;
        }
index b55cb236cf74c0be1adf41d43e21e71d298fa1b5..df0f41e0988526fe8c8529fbfbe7f32e0b41c4eb 100644 (file)
@@ -16,4 +16,3 @@ nfs-$(CONFIG_NFS_V4)  += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
                           nfs4namespace.o
 nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
 nfs-$(CONFIG_SYSCTL) += sysctl.o
-nfs-objs               := $(nfs-y)
index a204484072f34ca37320f310eeee2b8bdbb35cca..a532ee12740acd34ffdea0f139c619ae097a1308 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/metrics.h>
+#include <linux/sunrpc/xprtsock.h>
+#include <linux/sunrpc/xprtrdma.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
@@ -340,7 +342,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
                to->to_retries = 2;
 
        switch (proto) {
-       case IPPROTO_TCP:
+       case XPRT_TRANSPORT_TCP:
+       case XPRT_TRANSPORT_RDMA:
                if (!to->to_initval)
                        to->to_initval = 60 * HZ;
                if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
@@ -349,7 +352,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
                to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
                to->to_exponential = 0;
                break;
-       case IPPROTO_UDP:
+       case XPRT_TRANSPORT_UDP:
        default:
                if (!to->to_initval)
                        to->to_initval = 11 * HZ / 10;
@@ -501,9 +504,9 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t
 /*
  * Initialise an NFS2 or NFS3 client
  */
-static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data)
+static int nfs_init_client(struct nfs_client *clp,
+                          const struct nfs_parsed_mount_data *data)
 {
-       int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
        int error;
 
        if (clp->cl_cons_state == NFS_CS_READY) {
@@ -522,8 +525,8 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *
         * Create a client RPC handle for doing FSSTAT with UNIX auth only
         * - RFC 2623, sec 2.3.2
         */
-       error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans,
-                                       RPC_AUTH_UNIX, 0);
+       error = nfs_create_rpc_client(clp, data->nfs_server.protocol,
+                               data->timeo, data->retrans, RPC_AUTH_UNIX, 0);
        if (error < 0)
                goto error;
        nfs_mark_client_ready(clp, NFS_CS_READY);
@@ -538,7 +541,8 @@ error:
 /*
  * Create a version 2 or 3 client
  */
-static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data)
+static int nfs_init_server(struct nfs_server *server,
+                          const struct nfs_parsed_mount_data *data)
 {
        struct nfs_client *clp;
        int error, nfsvers = 2;
@@ -551,7 +555,8 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
 #endif
 
        /* Allocate or find a client reference we can use */
-       clp = nfs_get_client(data->hostname, &data->addr, nfsvers);
+       clp = nfs_get_client(data->nfs_server.hostname,
+                               &data->nfs_server.address, nfsvers);
        if (IS_ERR(clp)) {
                dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
                return PTR_ERR(clp);
@@ -581,7 +586,7 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
        if (error < 0)
                goto error;
 
-       error = nfs_init_server_rpcclient(server, data->pseudoflavor);
+       error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
        if (error < 0)
                goto error;
 
@@ -760,7 +765,7 @@ void nfs_free_server(struct nfs_server *server)
  * Create a version 2 or 3 volume record
  * - keyed on server and FSID
  */
-struct nfs_server *nfs_create_server(const struct nfs_mount_data *data,
+struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
                                     struct nfs_fh *mntfh)
 {
        struct nfs_server *server;
@@ -906,7 +911,7 @@ error:
  * Create a version 4 volume record
  */
 static int nfs4_init_server(struct nfs_server *server,
-               const struct nfs4_mount_data *data, rpc_authflavor_t authflavour)
+               const struct nfs_parsed_mount_data *data)
 {
        int error;
 
@@ -926,7 +931,7 @@ static int nfs4_init_server(struct nfs_server *server,
        server->acdirmin = data->acdirmin * HZ;
        server->acdirmax = data->acdirmax * HZ;
 
-       error = nfs_init_server_rpcclient(server, authflavour);
+       error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
 
        /* Done */
        dprintk("<-- nfs4_init_server() = %d\n", error);
@@ -937,12 +942,7 @@ static int nfs4_init_server(struct nfs_server *server,
  * Create a version 4 volume record
  * - keyed on server and FSID
  */
-struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
-                                     const char *hostname,
-                                     const struct sockaddr_in *addr,
-                                     const char *mntpath,
-                                     const char *ip_addr,
-                                     rpc_authflavor_t authflavour,
+struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
                                      struct nfs_fh *mntfh)
 {
        struct nfs_fattr fattr;
@@ -956,13 +956,18 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
                return ERR_PTR(-ENOMEM);
 
        /* Get a client record */
-       error = nfs4_set_client(server, hostname, addr, ip_addr, authflavour,
-                       data->proto, data->timeo, data->retrans);
+       error = nfs4_set_client(server,
+                       data->nfs_server.hostname,
+                       &data->nfs_server.address,
+                       data->client_address,
+                       data->auth_flavors[0],
+                       data->nfs_server.protocol,
+                       data->timeo, data->retrans);
        if (error < 0)
                goto error;
 
        /* set up the general RPC client */
-       error = nfs4_init_server(server, data, authflavour);
+       error = nfs4_init_server(server, data);
        if (error < 0)
                goto error;
 
@@ -971,7 +976,7 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
        BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
 
        /* Probe the root fh to retrieve its FSID */
-       error = nfs4_path_walk(server, mntfh, mntpath);
+       error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path);
        if (error < 0)
                goto error;
 
index c55a761c22bb69eb0b9c8a83f3cb575cff5a0845..af8b235d405dba2ea74c260fd13aba31a5ac46f1 100644 (file)
@@ -52,7 +52,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
        for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
-               if ((struct nfs_open_context *)fl->fl_file->private_data != ctx)
+               if (nfs_file_open_context(fl->fl_file) != ctx)
                        continue;
                status = nfs4_lock_delegation_recall(state, fl);
                if (status >= 0)
@@ -109,6 +109,7 @@ again:
 void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
 {
        struct nfs_delegation *delegation = NFS_I(inode)->delegation;
+       struct rpc_cred *oldcred;
 
        if (delegation == NULL)
                return;
@@ -116,11 +117,12 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
                        sizeof(delegation->stateid.data));
        delegation->type = res->delegation_type;
        delegation->maxsize = res->maxsize;
-       put_rpccred(cred);
+       oldcred = delegation->cred;
        delegation->cred = get_rpccred(cred);
        delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
        NFS_I(inode)->delegation_state = delegation->type;
        smp_wmb();
+       put_rpccred(oldcred);
 }
 
 /*
index e4a04d16b8b06fd4faf22b7ba238f404403a8c7f..8ec7fbd8240c2ed37c24e0f342b72c90a1a3a212 100644 (file)
@@ -200,9 +200,6 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
        desc->timestamp = timestamp;
        desc->timestamp_valid = 1;
        SetPageUptodate(page);
-       spin_lock(&inode->i_lock);
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
-       spin_unlock(&inode->i_lock);
        /* Ensure consistent page alignment of the data.
         * Note: assumes we have exclusive access to this mapping either
         *       through inode->i_mutex or some other mechanism.
@@ -214,9 +211,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
        unlock_page(page);
        return 0;
  error:
-       SetPageError(page);
        unlock_page(page);
-       nfs_zap_caches(inode);
        desc->error = error;
        return -EIO;
 }
@@ -407,7 +402,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
        struct file     *file = desc->file;
        struct nfs_entry *entry = desc->entry;
        struct dentry   *dentry = NULL;
-       unsigned long   fileid;
+       u64             fileid;
        int             loop_count = 0,
                        res;
 
@@ -418,7 +413,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                unsigned d_type = DT_UNKNOWN;
                /* Note: entry->prev_cookie contains the cookie for
                 *       retrieving the current dirent on the server */
-               fileid = nfs_fileid_to_ino_t(entry->ino);
+               fileid = entry->ino;
 
                /* Get a dentry if we have one */
                if (dentry != NULL)
@@ -428,11 +423,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                /* Use readdirplus info */
                if (dentry != NULL && dentry->d_inode != NULL) {
                        d_type = dt_type(dentry->d_inode);
-                       fileid = dentry->d_inode->i_ino;
+                       fileid = NFS_FILEID(dentry->d_inode);
                }
 
                res = filldir(dirent, entry->name, entry->len, 
-                             file->f_pos, fileid, d_type);
+                             file->f_pos, nfs_compat_user_ino64(fileid),
+                             d_type);
                if (res < 0)
                        break;
                file->f_pos++;
@@ -490,9 +486,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
                                                page,
                                                NFS_SERVER(inode)->dtsize,
                                                desc->plus);
-       spin_lock(&inode->i_lock);
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
-       spin_unlock(&inode->i_lock);
        desc->page = page;
        desc->ptr = kmap(page);         /* matching kunmap in nfs_do_filldir */
        if (desc->error >= 0) {
@@ -558,7 +551,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        memset(desc, 0, sizeof(*desc));
 
        desc->file = filp;
-       desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie;
+       desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie;
        desc->decode = NFS_PROTO(inode)->decode_dirent;
        desc->plus = NFS_USE_READDIRPLUS(inode);
 
@@ -623,7 +616,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
        }
        if (offset != filp->f_pos) {
                filp->f_pos = offset;
-               ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0;
+               nfs_file_open_context(filp)->dir_cookie = 0;
        }
 out:
        mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
@@ -650,36 +643,18 @@ static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
  */
 static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 {
-       unsigned long verf;
-
        if (IS_ROOT(dentry))
                return 1;
-       verf = dentry->d_time;
-       if (nfs_caches_unstable(dir)
-                       || verf != NFS_I(dir)->cache_change_attribute)
+       if (!nfs_verify_change_attribute(dir, dentry->d_time))
+               return 0;
+       /* Revalidate nfsi->cache_change_attribute before we declare a match */
+       if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+               return 0;
+       if (!nfs_verify_change_attribute(dir, dentry->d_time))
                return 0;
        return 1;
 }
 
-static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
-{
-       dentry->d_time = verf;
-}
-
-static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
-{
-       nfs_set_verifier(dentry, verf);
-}
-
-/*
- * Whenever an NFS operation succeeds, we know that the dentry
- * is valid, so we update the revalidation timestamp.
- */
-static inline void nfs_renew_times(struct dentry * dentry)
-{
-       dentry->d_time = jiffies;
-}
-
 /*
  * Return the intent data that applies to this particular path component
  *
@@ -694,6 +669,19 @@ static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigne
        return nd->flags & mask;
 }
 
+/*
+ * Use intent information to check whether or not we're going to do
+ * an O_EXCL create using this path component.
+ */
+static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
+{
+       if (NFS_PROTO(dir)->version == 2)
+               return 0;
+       if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
+               return 0;
+       return (nd->intent.open.flags & O_EXCL) != 0;
+}
+
 /*
  * Inode and filehandle revalidation for lookups.
  *
@@ -717,6 +705,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
                                (S_ISREG(inode->i_mode) ||
                                 S_ISDIR(inode->i_mode)))
                        goto out_force;
+               return 0;
        }
        return nfs_revalidate_inode(server, inode);
 out_force:
@@ -759,7 +748,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        int error;
        struct nfs_fh fhandle;
        struct nfs_fattr fattr;
-       unsigned long verifier;
 
        parent = dget_parent(dentry);
        lock_kernel();
@@ -767,10 +755,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
        inode = dentry->d_inode;
 
-       /* Revalidate parent directory attribute cache */
-       if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
-               goto out_zap_parent;
-
        if (!inode) {
                if (nfs_neg_need_reval(dir, dentry, nd))
                        goto out_bad;
@@ -785,7 +769,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        }
 
        /* Force a full look up iff the parent directory has changed */
-       if (nfs_check_verifier(dir, dentry)) {
+       if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
                if (nfs_lookup_verify_inode(inode, nd))
                        goto out_zap_parent;
                goto out_valid;
@@ -794,7 +778,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        if (NFS_STALE(inode))
                goto out_bad;
 
-       verifier = nfs_save_change_attribute(dir);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
        if (error)
                goto out_bad;
@@ -803,8 +786,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
                goto out_bad;
 
-       nfs_renew_times(dentry);
-       nfs_refresh_verifier(dentry, verifier);
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  out_valid:
        unlock_kernel();
        dput(parent);
@@ -815,7 +797,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
 out_zap_parent:
        nfs_zap_caches(dir);
  out_bad:
-       NFS_CACHEINV(dir);
+       nfs_mark_for_revalidate(dir);
        if (inode && S_ISDIR(inode->i_mode)) {
                /* Purge readdir caches. */
                nfs_zap_caches(inode);
@@ -872,8 +854,6 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
                nfs_complete_unlink(dentry, inode);
                unlock_kernel();
        }
-       /* When creating a negative dentry, we want to renew d_time */
-       nfs_renew_times(dentry);
        iput(inode);
 }
 
@@ -883,30 +863,6 @@ struct dentry_operations nfs_dentry_operations = {
        .d_iput         = nfs_dentry_iput,
 };
 
-/*
- * Use intent information to check whether or not we're going to do
- * an O_EXCL create using this path component.
- */
-static inline
-int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
-{
-       if (NFS_PROTO(dir)->version == 2)
-               return 0;
-       if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
-               return 0;
-       return (nd->intent.open.flags & O_EXCL) != 0;
-}
-
-static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr)
-{
-       struct nfs_server *server = NFS_SERVER(dir);
-
-       if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
-               /* Revalidate fsid using the parent directory */
-               return __nfs_revalidate_inode(server, dir);
-       return 0;
-}
-
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
        struct dentry *res;
@@ -945,11 +901,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
                res = ERR_PTR(error);
                goto out_unlock;
        }
-       error = nfs_reval_fsid(dir, &fattr);
-       if (error < 0) {
-               res = ERR_PTR(error);
-               goto out_unlock;
-       }
        inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
        res = (struct dentry *)inode;
        if (IS_ERR(res))
@@ -958,17 +909,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
 no_entry:
        res = d_materialise_unique(dentry, inode);
        if (res != NULL) {
-               struct dentry *parent;
                if (IS_ERR(res))
                        goto out_unlock;
-               /* Was a directory renamed! */
-               parent = dget_parent(res);
-               if (!IS_ROOT(parent))
-                       nfs_mark_for_revalidate(parent->d_inode);
-               dput(parent);
                dentry = res;
        }
-       nfs_renew_times(dentry);
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out_unlock:
        unlock_kernel();
@@ -1020,28 +964,16 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
        }
        dentry->d_op = NFS_PROTO(dir)->dentry_ops;
 
-       /* Let vfs_create() deal with O_EXCL */
+       /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
+        * the dentry. */
        if (nd->intent.open.flags & O_EXCL) {
-               d_add(dentry, NULL);
+               d_instantiate(dentry, NULL);
                goto out;
        }
 
        /* Open the file on the server */
        lock_kernel();
-       /* Revalidate parent directory attribute cache */
-       error = nfs_revalidate_inode(NFS_SERVER(dir), dir);
-       if (error < 0) {
-               res = ERR_PTR(error);
-               unlock_kernel();
-               goto out;
-       }
-
-       if (nd->intent.open.flags & O_CREAT) {
-               nfs_begin_data_update(dir);
-               res = nfs4_atomic_open(dir, dentry, nd);
-               nfs_end_data_update(dir);
-       } else
-               res = nfs4_atomic_open(dir, dentry, nd);
+       res = nfs4_atomic_open(dir, dentry, nd);
        unlock_kernel();
        if (IS_ERR(res)) {
                error = PTR_ERR(res);
@@ -1063,8 +995,6 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
                }
        } else if (res != NULL)
                dentry = res;
-       nfs_renew_times(dentry);
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out:
        return res;
 no_open:
@@ -1076,7 +1006,6 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct dentry *parent = NULL;
        struct inode *inode = dentry->d_inode;
        struct inode *dir;
-       unsigned long verifier;
        int openflags, ret = 0;
 
        parent = dget_parent(dentry);
@@ -1086,8 +1015,12 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        /* We can't create new files in nfs_open_revalidate(), so we
         * optimize away revalidation of negative dentries.
         */
-       if (inode == NULL)
+       if (inode == NULL) {
+               if (!nfs_neg_need_reval(dir, dentry, nd))
+                       ret = 1;
                goto out;
+       }
+
        /* NFS only supports OPEN on regular files */
        if (!S_ISREG(inode->i_mode))
                goto no_open;
@@ -1104,10 +1037,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
         * change attribute *before* we do the RPC call.
         */
        lock_kernel();
-       verifier = nfs_save_change_attribute(dir);
        ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
-       if (!ret)
-               nfs_refresh_verifier(dentry, verifier);
        unlock_kernel();
 out:
        dput(parent);
@@ -1133,6 +1063,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
                .len = entry->len,
        };
        struct inode *inode;
+       unsigned long verf = nfs_save_change_attribute(dir);
 
        switch (name.len) {
                case 2:
@@ -1143,6 +1074,14 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
                        if (name.name[0] == '.')
                                return dget(parent);
        }
+
+       spin_lock(&dir->i_lock);
+       if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) {
+               spin_unlock(&dir->i_lock);
+               return NULL;
+       }
+       spin_unlock(&dir->i_lock);
+
        name.hash = full_name_hash(name.name, name.len);
        dentry = d_lookup(parent, &name);
        if (dentry != NULL) {
@@ -1183,12 +1122,8 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
                dentry = alias;
        }
 
-       nfs_renew_times(dentry);
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-       return dentry;
 out_renew:
-       nfs_renew_times(dentry);
-       nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir));
+       nfs_set_verifier(dentry, verf);
        return dentry;
 }
 
@@ -1198,32 +1133,40 @@ out_renew:
 int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
                                struct nfs_fattr *fattr)
 {
+       struct dentry *parent = dget_parent(dentry);
+       struct inode *dir = parent->d_inode;
        struct inode *inode;
        int error = -EACCES;
 
+       d_drop(dentry);
+
        /* We may have been initialized further down */
        if (dentry->d_inode)
-               return 0;
+               goto out;
        if (fhandle->size == 0) {
-               struct inode *dir = dentry->d_parent->d_inode;
                error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
                if (error)
-                       return error;
+                       goto out_error;
        }
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        if (!(fattr->valid & NFS_ATTR_FATTR)) {
                struct nfs_server *server = NFS_SB(dentry->d_sb);
                error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
                if (error < 0)
-                       return error;
+                       goto out_error;
        }
        inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
        error = PTR_ERR(inode);
        if (IS_ERR(inode))
-               return error;
-       d_instantiate(dentry, inode);
-       if (d_unhashed(dentry))
-               d_rehash(dentry);
+               goto out_error;
+       d_add(dentry, inode);
+out:
+       dput(parent);
        return 0;
+out_error:
+       nfs_mark_for_revalidate(dir);
+       dput(parent);
+       return error;
 }
 
 /*
@@ -1249,13 +1192,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
                open_flags = nd->intent.open.flags;
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
-       nfs_end_data_update(dir);
        if (error != 0)
                goto out_err;
-       nfs_renew_times(dentry);
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        unlock_kernel();
        return 0;
 out_err:
@@ -1283,13 +1222,9 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
        attr.ia_valid = ATTR_MODE;
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
-       nfs_end_data_update(dir);
        if (status != 0)
                goto out_err;
-       nfs_renew_times(dentry);
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        unlock_kernel();
        return 0;
 out_err:
@@ -1313,13 +1248,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        attr.ia_mode = mode | S_IFDIR;
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
-       nfs_end_data_update(dir);
        if (error != 0)
                goto out_err;
-       nfs_renew_times(dentry);
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        unlock_kernel();
        return 0;
 out_err:
@@ -1336,12 +1267,10 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
        lock_kernel();
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
        /* Ensure the VFS deletes this inode */
        if (error == 0 && dentry->d_inode != NULL)
                clear_nlink(dentry->d_inode);
-       nfs_end_data_update(dir);
        unlock_kernel();
 
        return error;
@@ -1350,9 +1279,9 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
 {
        static unsigned int sillycounter;
-       const int      i_inosize  = sizeof(dir->i_ino)*2;
+       const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;
        const int      countersize = sizeof(sillycounter)*2;
-       const int      slen       = sizeof(".nfs") + i_inosize + countersize - 1;
+       const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;
        char           silly[slen+1];
        struct qstr    qsilly;
        struct dentry *sdentry;
@@ -1370,8 +1299,9 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
                goto out;
 
-       sprintf(silly, ".nfs%*.*lx",
-               i_inosize, i_inosize, dentry->d_inode->i_ino);
+       sprintf(silly, ".nfs%*.*Lx",
+               fileidsize, fileidsize,
+               (unsigned long long)NFS_FILEID(dentry->d_inode));
 
        /* Return delegation in anticipation of the rename */
        nfs_inode_return_delegation(dentry->d_inode);
@@ -1398,19 +1328,14 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
 
        qsilly.name = silly;
        qsilly.len  = strlen(silly);
-       nfs_begin_data_update(dir);
        if (dentry->d_inode) {
-               nfs_begin_data_update(dentry->d_inode);
                error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
                                dir, &qsilly);
                nfs_mark_for_revalidate(dentry->d_inode);
-               nfs_end_data_update(dentry->d_inode);
        } else
                error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
                                dir, &qsilly);
-       nfs_end_data_update(dir);
        if (!error) {
-               nfs_renew_times(dentry);
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                d_move(dentry, sdentry);
                error = nfs_async_unlink(dir, dentry);
@@ -1443,19 +1368,15 @@ static int nfs_safe_remove(struct dentry *dentry)
                goto out;
        }
 
-       nfs_begin_data_update(dir);
        if (inode != NULL) {
                nfs_inode_return_delegation(inode);
-               nfs_begin_data_update(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
                /* The VFS may want to delete this inode */
                if (error == 0)
                        drop_nlink(inode);
                nfs_mark_for_revalidate(inode);
-               nfs_end_data_update(inode);
        } else
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
-       nfs_end_data_update(dir);
 out:
        return error;
 }
@@ -1493,7 +1414,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
        spin_unlock(&dcache_lock);
        error = nfs_safe_remove(dentry);
        if (!error) {
-               nfs_renew_times(dentry);
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        } else if (need_rehash)
                d_rehash(dentry);
@@ -1548,9 +1468,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
                memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
        kunmap_atomic(kaddr, KM_USER0);
 
-       nfs_begin_data_update(dir);
        error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
-       nfs_end_data_update(dir);
        if (error != 0) {
                dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
                        dir->i_sb->s_id, dir->i_ino,
@@ -1590,15 +1508,12 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
        lock_kernel();
-       nfs_begin_data_update(dir);
-       nfs_begin_data_update(inode);
+       d_drop(dentry);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
        if (error == 0) {
                atomic_inc(&inode->i_count);
-               d_instantiate(dentry, inode);
+               d_add(dentry, inode);
        }
-       nfs_end_data_update(inode);
-       nfs_end_data_update(dir);
        unlock_kernel();
        return error;
 }
@@ -1701,22 +1616,16 @@ go_ahead:
                d_delete(new_dentry);
        }
 
-       nfs_begin_data_update(old_dir);
-       nfs_begin_data_update(new_dir);
-       nfs_begin_data_update(old_inode);
        error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
                                           new_dir, &new_dentry->d_name);
        nfs_mark_for_revalidate(old_inode);
-       nfs_end_data_update(old_inode);
-       nfs_end_data_update(new_dir);
-       nfs_end_data_update(old_dir);
 out:
        if (rehash)
                d_rehash(rehash);
        if (!error) {
                d_move(old_dentry, new_dentry);
-               nfs_renew_times(new_dentry);
-               nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir));
+               nfs_set_verifier(new_dentry,
+                                       nfs_save_change_attribute(new_dir));
        }
 
        /* new dentry created? */
@@ -1842,7 +1751,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
        return NULL;
 }
 
-int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
+static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_access_entry *cache;
@@ -1854,7 +1763,7 @@ int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs
        cache = nfs_access_search_rbtree(inode, cred);
        if (cache == NULL)
                goto out;
-       if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)))
+       if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
                goto out_stale;
        res->jiffies = cache->jiffies;
        res->cred = cache->cred;
@@ -1909,7 +1818,7 @@ found:
        nfs_access_free_entry(entry);
 }
 
-void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
+static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
 {
        struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
        if (cache == NULL)
@@ -1957,6 +1866,24 @@ out:
        return -EACCES;
 }
 
+static int nfs_open_permission_mask(int openflags)
+{
+       int mask = 0;
+
+       if (openflags & FMODE_READ)
+               mask |= MAY_READ;
+       if (openflags & FMODE_WRITE)
+               mask |= MAY_WRITE;
+       if (openflags & FMODE_EXEC)
+               mask |= MAY_EXEC;
+       return mask;
+}
+
+int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
+{
+       return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
+}
+
 int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
        struct rpc_cred *cred;
index fcf4d384610e1a916cebf2f5c9c3f958f8c54b0b..32fe97211eea995b3b6b76d63507bbda3b2a5398 100644 (file)
@@ -368,7 +368,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
                return -ENOMEM;
 
        dreq->inode = inode;
-       dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
+       dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
@@ -510,7 +510,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
                        nfs_direct_write_reschedule(dreq);
                        break;
                default:
-                       nfs_end_data_update(inode);
                        if (dreq->commit_data != NULL)
                                nfs_commit_free(dreq->commit_data);
                        nfs_direct_free_writedata(dreq);
@@ -533,7 +532,6 @@ static inline void nfs_alloc_commit_data(struct nfs_direct_req *dreq)
 
 static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode)
 {
-       nfs_end_data_update(inode);
        nfs_direct_free_writedata(dreq);
        nfs_zap_mapping(inode, inode->i_mapping);
        nfs_direct_complete(dreq);
@@ -718,14 +716,12 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
                sync = FLUSH_STABLE;
 
        dreq->inode = inode;
-       dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
+       dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
        nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count);
 
-       nfs_begin_data_update(inode);
-
        rpc_clnt_sigmask(clnt, &oldset);
        result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
        if (!result)
index 579cf8a7d4a75177a0a04a3baf615c0aa1ac4494..c664bb9214255eccdcba34e987a33f1deb1cbe10 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/system.h>
 
 #include "delegation.h"
+#include "internal.h"
 #include "iostat.h"
 
 #define NFSDBG_FACILITY                NFSDBG_FILE
@@ -55,6 +56,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
 static int nfs_setlease(struct file *file, long arg, struct file_lock **fl);
 
+static struct vm_operations_struct nfs_file_vm_ops;
+
 const struct file_operations nfs_file_operations = {
        .llseek         = nfs_file_llseek,
        .read           = do_sync_read,
@@ -173,6 +176,31 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
        return remote_llseek(filp, offset, origin);
 }
 
+/*
+ * Helper for nfs_file_flush() and nfs_fsync()
+ *
+ * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
+ * disk, but it retrieves and clears ctx->error after synching, despite
+ * the two being set at the same time in nfs_context_set_write_error().
+ * This is because the former is used to notify the _next_ call to
+ * nfs_file_write() that a write error occured, and hence cause it to
+ * fall back to doing a synchronous write.
+ */
+static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
+{
+       int have_error, status;
+       int ret = 0;
+
+       have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+       status = nfs_wb_all(inode);
+       have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+       if (have_error)
+               ret = xchg(&ctx->error, 0);
+       if (!ret)
+               ret = status;
+       return ret;
+}
+
 /*
  * Flush all dirty pages, and check for write errors.
  *
@@ -180,7 +208,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
 static int
 nfs_file_flush(struct file *file, fl_owner_t id)
 {
-       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+       struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode    *inode = file->f_path.dentry->d_inode;
        int             status;
 
@@ -189,16 +217,11 @@ nfs_file_flush(struct file *file, fl_owner_t id)
        if ((file->f_mode & FMODE_WRITE) == 0)
                return 0;
        nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
-       lock_kernel();
+
        /* Ensure that data+attribute caches are up to date after close() */
-       status = nfs_wb_all(inode);
-       if (!status) {
-               status = ctx->error;
-               ctx->error = 0;
-               if (!status)
-                       nfs_revalidate_inode(NFS_SERVER(inode), inode);
-       }
-       unlock_kernel();
+       status = nfs_do_fsync(ctx, inode);
+       if (!status)
+               nfs_revalidate_inode(NFS_SERVER(inode), inode);
        return status;
 }
 
@@ -257,8 +280,11 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
        status = nfs_revalidate_mapping(inode, file->f_mapping);
-       if (!status)
-               status = generic_file_mmap(file, vma);
+       if (!status) {
+               vma->vm_ops = &nfs_file_vm_ops;
+               vma->vm_flags |= VM_CAN_NONLINEAR;
+               file_accessed(file);
+       }
        return status;
 }
 
@@ -270,21 +296,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
 static int
 nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
-       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+       struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode *inode = dentry->d_inode;
-       int status;
 
        dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
 
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
-       lock_kernel();
-       status = nfs_wb_all(inode);
-       if (!status) {
-               status = ctx->error;
-               ctx->error = 0;
-       }
-       unlock_kernel();
-       return status;
+       return nfs_do_fsync(ctx, inode);
 }
 
 /*
@@ -333,7 +351,7 @@ static int nfs_launder_page(struct page *page)
 const struct address_space_operations nfs_file_aops = {
        .readpage = nfs_readpage,
        .readpages = nfs_readpages,
-       .set_page_dirty = nfs_set_page_dirty,
+       .set_page_dirty = __set_page_dirty_nobuffers,
        .writepage = nfs_writepage,
        .writepages = nfs_writepages,
        .prepare_write = nfs_prepare_write,
@@ -346,6 +364,43 @@ const struct address_space_operations nfs_file_aops = {
        .launder_page = nfs_launder_page,
 };
 
+static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+       struct file *filp = vma->vm_file;
+       unsigned pagelen;
+       int ret = -EINVAL;
+
+       lock_page(page);
+       if (page->mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping)
+               goto out_unlock;
+       pagelen = nfs_page_length(page);
+       if (pagelen == 0)
+               goto out_unlock;
+       ret = nfs_prepare_write(filp, page, 0, pagelen);
+       if (!ret)
+               ret = nfs_commit_write(filp, page, 0, pagelen);
+out_unlock:
+       unlock_page(page);
+       return ret;
+}
+
+static struct vm_operations_struct nfs_file_vm_ops = {
+       .fault = filemap_fault,
+       .page_mkwrite = nfs_vm_page_mkwrite,
+};
+
+static int nfs_need_sync_write(struct file *filp, struct inode *inode)
+{
+       struct nfs_open_context *ctx;
+
+       if (IS_SYNC(inode) || (filp->f_flags & O_SYNC))
+               return 1;
+       ctx = nfs_file_open_context(filp);
+       if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags))
+               return 1;
+       return 0;
+}
+
 static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos)
 {
@@ -382,8 +437,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
        nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
        result = generic_file_aio_write(iocb, iov, nr_segs, pos);
        /* Return error values for O_SYNC and IS_SYNC() */
-       if (result >= 0 && (IS_SYNC(inode) || (iocb->ki_filp->f_flags & O_SYNC))) {
-               int err = nfs_fsync(iocb->ki_filp, dentry, 1);
+       if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
+               int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode);
                if (err < 0)
                        result = err;
        }
index 71a49c3acabdb26d941fb5fea5ce41e23e72ff2b..035c769b715e8e256693402b260663fd17945514 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
+#define NFS_64_BIT_INODE_NUMBERS_ENABLED       1
+
+/* Default is to see 64-bit inode numbers */
+static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
+
 static void nfs_invalidate_inode(struct inode *);
 static int nfs_update_inode(struct inode *, struct nfs_fattr *);
 
@@ -62,6 +67,25 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
        return nfs_fileid_to_ino_t(fattr->fileid);
 }
 
+/**
+ * nfs_compat_user_ino64 - returns the user-visible inode number
+ * @fileid: 64-bit fileid
+ *
+ * This function returns a 32-bit inode number if the boot parameter
+ * nfs.enable_ino64 is zero.
+ */
+u64 nfs_compat_user_ino64(u64 fileid)
+{
+       int ino;
+
+       if (enable_ino64)
+               return fileid;
+       ino = fileid;
+       if (sizeof(ino) < sizeof(fileid))
+               ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8;
+       return ino;
+}
+
 int nfs_write_inode(struct inode *inode, int sync)
 {
        int ret;
@@ -85,7 +109,6 @@ void nfs_clear_inode(struct inode *inode)
         */
        BUG_ON(nfs_have_writebacks(inode));
        BUG_ON(!list_empty(&NFS_I(inode)->open_files));
-       BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0);
        nfs_zap_acl_cache(inode);
        nfs_access_zap_cache(inode);
 }
@@ -118,8 +141,8 @@ static void nfs_zap_caches_locked(struct inode *inode)
 
        nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
 
-       NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
-       NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+       nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
+       nfsi->attrtimeo_timestamp = jiffies;
 
        memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
        if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
@@ -156,6 +179,13 @@ static void nfs_zap_acl_cache(struct inode *inode)
        spin_unlock(&inode->i_lock);
 }
 
+void nfs_invalidate_atime(struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
+       spin_unlock(&inode->i_lock);
+}
+
 /*
  * Invalidate, but do not unhash, the inode.
  * NB: must be called with inode->i_lock held!
@@ -338,7 +368,6 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
                return 0;
 
        lock_kernel();
-       nfs_begin_data_update(inode);
        /* Write all dirty data */
        if (S_ISREG(inode->i_mode)) {
                filemap_write_and_wait(inode->i_mapping);
@@ -352,7 +381,6 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
        error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
        if (error == 0)
                nfs_refresh_inode(inode, &fattr);
-       nfs_end_data_update(inode);
        unlock_kernel();
        return error;
 }
@@ -431,7 +459,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 
        /* Flush out writes to the server in order to update c/mtime */
        if (S_ISREG(inode->i_mode))
-               nfs_sync_mapping_range(inode->i_mapping, 0, 0, FLUSH_NOCOMMIT);
+               nfs_wb_nocommit(inode);
 
        /*
         * We may force a getattr if the user cares about atime.
@@ -450,8 +478,10 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
                err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
        else
                err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
-       if (!err)
+       if (!err) {
                generic_fillattr(inode, stat);
+               stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
+       }
        return err;
 }
 
@@ -536,7 +566,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
 static void nfs_file_clear_open_context(struct file *filp)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
-       struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
+       struct nfs_open_context *ctx = nfs_file_open_context(filp);
 
        if (ctx) {
                filp->private_data = NULL;
@@ -598,16 +628,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        status = nfs_wait_on_inode(inode);
        if (status < 0)
                goto out;
-       if (NFS_STALE(inode)) {
-               status = -ESTALE;
-               /* Do we trust the cached ESTALE? */
-               if (NFS_ATTRTIMEO(inode) != 0) {
-                       if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME)) {
-                               /* no */
-                       } else
-                               goto out;
-               }
-       }
+
+       status = -ESTALE;
+       if (NFS_STALE(inode))
+               goto out;
 
        status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
        if (status != 0) {
@@ -654,7 +678,7 @@ int nfs_attribute_timeout(struct inode *inode)
 
        if (nfs_have_delegation(inode, FMODE_READ))
                return 0;
-       return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
+       return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
 }
 
 /**
@@ -683,11 +707,8 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa
        }
        spin_lock(&inode->i_lock);
        nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
-       if (S_ISDIR(inode->i_mode)) {
+       if (S_ISDIR(inode->i_mode))
                memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
-               /* This ensures we revalidate child dentries */
-               nfsi->cache_change_attribute = jiffies;
-       }
        spin_unlock(&inode->i_lock);
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
        dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
@@ -756,56 +777,27 @@ out:
        return ret;
 }
 
-/**
- * nfs_begin_data_update
- * @inode - pointer to inode
- * Declare that a set of operations will update file data on the server
- */
-void nfs_begin_data_update(struct inode *inode)
-{
-       atomic_inc(&NFS_I(inode)->data_updates);
-}
-
-/**
- * nfs_end_data_update
- * @inode - pointer to inode
- * Declare end of the operations that will update file data
- * This will mark the inode as immediately needing revalidation
- * of its attribute cache.
- */
-void nfs_end_data_update(struct inode *inode)
-{
-       struct nfs_inode *nfsi = NFS_I(inode);
-
-       /* Directories: invalidate page cache */
-       if (S_ISDIR(inode->i_mode)) {
-               spin_lock(&inode->i_lock);
-               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
-               spin_unlock(&inode->i_lock);
-       }
-       nfsi->cache_change_attribute = jiffies;
-       atomic_dec(&nfsi->data_updates);
-}
-
 static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       unsigned long now = jiffies;
 
+       if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
+                       nfsi->change_attr == fattr->pre_change_attr) {
+               nfsi->change_attr = fattr->change_attr;
+               if (S_ISDIR(inode->i_mode))
+                       nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+       }
        /* If we have atomic WCC data, we may update some attributes */
        if ((fattr->valid & NFS_ATTR_WCC) != 0) {
-               if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
+               if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
                        memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-                       nfsi->cache_change_attribute = now;
-               }
                if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
                        memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-                       nfsi->cache_change_attribute = now;
+                       if (S_ISDIR(inode->i_mode))
+                               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
                }
-               if (inode->i_size == fattr->pre_size && nfsi->npages == 0) {
+               if (inode->i_size == fattr->pre_size && nfsi->npages == 0)
                        inode->i_size = fattr->size;
-                       nfsi->cache_change_attribute = now;
-               }
        }
 }
 
@@ -822,7 +814,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t cur_size, new_isize;
-       int data_unstable;
+       unsigned long invalid = 0;
 
 
        /* Has the inode gone and changed behind our back? */
@@ -831,37 +823,41 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
                return -EIO;
        }
 
-       /* Are we in the process of updating data on the server? */
-       data_unstable = nfs_caches_unstable(inode);
-
        /* Do atomic weak cache consistency updates */
        nfs_wcc_update_inode(inode, fattr);
 
        if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
                        nfsi->change_attr != fattr->change_attr)
-               nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
        /* Verify a few of the more important attributes */
        if (!timespec_equal(&inode->i_mtime, &fattr->mtime))
-               nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
        cur_size = i_size_read(inode);
        new_isize = nfs_size_to_loff_t(fattr->size);
        if (cur_size != new_isize && nfsi->npages == 0)
-               nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
        /* Have any file permissions changed? */
        if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
                        || inode->i_uid != fattr->uid
                        || inode->i_gid != fattr->gid)
-               nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
+               invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
 
        /* Has the link count changed? */
        if (inode->i_nlink != fattr->nlink)
-               nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
+               invalid |= NFS_INO_INVALID_ATTR;
 
        if (!timespec_equal(&inode->i_atime, &fattr->atime))
-               nfsi->cache_validity |= NFS_INO_INVALID_ATIME;
+               invalid |= NFS_INO_INVALID_ATIME;
+
+       if (invalid != 0)
+               nfsi->cache_validity |= invalid;
+       else
+               nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
+                               | NFS_INO_INVALID_ATIME
+                               | NFS_INO_REVAL_PAGECACHE);
 
        nfsi->read_cache_jiffies = fattr->time_start;
        return 0;
@@ -911,17 +907,41 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       int status = 0;
 
        spin_lock(&inode->i_lock);
-       if (unlikely((fattr->valid & NFS_ATTR_FATTR) == 0)) {
-               nfsi->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
-               goto out;
-       }
-       status = nfs_update_inode(inode, fattr);
-out:
+       nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+       if (S_ISDIR(inode->i_mode))
+               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
        spin_unlock(&inode->i_lock);
-       return status;
+       return nfs_refresh_inode(inode, fattr);
+}
+
+/**
+ * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
+ *
+ * After an operation that has changed the inode metadata, mark the
+ * attribute cache as being invalid, then try to update it. Fake up
+ * weak cache consistency data, if none exist.
+ *
+ * This function is mainly designed to be used by the ->write_done() functions.
+ */
+int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+{
+       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+                       (fattr->valid & NFS_ATTR_WCC_V4) == 0) {
+               fattr->pre_change_attr = NFS_I(inode)->change_attr;
+               fattr->valid |= NFS_ATTR_WCC_V4;
+       }
+       if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
+                       (fattr->valid & NFS_ATTR_WCC) == 0) {
+               memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
+               memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
+               fattr->pre_size = inode->i_size;
+               fattr->valid |= NFS_ATTR_WCC;
+       }
+       return nfs_post_op_update_inode(inode, fattr);
 }
 
 /*
@@ -941,9 +961,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        struct nfs_server *server;
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t cur_isize, new_isize;
-       unsigned int    invalid = 0;
+       unsigned long invalid = 0;
        unsigned long now = jiffies;
-       int data_stable;
 
        dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
                        __FUNCTION__, inode->i_sb->s_id, inode->i_ino,
@@ -968,57 +987,51 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
         * Update the read time so we don't revalidate too often.
         */
        nfsi->read_cache_jiffies = fattr->time_start;
-       nfsi->last_updated = now;
 
-       /* Fix a wraparound issue with nfsi->cache_change_attribute */
-       if (time_before(now, nfsi->cache_change_attribute))
-               nfsi->cache_change_attribute = now - 600*HZ;
-
-       /* Are we racing with known updates of the metadata on the server? */
-       data_stable = nfs_verify_change_attribute(inode, fattr->time_start);
-       if (data_stable)
-               nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATIME);
+       nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME
+                       | NFS_INO_REVAL_PAGECACHE);
 
        /* Do atomic weak cache consistency updates */
        nfs_wcc_update_inode(inode, fattr);
 
+       /* More cache consistency checks */
+       if (!(fattr->valid & NFS_ATTR_FATTR_V4)) {
+               /* NFSv2/v3: Check if the mtime agrees */
+               if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
+                       dprintk("NFS: mtime change on server for file %s/%ld\n",
+                                       inode->i_sb->s_id, inode->i_ino);
+                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+                       nfsi->cache_change_attribute = now;
+               }
+               /* If ctime has changed we should definitely clear access+acl caches */
+               if (!timespec_equal(&inode->i_ctime, &fattr->ctime))
+                       invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+       } else if (nfsi->change_attr != fattr->change_attr) {
+               dprintk("NFS: change_attr change on server for file %s/%ld\n",
+                               inode->i_sb->s_id, inode->i_ino);
+               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               nfsi->cache_change_attribute = now;
+       }
+
        /* Check if our cached file size is stale */
        new_isize = nfs_size_to_loff_t(fattr->size);
        cur_isize = i_size_read(inode);
        if (new_isize != cur_isize) {
-               /* Do we perhaps have any outstanding writes? */
-               if (nfsi->npages == 0) {
-                       /* No, but did we race with nfs_end_data_update()? */
-                       if (data_stable) {
-                               inode->i_size = new_isize;
-                               invalid |= NFS_INO_INVALID_DATA;
-                       }
-                       invalid |= NFS_INO_INVALID_ATTR;
-               } else if (new_isize > cur_isize) {
+               /* Do we perhaps have any outstanding writes, or has
+                * the file grown beyond our last write? */
+               if (nfsi->npages == 0 || new_isize > cur_isize) {
                        inode->i_size = new_isize;
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                }
-               nfsi->cache_change_attribute = now;
                dprintk("NFS: isize change on server for file %s/%ld\n",
                                inode->i_sb->s_id, inode->i_ino);
        }
 
-       /* Check if the mtime agrees */
-       if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
-               memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-               dprintk("NFS: mtime change on server for file %s/%ld\n",
-                               inode->i_sb->s_id, inode->i_ino);
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
-               nfsi->cache_change_attribute = now;
-       }
 
-       /* If ctime has changed we should definitely clear access+acl caches */
-       if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
-               invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-               memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-               nfsi->cache_change_attribute = now;
-       }
+       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
        memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
+       nfsi->change_attr = fattr->change_attr;
 
        if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
            inode->i_uid != fattr->uid ||
@@ -1039,31 +1052,29 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                inode->i_blocks = fattr->du.nfs2.blocks;
        }
 
-       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
-                       nfsi->change_attr != fattr->change_attr) {
-               dprintk("NFS: change_attr change on server for file %s/%ld\n",
-                               inode->i_sb->s_id, inode->i_ino);
-               nfsi->change_attr = fattr->change_attr;
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-               nfsi->cache_change_attribute = now;
-       }
-
        /* Update attrtimeo value if we're out of the unstable period */
        if (invalid & NFS_INO_INVALID_ATTR) {
                nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
-       } else if (time_after(now, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
-               if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
-                       nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
-               nfsi->attrtimeo_timestamp = now;
+               nfsi->last_updated = now;
+       } else {
+               if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
+                       if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
+                               nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
+                       nfsi->attrtimeo_timestamp = now;
+               }
+               /*
+                * Avoid jiffy wraparound issues with nfsi->last_updated
+                */
+               if (!time_in_range(nfsi->last_updated, nfsi->read_cache_jiffies, now))
+                       nfsi->last_updated = nfsi->read_cache_jiffies;
        }
+       invalid &= ~NFS_INO_INVALID_ATTR;
        /* Don't invalidate the data if we were to blame */
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
                                || S_ISLNK(inode->i_mode)))
                invalid &= ~NFS_INO_INVALID_DATA;
-       if (data_stable)
-               invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE);
        if (!nfs_have_delegation(inode, FMODE_READ) ||
                        (nfsi->cache_validity & NFS_INO_REVAL_FORCED))
                nfsi->cache_validity |= invalid;
@@ -1152,7 +1163,6 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
        INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
        INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
        INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
-       atomic_set(&nfsi->data_updates, 0);
        nfsi->ncommit = 0;
        nfsi->npages = 0;
        nfs4_init_once(nfsi);
@@ -1249,6 +1259,7 @@ static void __exit exit_nfs_fs(void)
 /* Not quite true; I just maintain it */
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
 MODULE_LICENSE("GPL");
+module_param(enable_ino64, bool, 0644);
 
 module_init(init_nfs_fs)
 module_exit(exit_nfs_fs)
index 76cf55d57101ab5b2cf3acfac638684e27bb6543..f3acf48412be78dda1b26ce06e348e2b4ed38e87 100644 (file)
@@ -5,8 +5,6 @@
 #include <linux/mount.h>
 
 struct nfs_string;
-struct nfs_mount_data;
-struct nfs4_mount_data;
 
 /* Maximum number of readahead requests
  * FIXME: this should really be a sysctl so that users may tune it to suit
@@ -27,20 +25,50 @@ struct nfs_clone_mount {
        rpc_authflavor_t authflavor;
 };
 
+/*
+ * In-kernel mount arguments
+ */
+struct nfs_parsed_mount_data {
+       int                     flags;
+       int                     rsize, wsize;
+       int                     timeo, retrans;
+       int                     acregmin, acregmax,
+                               acdirmin, acdirmax;
+       int                     namlen;
+       unsigned int            bsize;
+       unsigned int            auth_flavor_len;
+       rpc_authflavor_t        auth_flavors[1];
+       char                    *client_address;
+
+       struct {
+               struct sockaddr_in      address;
+               char                    *hostname;
+               unsigned int            program;
+               unsigned int            version;
+               unsigned short          port;
+               int                     protocol;
+       } mount_server;
+
+       struct {
+               struct sockaddr_in      address;
+               char                    *hostname;
+               char                    *export_path;
+               unsigned int            program;
+               int                     protocol;
+       } nfs_server;
+};
+
 /* client.c */
 extern struct rpc_program nfs_program;
 
 extern void nfs_put_client(struct nfs_client *);
 extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
-extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *,
-                                           struct nfs_fh *);
-extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *,
-                                            const char *,
-                                            const struct sockaddr_in *,
-                                            const char *,
-                                            const char *,
-                                            rpc_authflavor_t,
-                                            struct nfs_fh *);
+extern struct nfs_server *nfs_create_server(
+                                       const struct nfs_parsed_mount_data *,
+                                       struct nfs_fh *);
+extern struct nfs_server *nfs4_create_server(
+                                       const struct nfs_parsed_mount_data *,
+                                       struct nfs_fh *);
 extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
                                                      struct nfs_fh *);
 extern void nfs_free_server(struct nfs_server *server);
index c5fce756720060e4dbd2b61b8123d35000cc43ff..668ab96c7b596f19c2550c034cbea48f0706ae93 100644 (file)
@@ -251,6 +251,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
        xdr_inline_pages(&req->rq_rcv_buf, replen,
                         args->pages, args->pgbase, count);
+       req->rq_rcv_buf.flags |= XDRBUF_READ;
        return 0;
 }
 
@@ -271,7 +272,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
        res->eof = 0;
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        if (iov->iov_len < hdrlen) {
-               printk(KERN_WARNING "NFS: READ reply header overflowed:"
+               dprintk("NFS: READ reply header overflowed:"
                                "length %d > %Zu\n", hdrlen, iov->iov_len);
                return -errno_NFSERR_IO;
        } else if (iov->iov_len != hdrlen) {
@@ -281,7 +282,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
 
        recvd = req->rq_rcv_buf.len - hdrlen;
        if (count > recvd) {
-               printk(KERN_WARNING "NFS: server cheating in read reply: "
+               dprintk("NFS: server cheating in read reply: "
                        "count %d > recvd %d\n", count, recvd);
                count = recvd;
        }
@@ -313,6 +314,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 
        /* Copy the page array */
        xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
+       sndbuf->flags |= XDRBUF_WRITE;
        return 0;
 }
 
@@ -431,7 +433,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
 
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        if (iov->iov_len < hdrlen) {
-               printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
+               dprintk("NFS: READDIR reply header overflowed:"
                                "length %d > %Zu\n", hdrlen, iov->iov_len);
                return -errno_NFSERR_IO;
        } else if (iov->iov_len != hdrlen) {
@@ -454,7 +456,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
                len = ntohl(*p++);
                p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
                if (len > NFS2_MAXNAMLEN) {
-                       printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
+                       dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
                                                len);
                        goto err_unmap;
                }
@@ -471,7 +473,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
        entry[0] = entry[1] = 0;
        /* truncate listing ? */
        if (!nr) {
-               printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+               dprintk("NFS: readdir reply truncated!\n");
                entry[1] = 1;
        }
        goto out;
@@ -583,12 +585,12 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
        /* Convert length of symlink */
        len = ntohl(*p++);
        if (len >= rcvbuf->page_len || len <= 0) {
-               dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
+               dprintk("nfs: server returned giant symlink!\n");
                return -ENAMETOOLONG;
        }
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        if (iov->iov_len < hdrlen) {
-               printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
+               dprintk("NFS: READLINK reply header overflowed:"
                                "length %d > %Zu\n", hdrlen, iov->iov_len);
                return -errno_NFSERR_IO;
        } else if (iov->iov_len != hdrlen) {
@@ -597,7 +599,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
        }
        recvd = req->rq_rcv_buf.len - hdrlen;
        if (recvd < len) {
-               printk(KERN_WARNING "NFS: server cheating in readlink reply: "
+               dprintk("NFS: server cheating in readlink reply: "
                                "count %u > recvd %u\n", len, recvd);
                return -EIO;
        }
@@ -695,7 +697,7 @@ nfs_stat_to_errno(int stat)
                if (nfs_errtbl[i].stat == stat)
                        return nfs_errtbl[i].errno;
        }
-       printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
+       dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
        return nfs_errtbl[i].errno;
 }
 
index 7322da4d2055a76b1c9097181241a9bbf8023d9d..9b7362565c0c3b9b8c5dc1610a2c354305ae4999 100644 (file)
@@ -317,13 +317,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
        }
 
        dprintk("NFS call setacl\n");
-       nfs_begin_data_update(inode);
        msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
        status = rpc_call_sync(server->client_acl, &msg, 0);
        spin_lock(&inode->i_lock);
        NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS;
        spin_unlock(&inode->i_lock);
-       nfs_end_data_update(inode);
        dprintk("NFS reply setacl: %d\n", status);
 
        /* pages may have been allocated at the xdr layer. */
index c7ca5d70870bc7eaeccb53d0b2d752580d9e6c6b..4cdc2361a669bed2347d599f027cc10e57c9d7dc 100644 (file)
@@ -166,6 +166,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
        nfs_fattr_init(&dir_attr);
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+       nfs_refresh_inode(dir, &dir_attr);
        if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) {
                msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
                msg.rpc_argp = fhandle;
@@ -173,8 +174,6 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
                status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
        }
        dprintk("NFS reply lookup: %d\n", status);
-       if (status >= 0)
-               status = nfs_refresh_inode(dir, &dir_attr);
        return status;
 }
 
@@ -607,6 +606,9 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 
        nfs_fattr_init(&dir_attr);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+
+       nfs_invalidate_atime(dir);
+
        nfs_refresh_inode(dir, &dir_attr);
        dprintk("NFS reply readdir: %d\n", status);
        return status;
@@ -724,9 +726,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
 {
        if (nfs3_async_handle_jukebox(task, data->inode))
                return -EAGAIN;
-       /* Call back common NFS readpage processing */
-       if (task->tk_status >= 0)
-               nfs_refresh_inode(data->inode, &data->fattr);
+
+       nfs_invalidate_atime(data->inode);
+       nfs_refresh_inode(data->inode, &data->fattr);
        return 0;
 }
 
@@ -747,7 +749,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
        if (nfs3_async_handle_jukebox(task, data->inode))
                return -EAGAIN;
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode(data->inode, data->res.fattr);
+               nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
        return 0;
 }
 
@@ -775,8 +777,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (nfs3_async_handle_jukebox(task, data->inode))
                return -EAGAIN;
-       if (task->tk_status >= 0)
-               nfs_post_op_update_inode(data->inode, data->res.fattr);
+       nfs_refresh_inode(data->inode, data->res.fattr);
        return 0;
 }
 
index d9e08f0cf2a057aa2f903781c33adc86839aaf7f..616d3267b7e7b545d02d0bb88c02a48e2cbe6e80 100644 (file)
@@ -346,6 +346,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
        xdr_inline_pages(&req->rq_rcv_buf, replen,
                         args->pages, args->pgbase, count);
+       req->rq_rcv_buf.flags |= XDRBUF_READ;
        return 0;
 }
 
@@ -367,6 +368,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 
        /* Copy the page array */
        xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
+       sndbuf->flags |= XDRBUF_WRITE;
        return 0;
 }
 
@@ -524,7 +526,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
 
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        if (iov->iov_len < hdrlen) {
-               printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
+               dprintk("NFS: READDIR reply header overflowed:"
                                "length %d > %Zu\n", hdrlen, iov->iov_len);
                return -errno_NFSERR_IO;
        } else if (iov->iov_len != hdrlen) {
@@ -547,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
                len = ntohl(*p++);              /* string length */
                p += XDR_QUADLEN(len) + 2;      /* name + cookie */
                if (len > NFS3_MAXNAMLEN) {
-                       printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
+                       dprintk("NFS: giant filename in readdir (len %x)!\n",
                                                len);
                        goto err_unmap;
                }
@@ -567,7 +569,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
                                        goto short_pkt;
                                len = ntohl(*p++);
                                if (len > NFS3_FHSIZE) {
-                                       printk(KERN_WARNING "NFS: giant filehandle in "
+                                       dprintk("NFS: giant filehandle in "
                                                "readdir (len %x)!\n", len);
                                        goto err_unmap;
                                }
@@ -588,7 +590,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
        entry[0] = entry[1] = 0;
        /* truncate listing ? */
        if (!nr) {
-               printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+               dprintk("NFS: readdir reply truncated!\n");
                entry[1] = 1;
        }
        goto out;
@@ -826,22 +828,23 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
        /* Convert length of symlink */
        len = ntohl(*p++);
        if (len >= rcvbuf->page_len || len <= 0) {
-               dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
+               dprintk("nfs: server returned giant symlink!\n");
                return -ENAMETOOLONG;
        }
 
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        if (iov->iov_len < hdrlen) {
-               printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
+               dprintk("NFS: READLINK reply header overflowed:"
                                "length %d > %Zu\n", hdrlen, iov->iov_len);
                return -errno_NFSERR_IO;
        } else if (iov->iov_len != hdrlen) {
-               dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
+               dprintk("NFS: READLINK header is short. "
+                       "iovec will be shifted.\n");
                xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
        }
        recvd = req->rq_rcv_buf.len - hdrlen;
        if (recvd < len) {
-               printk(KERN_WARNING "NFS: server cheating in readlink reply: "
+               dprintk("NFS: server cheating in readlink reply: "
                                "count %u > recvd %u\n", len, recvd);
                return -EIO;
        }
@@ -876,13 +879,13 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
        ocount   = ntohl(*p++);
 
        if (ocount != count) {
-               printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
+               dprintk("NFS: READ count doesn't match RPC opaque count.\n");
                return -errno_NFSERR_IO;
        }
 
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        if (iov->iov_len < hdrlen) {
-               printk(KERN_WARNING "NFS: READ reply header overflowed:"
+               dprintk("NFS: READ reply header overflowed:"
                                "length %d > %Zu\n", hdrlen, iov->iov_len);
                        return -errno_NFSERR_IO;
        } else if (iov->iov_len != hdrlen) {
@@ -892,7 +895,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
 
        recvd = req->rq_rcv_buf.len - hdrlen;
        if (count > recvd) {
-               printk(KERN_WARNING "NFS: server cheating in read reply: "
+               dprintk("NFS: server cheating in read reply: "
                        "count %d > recvd %d\n", count, recvd);
                count = recvd;
                res->eof = 0;
index 4b90e17555a99fa35bf7a607a532510992e256d7..cb99fd90a9acc5147135bb70846517ad8e79165e 100644 (file)
@@ -62,10 +62,8 @@ struct nfs4_opendata;
 static int _nfs4_proc_open(struct nfs4_opendata *data);
 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
-static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
 static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
 static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
-static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags);
 static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 
@@ -177,7 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
                *p++ = xdr_one;                         /* bitmap length */
                *p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
                *p++ = htonl(8);              /* attribute buffer length */
-               p = xdr_encode_hyper(p, dentry->d_inode->i_ino);
+               p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
        }
        
        *p++ = xdr_one;                                  /* next */
@@ -189,7 +187,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
        *p++ = xdr_one;                         /* bitmap length */
        *p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
        *p++ = htonl(8);              /* attribute buffer length */
-       p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino);
+       p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
 
        readdir->pgbase = (char *)p - (char *)start;
        readdir->count -= readdir->pgbase;
@@ -211,8 +209,9 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
 
        spin_lock(&dir->i_lock);
        nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
-       if (cinfo->before == nfsi->change_attr && cinfo->atomic)
-               nfsi->change_attr = cinfo->after;
+       if (!cinfo->atomic || cinfo->before != nfsi->change_attr)
+               nfsi->cache_change_attribute = jiffies;
+       nfsi->change_attr = cinfo->after;
        spin_unlock(&dir->i_lock);
 }
 
@@ -454,7 +453,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
                memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
                rcu_read_unlock();
                lock_kernel();
-               ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode);
+               ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
                unlock_kernel();
                if (ret != 0)
                        goto out;
@@ -948,36 +947,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
        return 0;
 }
 
-static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags)
-{
-       struct nfs_access_entry cache;
-       int mask = 0;
-       int status;
-
-       if (openflags & FMODE_READ)
-               mask |= MAY_READ;
-       if (openflags & FMODE_WRITE)
-               mask |= MAY_WRITE;
-       if (openflags & FMODE_EXEC)
-               mask |= MAY_EXEC;
-       status = nfs_access_get_cached(inode, cred, &cache);
-       if (status == 0)
-               goto out;
-
-       /* Be clever: ask server to check for all possible rights */
-       cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
-       cache.cred = cred;
-       cache.jiffies = jiffies;
-       status = _nfs4_proc_access(inode, &cache);
-       if (status != 0)
-               return status;
-       nfs_access_add_cache(inode, &cache);
-out:
-       if ((cache.mask & mask) == mask)
-               return 0;
-       return -EACCES;
-}
-
 static int nfs4_recover_expired_lease(struct nfs_server *server)
 {
        struct nfs_client *clp = server->nfs_client;
@@ -1381,7 +1350,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
 
        /* If the open_intent is for execute, we have an extra check to make */
        if (nd->intent.open.flags & FMODE_EXEC) {
-               ret = _nfs4_do_access(state->inode,
+               ret = nfs_may_open(state->inode,
                                state->owner->so_cred,
                                nd->intent.open.flags);
                if (ret < 0)
@@ -1390,7 +1359,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
        filp = lookup_instantiate_filp(nd, path->dentry, NULL);
        if (!IS_ERR(filp)) {
                struct nfs_open_context *ctx;
-               ctx = (struct nfs_open_context *)filp->private_data;
+               ctx = nfs_file_open_context(filp);
                ctx->state = state;
                return 0;
        }
@@ -1428,13 +1397,16 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
        state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
        put_rpccred(cred);
        if (IS_ERR(state)) {
-               if (PTR_ERR(state) == -ENOENT)
+               if (PTR_ERR(state) == -ENOENT) {
                        d_add(dentry, NULL);
+                       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+               }
                return (struct dentry *)state;
        }
        res = d_add_unique(dentry, igrab(state->inode));
        if (res != NULL)
                path.dentry = res;
+       nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
        nfs4_intent_set_file(nd, &path, state);
        return res;
 }
@@ -1468,6 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
                }
        }
        if (state->inode == dentry->d_inode) {
+               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                nfs4_intent_set_file(nd, &path, state);
                return 1;
        }
@@ -1757,10 +1730,16 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh
 
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
 {
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct nfs_fattr fattr;
        struct nfs4_accessargs args = {
                .fh = NFS_FH(inode),
+               .bitmask = server->attr_bitmask,
+       };
+       struct nfs4_accessres res = {
+               .server = server,
+               .fattr = &fattr,
        };
-       struct nfs4_accessres res = { 0 };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
                .rpc_argp = &args,
@@ -1786,6 +1765,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
                if (mode & MAY_EXEC)
                        args.access |= NFS4_ACCESS_EXECUTE;
        }
+       nfs_fattr_init(&fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        if (!status) {
                entry->mask = 0;
@@ -1795,6 +1775,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
                        entry->mask |= MAY_WRITE;
                if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
                        entry->mask |= MAY_EXEC;
+               nfs_refresh_inode(inode, &fattr);
        }
        return status;
 }
@@ -1900,11 +1881,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        }
        state = nfs4_do_open(dir, &path, flags, sattr, cred);
        put_rpccred(cred);
+       d_drop(dentry);
        if (IS_ERR(state)) {
                status = PTR_ERR(state);
                goto out;
        }
-       d_instantiate(dentry, igrab(state->inode));
+       d_add(dentry, igrab(state->inode));
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        if (flags & O_EXCL) {
                struct nfs_fattr fattr;
                status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
@@ -2218,6 +2201,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
        if (status == 0)
                memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
+
+       nfs_invalidate_atime(dir);
+
        dprintk("%s: returns %d\n", __FUNCTION__, status);
        return status;
 }
@@ -2414,6 +2400,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
                rpc_restart_call(task);
                return -EAGAIN;
        }
+
+       nfs_invalidate_atime(data->inode);
        if (task->tk_status > 0)
                renew_lease(server, data->timestamp);
        return 0;
@@ -2443,7 +2431,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
        }
        if (task->tk_status >= 0) {
                renew_lease(NFS_SERVER(inode), data->timestamp);
-               nfs_post_op_update_inode(inode, data->res.fattr);
+               nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
        }
        return 0;
 }
@@ -2485,8 +2473,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
                rpc_restart_call(task);
                return -EAGAIN;
        }
-       if (task->tk_status >= 0)
-               nfs_post_op_update_inode(inode, data->res.fattr);
+       nfs_refresh_inode(inode, data->res.fattr);
        return 0;
 }
 
@@ -3056,7 +3043,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        if (status == 0) {
                status = data->rpc_status;
                if (status == 0)
-                       nfs_post_op_update_inode(inode, &data->fattr);
+                       nfs_refresh_inode(inode, &data->fattr);
        }
        rpc_put_task(task);
        return status;
@@ -3303,7 +3290,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        status = -ENOMEM;
        if (seqid == NULL)
                goto out;
-       task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
+       task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
        status = PTR_ERR(task);
        if (IS_ERR(task))
                goto out;
@@ -3447,7 +3434,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
        int ret;
 
        dprintk("%s: begin!\n", __FUNCTION__);
-       data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data,
+       data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
                        fl->fl_u.nfs4_fl.owner);
        if (data == NULL)
                return -ENOMEM;
@@ -3573,7 +3560,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
        int status;
 
        /* verify open state */
-       ctx = (struct nfs_open_context *)filp->private_data;
+       ctx = nfs_file_open_context(filp);
        state = ctx->state;
 
        if (request->fl_start < 0 || request->fl_end < 0)
index 3e4adf8c831214aaa7ef56e4abce36a3ef10d439..bfb36261cecb2ba6a542690b20ab3a573789d5e1 100644 (file)
@@ -774,7 +774,7 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s
        for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
-               if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state)
+               if (nfs_file_open_context(fl->fl_file)->state != state)
                        continue;
                status = ops->recover_lock(state, fl);
                if (status >= 0)
index badd73b7ca124ea19a057f8016c6f54a42cf5e02..51dd3804866f1575adc3ceeda8a47162796e1bbe 100644 (file)
@@ -376,10 +376,12 @@ static int nfs4_stat_to_errno(int);
                                decode_locku_maxsz)
 #define NFS4_enc_access_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_access_maxsz)
+                               encode_access_maxsz + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_access_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_access_maxsz)
+                               decode_access_maxsz + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_getattr_sz    (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_getattr_maxsz)
@@ -562,7 +564,6 @@ struct compound_hdr {
 
 #define RESERVE_SPACE(nbytes)  do {                            \
        p = xdr_reserve_space(xdr, nbytes);                     \
-       if (!p) printk("RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \
        BUG_ON(!p);                                             \
 } while (0)
 
@@ -628,8 +629,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
        if (iap->ia_valid & ATTR_UID) {
                owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
                if (owner_namelen < 0) {
-                       printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
-                              iap->ia_uid);
+                       dprintk("nfs: couldn't resolve uid %d to string\n",
+                                       iap->ia_uid);
                        /* XXX */
                        strcpy(owner_name, "nobody");
                        owner_namelen = sizeof("nobody") - 1;
@@ -640,8 +641,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
        if (iap->ia_valid & ATTR_GID) {
                owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
                if (owner_grouplen < 0) {
-                       printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
-                              iap->ia_gid);
+                       dprintk("nfs: couldn't resolve gid %d to string\n",
+                                       iap->ia_gid);
                        strcpy(owner_group, "nobody");
                        owner_grouplen = sizeof("nobody") - 1;
                        /* goto out; */
@@ -711,7 +712,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
         * Now we backfill the bitmap and the attribute buffer length.
         */
        if (len != ((char *)p - (char *)q) + 4) {
-               printk ("encode_attr: Attr length calculation error! %u != %Zu\n",
+               printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
                                len, ((char *)p - (char *)q) + 4);
                BUG();
        }
@@ -1376,14 +1377,20 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 2,
+               .nops = 3,
        };
        int status;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
        encode_compound_hdr(&xdr, &hdr);
-       if ((status = encode_putfh(&xdr, args->fh)) == 0)
-               status = encode_access(&xdr, args->access);
+       status = encode_putfh(&xdr, args->fh);
+       if (status != 0)
+               goto out;
+       status = encode_access(&xdr, args->access);
+       if (status != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
+out:
        return status;
 }
 
@@ -1857,6 +1864,7 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg
        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
        xdr_inline_pages(&req->rq_rcv_buf, replen,
                         args->pages, args->pgbase, args->count);
+       req->rq_rcv_buf.flags |= XDRBUF_READ;
 out:
        return status;
 }
@@ -1933,6 +1941,7 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea
        status = encode_write(&xdr, args);
        if (status)
                goto out;
+       req->rq_snd_buf.flags |= XDRBUF_WRITE;
        status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
@@ -2180,9 +2189,9 @@ out:
 #define READ_BUF(nbytes)  do { \
        p = xdr_inline_decode(xdr, nbytes); \
        if (unlikely(!p)) { \
-               printk(KERN_INFO "%s: prematurely hit end of receive" \
+               dprintk("nfs: %s: prematurely hit end of receive" \
                                " buffer\n", __FUNCTION__); \
-               printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
+               dprintk("nfs: %s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
                                __FUNCTION__, xdr->p, nbytes, xdr->end); \
                return -EIO; \
        } \
@@ -2223,9 +2232,8 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
        READ_BUF(8);
        READ32(opnum);
        if (opnum != expected) {
-               printk(KERN_NOTICE
-                               "nfs4_decode_op_hdr: Server returned operation"
-                               " %d but we issued a request for %d\n",
+               dprintk("nfs: Server returned operation"
+                       " %d but we issued a request for %d\n",
                                opnum, expected);
                return -EIO;
        }
@@ -2758,7 +2766,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                                dprintk("%s: nfs_map_name_to_uid failed!\n",
                                                __FUNCTION__);
                } else
-                       printk(KERN_WARNING "%s: name too long (%u)!\n",
+                       dprintk("%s: name too long (%u)!\n",
                                        __FUNCTION__, len);
                bitmap[1] &= ~FATTR4_WORD1_OWNER;
        }
@@ -2783,7 +2791,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                                dprintk("%s: nfs_map_group_to_gid failed!\n",
                                                __FUNCTION__);
                } else
-                       printk(KERN_WARNING "%s: name too long (%u)!\n",
+                       dprintk("%s: name too long (%u)!\n",
                                        __FUNCTION__, len);
                bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
        }
@@ -2950,7 +2958,8 @@ static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrl
        unsigned int nwords = xdr->p - savep;
 
        if (unlikely(attrwords != nwords)) {
-               printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n",
+               dprintk("%s: server returned incorrect attribute length: "
+                       "%u %c %u\n",
                                __FUNCTION__,
                                attrwords << 2,
                                (attrwords < nwords) ? '<' : '>',
@@ -3451,7 +3460,7 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        recvd = req->rq_rcv_buf.len - hdrlen;
        if (count > recvd) {
-               printk(KERN_WARNING "NFS: server cheating in read reply: "
+               dprintk("NFS: server cheating in read reply: "
                                "count %u > recvd %u\n", count, recvd);
                count = recvd;
                eof = 0;
@@ -3500,7 +3509,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
                p += 2;                 /* cookie */
                len = ntohl(*p++);      /* filename length */
                if (len > NFS4_MAXNAMLEN) {
-                       printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
+                       dprintk("NFS: giant filename in readdir (len 0x%x)\n",
+                                       len);
                        goto err_unmap;
                }
                xlen = XDR_QUADLEN(len);
@@ -3528,7 +3538,7 @@ short_pkt:
        entry[0] = entry[1] = 0;
        /* truncate listing ? */
        if (!nr) {
-               printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+               dprintk("NFS: readdir reply truncated!\n");
                entry[1] = 1;
        }
        goto out;
@@ -3554,13 +3564,13 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
        READ_BUF(4);
        READ32(len);
        if (len >= rcvbuf->page_len || len <= 0) {
-               dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
+               dprintk("nfs: server returned giant symlink!\n");
                return -ENAMETOOLONG;
        }
        hdrlen = (char *) xdr->p - (char *) iov->iov_base;
        recvd = req->rq_rcv_buf.len - hdrlen;
        if (recvd < len) {
-               printk(KERN_WARNING "NFS: server cheating in readlink reply: "
+               dprintk("NFS: server cheating in readlink reply: "
                                "count %u > recvd %u\n", len, recvd);
                return -EIO;
        }
@@ -3643,7 +3653,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
                hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
                recvd = req->rq_rcv_buf.len - hdrlen;
                if (attrlen > recvd) {
-                       printk(KERN_WARNING "NFS: server cheating in getattr"
+                       dprintk("NFS: server cheating in getattr"
                                        " acl reply: attrlen %u > recvd %u\n",
                                        attrlen, recvd);
                        return -EINVAL;
@@ -3688,8 +3698,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
        READ_BUF(8);
        READ32(opnum);
        if (opnum != OP_SETCLIENTID) {
-               printk(KERN_NOTICE
-                               "nfs4_decode_setclientid: Server returned operation"
+               dprintk("nfs: decode_setclientid: Server returned operation"
                                " %d\n", opnum);
                return -EIO;
        }
@@ -3783,8 +3792,13 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac
        xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
        if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
                goto out;
-       if ((status = decode_putfh(&xdr)) == 0)
-               status = decode_access(&xdr, res);
+       status = decode_putfh(&xdr);
+       if (status != 0)
+               goto out;
+       status = decode_access(&xdr, res);
+       if (status != 0)
+               goto out;
+       decode_getfattr(&xdr, res->fattr, res->server);
 out:
        return status;
 }
index 3490322d11459f0023bc60d56da1bddc0c06b9c5..e87b44ee9ac9b0490e00de2dd420e4cb1bcebb46 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprtsock.h>
 #include <linux/nfs.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
@@ -491,7 +492,7 @@ static int __init root_nfs_get_handle(void)
        struct sockaddr_in sin;
        int status;
        int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
-                                       IPPROTO_TCP : IPPROTO_UDP;
+                                       XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP;
        int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
                                        NFS_MNT3_VERSION : NFS_MNT_VERSION;
 
index 845cdde1d8b742bee0d017f72e291c9c2ceb4e57..97669ed05500c6277387f1b0323d53b6face4950 100644 (file)
@@ -476,6 +476,8 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
        dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
+       nfs_invalidate_atime(dir);
+
        dprintk("NFS reply readdir: %d\n", status);
        return status;
 }
@@ -550,6 +552,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
 
 static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
 {
+       nfs_invalidate_atime(data->inode);
        if (task->tk_status >= 0) {
                nfs_refresh_inode(data->inode, data->res.fattr);
                /* Emulate the eof flag, which isn't normally needed in NFSv2
@@ -576,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data)
 static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode(data->inode, data->res.fattr);
+               nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
        return 0;
 }
 
index 19e05633f4e3463152b2867fcc2ac3f13e933b96..4587a86adaac8d5cc0762f36fbddaa3b96dc71f8 100644 (file)
@@ -341,9 +341,6 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
                set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode));
                nfs_mark_for_revalidate(data->inode);
        }
-       spin_lock(&data->inode->i_lock);
-       NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME;
-       spin_unlock(&data->inode->i_lock);
        return 0;
 }
 
@@ -497,8 +494,7 @@ int nfs_readpage(struct file *file, struct page *page)
                if (ctx == NULL)
                        goto out_unlock;
        } else
-               ctx = get_nfs_open_context((struct nfs_open_context *)
-                               file->private_data);
+               ctx = get_nfs_open_context(nfs_file_open_context(file));
 
        error = nfs_readpage_async(ctx, inode, page);
 
@@ -576,8 +572,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
                if (desc.ctx == NULL)
                        return -EBADF;
        } else
-               desc.ctx = get_nfs_open_context((struct nfs_open_context *)
-                               filp->private_data);
+               desc.ctx = get_nfs_open_context(nfs_file_open_context(filp));
        if (rsize < PAGE_CACHE_SIZE)
                nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
        else
index b878528b64c1a9d0aed22fd19b20339bc1644b22..fa517ae9207f6d04f66fcf4c0b12ef229bc5a176 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/metrics.h>
+#include <linux/sunrpc/xprtsock.h>
+#include <linux/sunrpc/xprtrdma.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
-
-struct nfs_parsed_mount_data {
-       int                     flags;
-       int                     rsize, wsize;
-       int                     timeo, retrans;
-       int                     acregmin, acregmax,
-                               acdirmin, acdirmax;
-       int                     namlen;
-       unsigned int            bsize;
-       unsigned int            auth_flavor_len;
-       rpc_authflavor_t        auth_flavors[1];
-       char                    *client_address;
-
-       struct {
-               struct sockaddr_in      address;
-               unsigned int            program;
-               unsigned int            version;
-               unsigned short          port;
-               int                     protocol;
-       } mount_server;
-
-       struct {
-               struct sockaddr_in      address;
-               char                    *hostname;
-               char                    *export_path;
-               unsigned int            program;
-               int                     protocol;
-       } nfs_server;
-};
-
 enum {
        /* Mount options that take no arguments */
        Opt_soft, Opt_hard,
@@ -97,7 +69,7 @@ enum {
        Opt_ac, Opt_noac,
        Opt_lock, Opt_nolock,
        Opt_v2, Opt_v3,
-       Opt_udp, Opt_tcp,
+       Opt_udp, Opt_tcp, Opt_rdma,
        Opt_acl, Opt_noacl,
        Opt_rdirplus, Opt_nordirplus,
        Opt_sharecache, Opt_nosharecache,
@@ -116,7 +88,7 @@ enum {
 
        /* Mount options that take string arguments */
        Opt_sec, Opt_proto, Opt_mountproto,
-       Opt_addr, Opt_mounthost, Opt_clientaddr,
+       Opt_addr, Opt_mountaddr, Opt_clientaddr,
 
        /* Mount options that are ignored */
        Opt_userspace, Opt_deprecated,
@@ -143,6 +115,7 @@ static match_table_t nfs_mount_option_tokens = {
        { Opt_v3, "v3" },
        { Opt_udp, "udp" },
        { Opt_tcp, "tcp" },
+       { Opt_rdma, "rdma" },
        { Opt_acl, "acl" },
        { Opt_noacl, "noacl" },
        { Opt_rdirplus, "rdirplus" },
@@ -175,13 +148,14 @@ static match_table_t nfs_mount_option_tokens = {
        { Opt_mountproto, "mountproto=%s" },
        { Opt_addr, "addr=%s" },
        { Opt_clientaddr, "clientaddr=%s" },
-       { Opt_mounthost, "mounthost=%s" },
+       { Opt_userspace, "mounthost=%s" },
+       { Opt_mountaddr, "mountaddr=%s" },
 
        { Opt_err, NULL }
 };
 
 enum {
-       Opt_xprt_udp, Opt_xprt_tcp,
+       Opt_xprt_udp, Opt_xprt_tcp, Opt_xprt_rdma,
 
        Opt_xprt_err
 };
@@ -189,6 +163,7 @@ enum {
 static match_table_t nfs_xprt_protocol_tokens = {
        { Opt_xprt_udp, "udp" },
        { Opt_xprt_tcp, "tcp" },
+       { Opt_xprt_rdma, "rdma" },
 
        { Opt_xprt_err, NULL }
 };
@@ -449,7 +424,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                const char *nostr;
        } nfs_info[] = {
                { NFS_MOUNT_SOFT, ",soft", ",hard" },
-               { NFS_MOUNT_INTR, ",intr", "" },
+               { NFS_MOUNT_INTR, ",intr", ",nointr" },
                { NFS_MOUNT_NOCTO, ",nocto", "" },
                { NFS_MOUNT_NOAC, ",noac", "" },
                { NFS_MOUNT_NONLM, ",nolock", "" },
@@ -460,8 +435,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        };
        const struct proc_nfs_info *nfs_infop;
        struct nfs_client *clp = nfss->nfs_client;
-       char buf[12];
-       const char *proto;
 
        seq_printf(m, ",vers=%d", clp->rpc_ops->version);
        seq_printf(m, ",rsize=%d", nfss->rsize);
@@ -480,18 +453,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                else
                        seq_puts(m, nfs_infop->nostr);
        }
-       switch (nfss->client->cl_xprt->prot) {
-               case IPPROTO_TCP:
-                       proto = "tcp";
-                       break;
-               case IPPROTO_UDP:
-                       proto = "udp";
-                       break;
-               default:
-                       snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
-                       proto = buf;
-       }
-       seq_printf(m, ",proto=%s", proto);
+       seq_printf(m, ",proto=%s",
+                  rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO));
        seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ);
        seq_printf(m, ",retrans=%u", clp->retrans_count);
        seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
@@ -506,8 +469,8 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
 
        nfs_show_mount_options(m, nfss, 0);
 
-       seq_puts(m, ",addr=");
-       seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\");
+       seq_printf(m, ",addr="NIPQUAD_FMT,
+               NIPQUAD(nfss->nfs_client->cl_addr.sin_addr));
 
        return 0;
 }
@@ -698,13 +661,19 @@ static int nfs_parse_mount_options(char *raw,
                        break;
                case Opt_udp:
                        mnt->flags &= ~NFS_MOUNT_TCP;
-                       mnt->nfs_server.protocol = IPPROTO_UDP;
+                       mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
                        mnt->timeo = 7;
                        mnt->retrans = 5;
                        break;
                case Opt_tcp:
                        mnt->flags |= NFS_MOUNT_TCP;
-                       mnt->nfs_server.protocol = IPPROTO_TCP;
+                       mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+                       mnt->timeo = 600;
+                       mnt->retrans = 2;
+                       break;
+               case Opt_rdma:
+                       mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
+                       mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
                        mnt->timeo = 600;
                        mnt->retrans = 2;
                        break;
@@ -913,13 +882,20 @@ static int nfs_parse_mount_options(char *raw,
                        switch (token) {
                        case Opt_xprt_udp:
                                mnt->flags &= ~NFS_MOUNT_TCP;
-                               mnt->nfs_server.protocol = IPPROTO_UDP;
+                               mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
                                mnt->timeo = 7;
                                mnt->retrans = 5;
                                break;
                        case Opt_xprt_tcp:
                                mnt->flags |= NFS_MOUNT_TCP;
-                               mnt->nfs_server.protocol = IPPROTO_TCP;
+                               mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+                               mnt->timeo = 600;
+                               mnt->retrans = 2;
+                               break;
+                       case Opt_xprt_rdma:
+                               /* vector side protocols to TCP */
+                               mnt->flags |= NFS_MOUNT_TCP;
+                               mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
                                mnt->timeo = 600;
                                mnt->retrans = 2;
                                break;
@@ -937,11 +913,12 @@ static int nfs_parse_mount_options(char *raw,
 
                        switch (token) {
                        case Opt_xprt_udp:
-                               mnt->mount_server.protocol = IPPROTO_UDP;
+                               mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
                                break;
                        case Opt_xprt_tcp:
-                               mnt->mount_server.protocol = IPPROTO_TCP;
+                               mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
                                break;
+                       case Opt_xprt_rdma: /* not used for side protocols */
                        default:
                                goto out_unrec_xprt;
                        }
@@ -961,7 +938,7 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        mnt->client_address = string;
                        break;
-               case Opt_mounthost:
+               case Opt_mountaddr:
                        string = match_strdup(args);
                        if (string == NULL)
                                goto out_nomem;
@@ -1027,16 +1004,10 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
                sin = args->mount_server.address;
        else
                sin = args->nfs_server.address;
-       if (args->mount_server.port == 0) {
-               status = rpcb_getport_sync(&sin,
-                                          args->mount_server.program,
-                                          args->mount_server.version,
-                                          args->mount_server.protocol);
-               if (status < 0)
-                       goto out_err;
-               sin.sin_port = htons(status);
-       } else
-               sin.sin_port = htons(args->mount_server.port);
+       /*
+        * autobind will be used if mount_server.port == 0
+        */
+       sin.sin_port = htons(args->mount_server.port);
 
        /*
         * Now ask the mount server to map our export path
@@ -1049,14 +1020,11 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
                           args->mount_server.version,
                           args->mount_server.protocol,
                           root_fh);
-       if (status < 0)
-               goto out_err;
-
-       return status;
+       if (status == 0)
+               return 0;
 
-out_err:
-       dfprintk(MOUNT, "NFS: unable to contact server on host "
-                NIPQUAD_FMT "\n", NIPQUAD(sin.sin_addr.s_addr));
+       dfprintk(MOUNT, "NFS: unable to mount server " NIPQUAD_FMT
+                       ", error %d\n", NIPQUAD(sin.sin_addr.s_addr), status);
        return status;
 }
 
@@ -1079,15 +1047,31 @@ out_err:
  * XXX: as far as I can tell, changing the NFS program number is not
  *      supported in the NFS client.
  */
-static int nfs_validate_mount_data(struct nfs_mount_data **options,
+static int nfs_validate_mount_data(void *options,
+                                  struct nfs_parsed_mount_data *args,
                                   struct nfs_fh *mntfh,
                                   const char *dev_name)
 {
-       struct nfs_mount_data *data = *options;
+       struct nfs_mount_data *data = (struct nfs_mount_data *)options;
 
        if (data == NULL)
                goto out_no_data;
 
+       memset(args, 0, sizeof(*args));
+       args->flags             = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP);
+       args->rsize             = NFS_MAX_FILE_IO_SIZE;
+       args->wsize             = NFS_MAX_FILE_IO_SIZE;
+       args->timeo             = 600;
+       args->retrans           = 2;
+       args->acregmin          = 3;
+       args->acregmax          = 60;
+       args->acdirmin          = 30;
+       args->acdirmax          = 60;
+       args->mount_server.protocol = XPRT_TRANSPORT_UDP;
+       args->mount_server.program = NFS_MNT_PROGRAM;
+       args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+       args->nfs_server.program = NFS_PROGRAM;
+
        switch (data->version) {
        case 1:
                data->namlen = 0;
@@ -1116,92 +1100,73 @@ static int nfs_validate_mount_data(struct nfs_mount_data **options,
                if (mntfh->size < sizeof(mntfh->data))
                        memset(mntfh->data + mntfh->size, 0,
                               sizeof(mntfh->data) - mntfh->size);
+
+               if (!nfs_verify_server_address((struct sockaddr *) &data->addr))
+                       goto out_no_address;
+
+               /*
+                * Translate to nfs_parsed_mount_data, which nfs_fill_super
+                * can deal with.
+                */
+               args->flags             = data->flags;
+               args->rsize             = data->rsize;
+               args->wsize             = data->wsize;
+               args->flags             = data->flags;
+               args->timeo             = data->timeo;
+               args->retrans           = data->retrans;
+               args->acregmin          = data->acregmin;
+               args->acregmax          = data->acregmax;
+               args->acdirmin          = data->acdirmin;
+               args->acdirmax          = data->acdirmax;
+               args->nfs_server.address = data->addr;
+               if (!(data->flags & NFS_MOUNT_TCP))
+                       args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+               /* N.B. caller will free nfs_server.hostname in all cases */
+               args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+               args->namlen            = data->namlen;
+               args->bsize             = data->bsize;
+               args->auth_flavors[0]   = data->pseudoflavor;
                break;
        default: {
                unsigned int len;
                char *c;
                int status;
-               struct nfs_parsed_mount_data args = {
-                       .flags          = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP),
-                       .rsize          = NFS_MAX_FILE_IO_SIZE,
-                       .wsize          = NFS_MAX_FILE_IO_SIZE,
-                       .timeo          = 600,
-                       .retrans        = 2,
-                       .acregmin       = 3,
-                       .acregmax       = 60,
-                       .acdirmin       = 30,
-                       .acdirmax       = 60,
-                       .mount_server.protocol = IPPROTO_UDP,
-                       .mount_server.program = NFS_MNT_PROGRAM,
-                       .nfs_server.protocol = IPPROTO_TCP,
-                       .nfs_server.program = NFS_PROGRAM,
-               };
-
-               if (nfs_parse_mount_options((char *) *options, &args) == 0)
-                       return -EINVAL;
 
-               data = kzalloc(sizeof(*data), GFP_KERNEL);
-               if (data == NULL)
-                       return -ENOMEM;
+               if (nfs_parse_mount_options((char *)options, args) == 0)
+                       return -EINVAL;
 
-               /*
-                * NB: after this point, caller will free "data"
-                * if we return an error
-                */
-               *options = data;
+               if (!nfs_verify_server_address((struct sockaddr *)
+                                               &args->nfs_server.address))
+                       goto out_no_address;
 
                c = strchr(dev_name, ':');
                if (c == NULL)
                        return -EINVAL;
                len = c - dev_name;
-               if (len > sizeof(data->hostname))
-                       return -ENAMETOOLONG;
-               strncpy(data->hostname, dev_name, len);
-               args.nfs_server.hostname = data->hostname;
+               /* N.B. caller will free nfs_server.hostname in all cases */
+               args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
 
                c++;
                if (strlen(c) > NFS_MAXPATHLEN)
                        return -ENAMETOOLONG;
-               args.nfs_server.export_path = c;
+               args->nfs_server.export_path = c;
 
-               status = nfs_try_mount(&args, mntfh);
+               status = nfs_try_mount(args, mntfh);
                if (status)
                        return status;
 
-               /*
-                * Translate to nfs_mount_data, which nfs_fill_super
-                * can deal with.
-                */
-               data->version           = 6;
-               data->flags             = args.flags;
-               data->rsize             = args.rsize;
-               data->wsize             = args.wsize;
-               data->timeo             = args.timeo;
-               data->retrans           = args.retrans;
-               data->acregmin          = args.acregmin;
-               data->acregmax          = args.acregmax;
-               data->acdirmin          = args.acdirmin;
-               data->acdirmax          = args.acdirmax;
-               data->addr              = args.nfs_server.address;
-               data->namlen            = args.namlen;
-               data->bsize             = args.bsize;
-               data->pseudoflavor      = args.auth_flavors[0];
-
                break;
                }
        }
 
-       if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
-               data->pseudoflavor = RPC_AUTH_UNIX;
+       if (!(args->flags & NFS_MOUNT_SECFLAVOUR))
+               args->auth_flavors[0] = RPC_AUTH_UNIX;
 
 #ifndef CONFIG_NFS_V3
-       if (data->flags & NFS_MOUNT_VER3)
+       if (args->flags & NFS_MOUNT_VER3)
                goto out_v3_not_compiled;
 #endif /* !CONFIG_NFS_V3 */
 
-       if (!nfs_verify_server_address((struct sockaddr *) &data->addr))
-               goto out_no_address;
-
        return 0;
 
 out_no_data:
@@ -1258,7 +1223,8 @@ static inline void nfs_initialise_sb(struct super_block *sb)
 /*
  * Finish setting up an NFS2/3 superblock
  */
-static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data)
+static void nfs_fill_super(struct super_block *sb,
+                          struct nfs_parsed_mount_data *data)
 {
        struct nfs_server *server = NFS_SB(sb);
 
@@ -1379,7 +1345,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
        struct nfs_server *server = NULL;
        struct super_block *s;
        struct nfs_fh mntfh;
-       struct nfs_mount_data *data = raw_data;
+       struct nfs_parsed_mount_data data;
        struct dentry *mntroot;
        int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
        struct nfs_sb_mountdata sb_mntdata = {
@@ -1388,12 +1354,12 @@ static int nfs_get_sb(struct file_system_type *fs_type,
        int error;
 
        /* Validate the mount data */
-       error = nfs_validate_mount_data(&data, &mntfh, dev_name);
+       error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name);
        if (error < 0)
                goto out;
 
        /* Get a volume representation */
-       server = nfs_create_server(data, &mntfh);
+       server = nfs_create_server(&data, &mntfh);
        if (IS_ERR(server)) {
                error = PTR_ERR(server);
                goto out;
@@ -1417,7 +1383,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
 
        if (!s->s_root) {
                /* initial superblock/root creation */
-               nfs_fill_super(s, data);
+               nfs_fill_super(s, &data);
        }
 
        mntroot = nfs_get_root(s, &mntfh);
@@ -1432,8 +1398,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
        error = 0;
 
 out:
-       if (data != raw_data)
-               kfree(data);
+       kfree(data.nfs_server.hostname);
        return error;
 
 out_err_nosb:
@@ -1559,38 +1524,49 @@ static void nfs4_fill_super(struct super_block *sb)
 /*
  * Validate NFSv4 mount options
  */
-static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
-                                   const char *dev_name,
-                                   struct sockaddr_in *addr,
-                                   rpc_authflavor_t *authflavour,
-                                   char **hostname,
-                                   char **mntpath,
-                                   char **ip_addr)
+static int nfs4_validate_mount_data(void *options,
+                                   struct nfs_parsed_mount_data *args,
+                                   const char *dev_name)
 {
-       struct nfs4_mount_data *data = *options;
+       struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
        char *c;
 
        if (data == NULL)
                goto out_no_data;
 
+       memset(args, 0, sizeof(*args));
+       args->rsize             = NFS_MAX_FILE_IO_SIZE;
+       args->wsize             = NFS_MAX_FILE_IO_SIZE;
+       args->timeo             = 600;
+       args->retrans           = 2;
+       args->acregmin          = 3;
+       args->acregmax          = 60;
+       args->acdirmin          = 30;
+       args->acdirmax          = 60;
+       args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+
        switch (data->version) {
        case 1:
-               if (data->host_addrlen != sizeof(*addr))
+               if (data->host_addrlen != sizeof(args->nfs_server.address))
                        goto out_no_address;
-               if (copy_from_user(addr, data->host_addr, sizeof(*addr)))
+               if (copy_from_user(&args->nfs_server.address,
+                                  data->host_addr,
+                                  sizeof(args->nfs_server.address)))
                        return -EFAULT;
-               if (addr->sin_port == 0)
-                       addr->sin_port = htons(NFS_PORT);
-               if (!nfs_verify_server_address((struct sockaddr *) addr))
+               if (args->nfs_server.address.sin_port == 0)
+                       args->nfs_server.address.sin_port = htons(NFS_PORT);
+               if (!nfs_verify_server_address((struct sockaddr *)
+                                               &args->nfs_server.address))
                        goto out_no_address;
 
                switch (data->auth_flavourlen) {
                case 0:
-                       *authflavour = RPC_AUTH_UNIX;
+                       args->auth_flavors[0] = RPC_AUTH_UNIX;
                        break;
                case 1:
-                       if (copy_from_user(authflavour, data->auth_flavours,
-                                          sizeof(*authflavour)))
+                       if (copy_from_user(&args->auth_flavors[0],
+                                          data->auth_flavours,
+                                          sizeof(args->auth_flavors[0])))
                                return -EFAULT;
                        break;
                default:
@@ -1600,74 +1576,56 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
                c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
                if (IS_ERR(c))
                        return PTR_ERR(c);
-               *hostname = c;
+               args->nfs_server.hostname = c;
 
                c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
                if (IS_ERR(c))
                        return PTR_ERR(c);
-               *mntpath = c;
-               dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath);
+               args->nfs_server.export_path = c;
+               dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
 
                c = strndup_user(data->client_addr.data, 16);
                if (IS_ERR(c))
                        return PTR_ERR(c);
-               *ip_addr = c;
+               args->client_address = c;
+
+               /*
+                * Translate to nfs_parsed_mount_data, which nfs4_fill_super
+                * can deal with.
+                */
+
+               args->flags     = data->flags & NFS4_MOUNT_FLAGMASK;
+               args->rsize     = data->rsize;
+               args->wsize     = data->wsize;
+               args->timeo     = data->timeo;
+               args->retrans   = data->retrans;
+               args->acregmin  = data->acregmin;
+               args->acregmax  = data->acregmax;
+               args->acdirmin  = data->acdirmin;
+               args->acdirmax  = data->acdirmax;
+               args->nfs_server.protocol = data->proto;
 
                break;
        default: {
                unsigned int len;
-               struct nfs_parsed_mount_data args = {
-                       .rsize          = NFS_MAX_FILE_IO_SIZE,
-                       .wsize          = NFS_MAX_FILE_IO_SIZE,
-                       .timeo          = 600,
-                       .retrans        = 2,
-                       .acregmin       = 3,
-                       .acregmax       = 60,
-                       .acdirmin       = 30,
-                       .acdirmax       = 60,
-                       .nfs_server.protocol = IPPROTO_TCP,
-               };
-
-               if (nfs_parse_mount_options((char *) *options, &args) == 0)
+
+               if (nfs_parse_mount_options((char *)options, args) == 0)
                        return -EINVAL;
 
                if (!nfs_verify_server_address((struct sockaddr *)
-                                               &args.nfs_server.address))
+                                               &args->nfs_server.address))
                        return -EINVAL;
-               *addr = args.nfs_server.address;
 
-               switch (args.auth_flavor_len) {
+               switch (args->auth_flavor_len) {
                case 0:
-                       *authflavour = RPC_AUTH_UNIX;
+                       args->auth_flavors[0] = RPC_AUTH_UNIX;
                        break;
                case 1:
-                       *authflavour = (rpc_authflavor_t) args.auth_flavors[0];
                        break;
                default:
                        goto out_inval_auth;
                }
 
-               /*
-                * Translate to nfs4_mount_data, which nfs4_fill_super
-                * can deal with.
-                */
-               data = kzalloc(sizeof(*data), GFP_KERNEL);
-               if (data == NULL)
-                       return -ENOMEM;
-               *options = data;
-
-               data->version   = 1;
-               data->flags     = args.flags & NFS4_MOUNT_FLAGMASK;
-               data->rsize     = args.rsize;
-               data->wsize     = args.wsize;
-               data->timeo     = args.timeo;
-               data->retrans   = args.retrans;
-               data->acregmin  = args.acregmin;
-               data->acregmax  = args.acregmax;
-               data->acdirmin  = args.acdirmin;
-               data->acdirmax  = args.acdirmax;
-               data->proto     = args.nfs_server.protocol;
-
                /*
                 * Split "dev_name" into "hostname:mntpath".
                 */
@@ -1678,27 +1636,25 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
                len = c - dev_name;
                if (len > NFS4_MAXNAMLEN)
                        return -ENAMETOOLONG;
-               *hostname = kzalloc(len, GFP_KERNEL);
-               if (*hostname == NULL)
+               args->nfs_server.hostname = kzalloc(len, GFP_KERNEL);
+               if (args->nfs_server.hostname == NULL)
                        return -ENOMEM;
-               strncpy(*hostname, dev_name, len - 1);
+               strncpy(args->nfs_server.hostname, dev_name, len - 1);
 
                c++;                    /* step over the ':' */
                len = strlen(c);
                if (len > NFS4_MAXPATHLEN)
                        return -ENAMETOOLONG;
-               *mntpath = kzalloc(len + 1, GFP_KERNEL);
-               if (*mntpath == NULL)
+               args->nfs_server.export_path = kzalloc(len + 1, GFP_KERNEL);
+               if (args->nfs_server.export_path == NULL)
                        return -ENOMEM;
-               strncpy(*mntpath, c, len);
+               strncpy(args->nfs_server.export_path, c, len);
 
-               dprintk("MNTPATH: %s\n", *mntpath);
+               dprintk("MNTPATH: %s\n", args->nfs_server.export_path);
 
-               if (args.client_address == NULL)
+               if (args->client_address == NULL)
                        goto out_no_client_address;
 
-               *ip_addr = args.client_address;
-
                break;
                }
        }
@@ -1729,14 +1685,11 @@ out_no_client_address:
 static int nfs4_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
 {
-       struct nfs4_mount_data *data = raw_data;
+       struct nfs_parsed_mount_data data;
        struct super_block *s;
        struct nfs_server *server;
-       struct sockaddr_in addr;
-       rpc_authflavor_t authflavour;
        struct nfs_fh mntfh;
        struct dentry *mntroot;
-       char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
        int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
        struct nfs_sb_mountdata sb_mntdata = {
                .mntflags = flags,
@@ -1744,14 +1697,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
        int error;
 
        /* Validate the mount data */
-       error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour,
-                                        &hostname, &mntpath, &ip_addr);
+       error = nfs4_validate_mount_data(raw_data, &data, dev_name);
        if (error < 0)
                goto out;
 
        /* Get a volume representation */
-       server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
-                                   authflavour, &mntfh);
+       server = nfs4_create_server(&data, &mntfh);
        if (IS_ERR(server)) {
                error = PTR_ERR(server);
                goto out;
@@ -1790,9 +1741,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
        error = 0;
 
 out:
-       kfree(ip_addr);
-       kfree(mntpath);
-       kfree(hostname);
+       kfree(data.client_address);
+       kfree(data.nfs_server.export_path);
+       kfree(data.nfs_server.hostname);
        return error;
 
 out_free:
index 045ab805c17f5aa25e0a1b5179c3eefd3ba5858a..1aed850d18f2ebab29f2b6b7077f4effb85413ff 100644 (file)
@@ -66,7 +66,6 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
                .rpc_cred = data->cred,
        };
 
-       nfs_begin_data_update(dir);
        NFS_PROTO(dir)->unlink_setup(&msg, dir);
        rpc_call_setup(task, &msg, 0);
 }
@@ -84,8 +83,6 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
 
        if (!NFS_PROTO(dir)->unlink_done(task, dir))
                rpc_restart_call(task);
-       else
-               nfs_end_data_update(dir);
 }
 
 /**
index 0d7a77cc394babb9933d37980f0b3e8f64dd153d..e2bb66c34406d7cc6dc61b0557e0017166575dc8 100644 (file)
@@ -110,6 +110,13 @@ void nfs_writedata_release(void *wdata)
        nfs_writedata_free(wdata);
 }
 
+static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
+{
+       ctx->error = error;
+       smp_wmb();
+       set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+}
+
 static struct nfs_page *nfs_page_find_request_locked(struct page *page)
 {
        struct nfs_page *req = NULL;
@@ -243,10 +250,7 @@ static void nfs_end_page_writeback(struct page *page)
 
 /*
  * Find an associated nfs write request, and prepare to flush it out
- * Returns 1 if there was no write request, or if the request was
- * already tagged by nfs_set_page_dirty.Returns 0 if the request
- * was not tagged.
- * May also return an error if the user signalled nfs_wait_on_request().
+ * May return an error if the user signalled nfs_wait_on_request().
  */
 static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
                                struct page *page)
@@ -261,7 +265,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
                req = nfs_page_find_request_locked(page);
                if (req == NULL) {
                        spin_unlock(&inode->i_lock);
-                       return 1;
+                       return 0;
                }
                if (nfs_lock_request_dontget(req))
                        break;
@@ -282,7 +286,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
                spin_unlock(&inode->i_lock);
                nfs_unlock_request(req);
                nfs_pageio_complete(pgio);
-               return 1;
+               return 0;
        }
        if (nfs_set_page_writeback(page) != 0) {
                spin_unlock(&inode->i_lock);
@@ -290,70 +294,56 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
        }
        radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
                        NFS_PAGE_TAG_LOCKED);
-       ret = test_bit(PG_NEED_FLUSH, &req->wb_flags);
        spin_unlock(&inode->i_lock);
        nfs_pageio_add_request(pgio, req);
-       return ret;
+       return 0;
 }
 
-/*
- * Write an mmapped page to the server.
- */
-static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
+static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
 {
-       struct nfs_pageio_descriptor mypgio, *pgio;
-       struct nfs_open_context *ctx;
        struct inode *inode = page->mapping->host;
-       unsigned offset;
-       int err;
 
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
        nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
-       if (wbc->for_writepages)
-               pgio = wbc->fs_private;
-       else {
-               nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc));
-               pgio = &mypgio;
-       }
-
        nfs_pageio_cond_complete(pgio, page->index);
+       return nfs_page_async_flush(pgio, page);
+}
 
-       err = nfs_page_async_flush(pgio, page);
-       if (err <= 0)
-               goto out;
-       err = 0;
-       offset = nfs_page_length(page);
-       if (!offset)
-               goto out;
-
-       nfs_pageio_cond_complete(pgio, page->index);
+/*
+ * Write an mmapped page to the server.
+ */
+static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
+{
+       struct nfs_pageio_descriptor pgio;
+       int err;
 
-       ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE);
-       if (ctx == NULL) {
-               err = -EBADF;
-               goto out;
-       }
-       err = nfs_writepage_setup(ctx, page, 0, offset);
-       put_nfs_open_context(ctx);
-       if (err != 0)
-               goto out;
-       err = nfs_page_async_flush(pgio, page);
-       if (err > 0)
-               err = 0;
-out:
-       if (!wbc->for_writepages)
-               nfs_pageio_complete(pgio);
-       return err;
+       nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc));
+       err = nfs_do_writepage(page, wbc, &pgio);
+       nfs_pageio_complete(&pgio);
+       if (err < 0)
+               return err;
+       if (pgio.pg_error < 0)
+               return pgio.pg_error;
+       return 0;
 }
 
 int nfs_writepage(struct page *page, struct writeback_control *wbc)
 {
-       int err;
+       int ret;
+
+       ret = nfs_writepage_locked(page, wbc);
+       unlock_page(page);
+       return ret;
+}
+
+static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data)
+{
+       int ret;
 
-       err = nfs_writepage_locked(page, wbc);
+       ret = nfs_do_writepage(page, wbc, data);
        unlock_page(page);
-       return err; 
+       return ret;
 }
 
 int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
@@ -365,12 +355,11 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
        nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
-       wbc->fs_private = &pgio;
-       err = generic_writepages(mapping, wbc);
+       err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
        nfs_pageio_complete(&pgio);
-       if (err)
+       if (err < 0)
                return err;
-       if (pgio.pg_error)
+       if (pgio.pg_error < 0)
                return pgio.pg_error;
        return 0;
 }
@@ -389,14 +378,11 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
                return error;
        if (!nfsi->npages) {
                igrab(inode);
-               nfs_begin_data_update(inode);
                if (nfs_have_delegation(inode, FMODE_WRITE))
                        nfsi->change_attr++;
        }
        SetPagePrivate(req->wb_page);
        set_page_private(req->wb_page, (unsigned long)req);
-       if (PageDirty(req->wb_page))
-               set_bit(PG_NEED_FLUSH, &req->wb_flags);
        nfsi->npages++;
        kref_get(&req->wb_kref);
        return 0;
@@ -416,12 +402,9 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        set_page_private(req->wb_page, 0);
        ClearPagePrivate(req->wb_page);
        radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
-       if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags))
-               __set_page_dirty_nobuffers(req->wb_page);
        nfsi->npages--;
        if (!nfsi->npages) {
                spin_unlock(&inode->i_lock);
-               nfs_end_data_update(inode);
                iput(inode);
        } else
                spin_unlock(&inode->i_lock);
@@ -682,7 +665,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
 
 int nfs_flush_incompatible(struct file *file, struct page *page)
 {
-       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+       struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct nfs_page *req;
        int do_flush, status;
        /*
@@ -716,7 +699,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
 int nfs_updatepage(struct file *file, struct page *page,
                unsigned int offset, unsigned int count)
 {
-       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+       struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode    *inode = page->mapping->host;
        int             status = 0;
 
@@ -967,7 +950,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
 
        if (task->tk_status < 0) {
                nfs_set_pageerror(page);
-               req->wb_context->error = task->tk_status;
+               nfs_context_set_write_error(req->wb_context, task->tk_status);
                dprintk(", error = %d\n", task->tk_status);
                goto out;
        }
@@ -1030,7 +1013,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
 
                if (task->tk_status < 0) {
                        nfs_set_pageerror(page);
-                       req->wb_context->error = task->tk_status;
+                       nfs_context_set_write_error(req->wb_context, task->tk_status);
                        dprintk(", error = %d\n", task->tk_status);
                        goto remove_request;
                }
@@ -1244,7 +1227,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
                        req->wb_bytes,
                        (long long)req_offset(req));
                if (task->tk_status < 0) {
-                       req->wb_context->error = task->tk_status;
+                       nfs_context_set_write_error(req->wb_context, task->tk_status);
                        nfs_inode_remove_request(req);
                        dprintk(", error = %d\n", task->tk_status);
                        goto next;
@@ -1347,53 +1330,52 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr
        return ret;
 }
 
-/*
- * flush the inode to disk.
- */
-int nfs_wb_all(struct inode *inode)
+static int __nfs_write_mapping(struct address_space *mapping, struct writeback_control *wbc, int how)
 {
-       struct address_space *mapping = inode->i_mapping;
-       struct writeback_control wbc = {
-               .bdi = mapping->backing_dev_info,
-               .sync_mode = WB_SYNC_ALL,
-               .nr_to_write = LONG_MAX,
-               .for_writepages = 1,
-               .range_cyclic = 1,
-       };
        int ret;
 
-       ret = nfs_writepages(mapping, &wbc);
+       ret = nfs_writepages(mapping, wbc);
        if (ret < 0)
                goto out;
-       ret = nfs_sync_mapping_wait(mapping, &wbc, 0);
-       if (ret >= 0)
-               return 0;
+       ret = nfs_sync_mapping_wait(mapping, wbc, how);
+       if (ret < 0)
+               goto out;
+       return 0;
 out:
        __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
        return ret;
 }
 
-int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how)
+/* Two pass sync: first using WB_SYNC_NONE, then WB_SYNC_ALL */
+static int nfs_write_mapping(struct address_space *mapping, int how)
 {
        struct writeback_control wbc = {
                .bdi = mapping->backing_dev_info,
-               .sync_mode = WB_SYNC_ALL,
+               .sync_mode = WB_SYNC_NONE,
                .nr_to_write = LONG_MAX,
-               .range_start = range_start,
-               .range_end = range_end,
                .for_writepages = 1,
+               .range_cyclic = 1,
        };
        int ret;
 
-       ret = nfs_writepages(mapping, &wbc);
+       ret = __nfs_write_mapping(mapping, &wbc, how);
        if (ret < 0)
-               goto out;
-       ret = nfs_sync_mapping_wait(mapping, &wbc, how);
-       if (ret >= 0)
-               return 0;
-out:
-       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
-       return ret;
+               return ret;
+       wbc.sync_mode = WB_SYNC_ALL;
+       return __nfs_write_mapping(mapping, &wbc, how);
+}
+
+/*
+ * flush the inode to disk.
+ */
+int nfs_wb_all(struct inode *inode)
+{
+       return nfs_write_mapping(inode->i_mapping, 0);
+}
+
+int nfs_wb_nocommit(struct inode *inode)
+{
+       return nfs_write_mapping(inode->i_mapping, FLUSH_NOCOMMIT);
 }
 
 int nfs_wb_page_cancel(struct inode *inode, struct page *page)
@@ -1477,35 +1459,6 @@ int nfs_wb_page(struct inode *inode, struct page* page)
        return nfs_wb_page_priority(inode, page, FLUSH_STABLE);
 }
 
-int nfs_set_page_dirty(struct page *page)
-{
-       struct address_space *mapping = page->mapping;
-       struct inode *inode;
-       struct nfs_page *req;
-       int ret;
-
-       if (!mapping)
-               goto out_raced;
-       inode = mapping->host;
-       if (!inode)
-               goto out_raced;
-       spin_lock(&inode->i_lock);
-       req = nfs_page_find_request_locked(page);
-       if (req != NULL) {
-               /* Mark any existing write requests for flushing */
-               ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags);
-               spin_unlock(&inode->i_lock);
-               nfs_release_request(req);
-               return ret;
-       }
-       ret = __set_page_dirty_nobuffers(page);
-       spin_unlock(&inode->i_lock);
-       return ret;
-out_raced:
-       return !TestSetPageDirty(page);
-}
-
-
 int __init nfs_init_writepagecache(void)
 {
        nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
index 10f6e7dcf6336b48746cd6c16d7ed5c1d04cae28..2d116d2298f8e3aec23982bc04795dd9daf69ca2 100644 (file)
@@ -174,9 +174,6 @@ static __be32 *
 encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
              struct kstat *stat)
 {
-       struct dentry   *dentry = fhp->fh_dentry;
-       struct timespec time;
-
        *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
        *p++ = htonl((u32) stat->mode);
        *p++ = htonl((u32) stat->nlink);
@@ -191,10 +188,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        *p++ = htonl((u32) MAJOR(stat->rdev));
        *p++ = htonl((u32) MINOR(stat->rdev));
        p = encode_fsid(p, fhp);
-       p = xdr_encode_hyper(p, (u64) stat->ino);
+       p = xdr_encode_hyper(p, stat->ino);
        p = encode_time3(p, &stat->atime);
-       lease_get_mtime(dentry->d_inode, &time); 
-       p = encode_time3(p, &time);
+       p = encode_time3(p, &stat->mtime);
        p = encode_time3(p, &stat->ctime);
 
        return p;
@@ -203,31 +199,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 static __be32 *
 encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
-       struct inode    *inode = fhp->fh_dentry->d_inode;
-
        /* Attributes to follow */
        *p++ = xdr_one;
-
-       *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
-       *p++ = htonl((u32) fhp->fh_post_mode);
-       *p++ = htonl((u32) fhp->fh_post_nlink);
-       *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
-       *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
-       if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
-               p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
-       } else {
-               p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
-       }
-       p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
-       *p++ = fhp->fh_post_rdev[0];
-       *p++ = fhp->fh_post_rdev[1];
-       p = encode_fsid(p, fhp);
-       p = xdr_encode_hyper(p, (u64) inode->i_ino);
-       p = encode_time3(p, &fhp->fh_post_atime);
-       p = encode_time3(p, &fhp->fh_post_mtime);
-       p = encode_time3(p, &fhp->fh_post_ctime);
-
-       return p;
+       return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
 }
 
 /*
@@ -246,6 +220,7 @@ encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
                err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);
                if (!err) {
                        *p++ = xdr_one;         /* attributes follow */
+                       lease_get_mtime(dentry->d_inode, &stat.mtime);
                        return encode_fattr3(rqstp, p, fhp, &stat);
                }
        }
@@ -284,6 +259,23 @@ encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
        return encode_post_op_attr(rqstp, p, fhp);
 }
 
+/*
+ * Fill in the post_op attr for the wcc data
+ */
+void fill_post_wcc(struct svc_fh *fhp)
+{
+       int err;
+
+       if (fhp->fh_post_saved)
+               printk("nfsd: inode locked twice during operation.\n");
+
+       err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry,
+                       &fhp->fh_post_attr);
+       if (err)
+               fhp->fh_post_saved = 0;
+       else
+               fhp->fh_post_saved = 1;
+}
 
 /*
  * XDR decode functions
@@ -643,8 +635,11 @@ int
 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_attrstat *resp)
 {
-       if (resp->status == 0)
+       if (resp->status == 0) {
+               lease_get_mtime(resp->fh.fh_dentry->d_inode,
+                               &resp->stat.mtime);
                p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
+       }
        return xdr_ressize_check(rqstp, p);
 }
 
@@ -802,7 +797,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
 
 static __be32 *
 encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
-            int namlen, ino_t ino)
+            int namlen, u64 ino)
 {
        *p++ = xdr_one;                          /* mark entry present */
        p    = xdr_encode_hyper(p, ino);         /* file id */
@@ -873,7 +868,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
 static int
 encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
-            loff_t offset, ino_t ino, unsigned int d_type, int plus)
+            loff_t offset, u64 ino, unsigned int d_type, int plus)
 {
        struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
                                                        common);
index 31d6633c7fe46345b7ec60a74caa0aa92e077d11..9d536a8cb3795651551af7b228407a09d890f7b7 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
@@ -343,26 +344,28 @@ static struct rpc_version *       nfs_cb_version[] = {
        &nfs_cb_version4,
 };
 
-/*
- * Use the SETCLIENTID credential
- */
-static struct rpc_cred *
-nfsd4_lookupcred(struct nfs4_client *clp, int taskflags)
+/* Reference counting, callback cleanup, etc., all look racy as heck.
+ * And why is cb_set an atomic? */
+
+static int do_probe_callback(void *data)
 {
-        struct auth_cred acred;
-       struct rpc_clnt *clnt = clp->cl_callback.cb_client;
-       struct rpc_cred *ret;
-
-        get_group_info(clp->cl_cred.cr_group_info);
-        acred.uid = clp->cl_cred.cr_uid;
-        acred.gid = clp->cl_cred.cr_gid;
-        acred.group_info = clp->cl_cred.cr_group_info;
-
-        dprintk("NFSD:     looking up %s cred\n",
-                clnt->cl_auth->au_ops->au_name);
-        ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags);
-        put_group_info(clp->cl_cred.cr_group_info);
-        return ret;
+       struct nfs4_client *clp = data;
+       struct nfs4_callback *cb = &clp->cl_callback;
+       struct rpc_message msg = {
+               .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
+               .rpc_argp       = clp,
+       };
+       int status;
+
+       status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);
+
+       if (status) {
+               rpc_shutdown_client(cb->cb_client);
+               cb->cb_client = NULL;
+       } else
+               atomic_set(&cb->cb_set, 1);
+       put_nfs4_client(clp);
+       return 0;
 }
 
 /*
@@ -390,11 +393,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
                .authflavor     = RPC_AUTH_UNIX,        /* XXX: need AUTH_GSS... */
                .flags          = (RPC_CLNT_CREATE_NOPING),
        };
-       struct rpc_message msg = {
-               .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
-               .rpc_argp       = clp,
-       };
-       int status;
+       struct task_struct *t;
 
        if (atomic_read(&cb->cb_set))
                return;
@@ -426,16 +425,11 @@ nfsd4_probe_callback(struct nfs4_client *clp)
        /* the task holds a reference to the nfs4_client struct */
        atomic_inc(&clp->cl_count);
 
-       msg.rpc_cred = nfsd4_lookupcred(clp,0);
-       if (IS_ERR(msg.rpc_cred))
-               goto out_release_clp;
-       status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
-       put_rpccred(msg.rpc_cred);
+       t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
 
-       if (status != 0) {
-               dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
+       if (IS_ERR(t))
                goto out_release_clp;
-       }
+
        return;
 
 out_release_clp:
@@ -447,30 +441,6 @@ out_err:
                (int)clp->cl_name.len, clp->cl_name.data);
 }
 
-static void
-nfs4_cb_null(struct rpc_task *task, void *dummy)
-{
-       struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
-       struct nfs4_callback *cb = &clp->cl_callback;
-       __be32 addr = htonl(cb->cb_addr);
-
-       dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status);
-
-       if (task->tk_status < 0) {
-               dprintk("NFSD: callback establishment to client %.*s failed\n",
-                       (int)clp->cl_name.len, clp->cl_name.data);
-               goto out;
-       }
-       atomic_set(&cb->cb_set, 1);
-       dprintk("NFSD: callback set to client %u.%u.%u.%u\n", NIPQUAD(addr));
-out:
-       put_nfs4_client(clp);
-}
-
-static const struct rpc_call_ops nfs4_cb_null_ops = {
-       .rpc_call_done = nfs4_cb_null,
-};
-
 /*
  * called with dp->dl_count inc'ed.
  * nfs4_lock_state() may or may not have been called.
@@ -491,10 +461,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
        if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
                return;
 
-       msg.rpc_cred = nfsd4_lookupcred(clp, 0);
-       if (IS_ERR(msg.rpc_cred))
-               goto out;
-
        cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
        cbr->cbr_dp = dp;
 
@@ -515,13 +481,12 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
                status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
        }
 out_put_cred:
-       put_rpccred(msg.rpc_cred);
-out:
        if (status == -EIO)
                atomic_set(&clp->cl_callback.cb_set, 0);
        /* Success or failure, now we're either waiting for lease expiration
         * or deleg_return. */
        dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
+       put_nfs4_client(clp);
        nfs4_put_delegation(dp);
        return;
 }
index 2ccffde81b8430575eb1d803278ba2ceda1f66bb..4c0c683ce07a8be9852f06370dfad35d3591a45a 100644 (file)
@@ -207,6 +207,7 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
 {
        struct ent ent, *res;
        char *buf1, *bp;
+       int len;
        int error = -EINVAL;
 
        if (buf[buflen - 1] != '\n')
@@ -248,10 +249,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
                goto out;
 
        /* Name */
-       error = qword_get(&buf, buf1, PAGE_SIZE);
-       if (error == -EINVAL)
+       error = -EINVAL;
+       len = qword_get(&buf, buf1, PAGE_SIZE);
+       if (len < 0)
                goto out;
-       if (error == -ENOENT)
+       if (len == 0)
                set_bit(CACHE_NEGATIVE, &ent.h.flags);
        else {
                if (error >= IDMAP_NAMESZ) {
index 29b7e63cb32c42aaf23d4852abdf12f4792557e2..18ead1790bb388461b08d42e3e5fcc5c1d1807cd 100644 (file)
@@ -238,12 +238,12 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        break;
                case NFS4_OPEN_CLAIM_DELEGATE_PREV:
                        open->op_stateowner->so_confirmed = 1;
-                       printk("NFSD: unsupported OPEN claim type %d\n",
+                       dprintk("NFSD: unsupported OPEN claim type %d\n",
                                open->op_claim_type);
                        status = nfserr_notsupp;
                        goto out;
                default:
-                       printk("NFSD: Invalid OPEN claim type %d\n",
+                       dprintk("NFSD: Invalid OPEN claim type %d\n",
                                open->op_claim_type);
                        status = nfserr_inval;
                        goto out;
index 3f559700788f1603a60840ce7bfc3b20e857fd48..6f182d25793dd67c2651b37e854d7936ab8223ea 100644 (file)
@@ -358,9 +358,22 @@ alloc_client(struct xdr_netobj name)
        return clp;
 }
 
+static void
+shutdown_callback_client(struct nfs4_client *clp)
+{
+       struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+
+       /* shutdown rpc client, ending any outstanding recall rpcs */
+       if (clnt) {
+               clp->cl_callback.cb_client = NULL;
+               rpc_shutdown_client(clnt);
+       }
+}
+
 static inline void
 free_client(struct nfs4_client *clp)
 {
+       shutdown_callback_client(clp);
        if (clp->cl_cred.cr_group_info)
                put_group_info(clp->cl_cred.cr_group_info);
        kfree(clp->cl_name.data);
@@ -374,18 +387,6 @@ put_nfs4_client(struct nfs4_client *clp)
                free_client(clp);
 }
 
-static void
-shutdown_callback_client(struct nfs4_client *clp)
-{
-       struct rpc_clnt *clnt = clp->cl_callback.cb_client;
-
-       /* shutdown rpc client, ending any outstanding recall rpcs */
-       if (clnt) {
-               clp->cl_callback.cb_client = NULL;
-               rpc_shutdown_client(clnt);
-       }
-}
-
 static void
 expire_client(struct nfs4_client *clp)
 {
@@ -396,8 +397,6 @@ expire_client(struct nfs4_client *clp)
        dprintk("NFSD: expire_client cl_count %d\n",
                            atomic_read(&clp->cl_count));
 
-       shutdown_callback_client(clp);
-
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&recall_lock);
        while (!list_empty(&clp->cl_delegations)) {
@@ -462,26 +461,28 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) {
 }
 
 static inline int
-same_name(const char *n1, const char *n2) {
+same_name(const char *n1, const char *n2)
+{
        return 0 == memcmp(n1, n2, HEXDIR_LEN);
 }
 
 static int
-cmp_verf(nfs4_verifier *v1, nfs4_verifier *v2) {
-       return(!memcmp(v1->data,v2->data,sizeof(v1->data)));
+same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
+{
+       return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
 }
 
 static int
-cmp_clid(clientid_t * cl1, clientid_t * cl2) {
-       return((cl1->cl_boot == cl2->cl_boot) &&
-               (cl1->cl_id == cl2->cl_id));
+same_clid(clientid_t *cl1, clientid_t *cl2)
+{
+       return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
 }
 
 /* XXX what about NGROUP */
 static int
-cmp_creds(struct svc_cred *cr1, struct svc_cred *cr2){
-       return(cr1->cr_uid == cr2->cr_uid);
-
+same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
+{
+       return cr1->cr_uid == cr2->cr_uid;
 }
 
 static void
@@ -507,7 +508,7 @@ check_name(struct xdr_netobj name) {
        if (name.len == 0) 
                return 0;
        if (name.len > NFS4_OPAQUE_LIMIT) {
-               printk("NFSD: check_name: name too long(%d)!\n", name.len);
+               dprintk("NFSD: check_name: name too long(%d)!\n", name.len);
                return 0;
        }
        return 1;
@@ -546,7 +547,7 @@ find_confirmed_client(clientid_t *clid)
        unsigned int idhashval = clientid_hashval(clid->cl_id);
 
        list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
-               if (cmp_clid(&clp->cl_clientid, clid))
+               if (same_clid(&clp->cl_clientid, clid))
                        return clp;
        }
        return NULL;
@@ -559,7 +560,7 @@ find_unconfirmed_client(clientid_t *clid)
        unsigned int idhashval = clientid_hashval(clid->cl_id);
 
        list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
-               if (cmp_clid(&clp->cl_clientid, clid))
+               if (same_clid(&clp->cl_clientid, clid))
                        return clp;
        }
        return NULL;
@@ -753,7 +754,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                 * or different ip_address
                 */
                status = nfserr_clid_inuse;
-               if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred)
+               if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
                                || conf->cl_addr != sin->sin_addr.s_addr) {
                        dprintk("NFSD: setclientid: string in use by client"
                                "at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr));
@@ -772,14 +773,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new, &clverifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                gen_clid(new);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new, strhashval);
-       } else if (cmp_verf(&conf->cl_verifier, &clverifier)) {
+       } else if (same_verf(&conf->cl_verifier, &clverifier)) {
                /*
                 * CASE 1:
                 * cl_name match, confirmed, principal match
@@ -804,13 +799,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new,&conf->cl_verifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                copy_clid(new, conf);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new,strhashval);
        } else if (!unconf) {
                /*
                 * CASE 2:
@@ -823,14 +812,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new,&clverifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                gen_clid(new);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new, strhashval);
-       } else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
+       } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
                /*      
                 * CASE3:
                 * confirmed found (name, principal match)
@@ -850,19 +833,19 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
-               copy_verf(new,&clverifier);
-               new->cl_addr = sin->sin_addr.s_addr;
-               copy_cred(&new->cl_cred,&rqstp->rq_cred);
                gen_clid(new);
-               gen_confirm(new);
-               gen_callback(new, setclid);
-               add_to_unconfirmed(new, strhashval);
        } else {
                /* No cases hit !!! */
                status = nfserr_inval;
                goto out;
 
        }
+       copy_verf(new, &clverifier);
+       new->cl_addr = sin->sin_addr.s_addr;
+       copy_cred(&new->cl_cred, &rqstp->rq_cred);
+       gen_confirm(new);
+       gen_callback(new, setclid);
+       add_to_unconfirmed(new, strhashval);
        setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
        setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
        memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
@@ -910,16 +893,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                goto out;
 
        if ((conf && unconf) && 
-           (cmp_verf(&unconf->cl_confirm, &confirm)) &&
-           (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
+           (same_verf(&unconf->cl_confirm, &confirm)) &&
+           (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
            (same_name(conf->cl_recdir,unconf->cl_recdir))  &&
-           (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
+           (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
                /* CASE 1:
                * unconf record that matches input clientid and input confirm.
                * conf record that matches input clientid.
                * conf and unconf records match names, verifiers
                */
-               if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) 
+               if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
                        status = nfserr_clid_inuse;
                else {
                        /* XXX: We just turn off callbacks until we can handle
@@ -933,7 +916,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                }
        } else if ((conf && !unconf) ||
            ((conf && unconf) && 
-            (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
+            (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
              !same_name(conf->cl_recdir, unconf->cl_recdir)))) {
                /* CASE 2:
                 * conf record that matches input clientid.
@@ -941,18 +924,18 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                 * unconf->cl_name or unconf->cl_verifier don't match the
                 * conf record.
                 */
-               if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred))
+               if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
                        status = nfserr_clid_inuse;
                else
                        status = nfs_ok;
        } else if (!conf && unconf
-                       && cmp_verf(&unconf->cl_confirm, &confirm)) {
+                       && same_verf(&unconf->cl_confirm, &confirm)) {
                /* CASE 3:
                 * conf record not found.
                 * unconf record found.
                 * unconf->cl_confirm matches input confirm
                 */
-               if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
+               if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
                        status = nfserr_clid_inuse;
                } else {
                        unsigned int hash =
@@ -967,8 +950,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        conf = unconf;
                        status = nfs_ok;
                }
-       } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm)))
-           && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm,
+       } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
+           && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
                                                                &confirm)))) {
                /* CASE 4:
                 * conf record not found, or if conf, conf->cl_confirm does not
@@ -1019,7 +1002,7 @@ nfsd4_free_slab(struct kmem_cache **slab)
        *slab = NULL;
 }
 
-static void
+void
 nfsd4_free_slabs(void)
 {
        nfsd4_free_slab(&stateowner_slab);
@@ -1207,10 +1190,12 @@ move_to_close_lru(struct nfs4_stateowner *sop)
 }
 
 static int
-cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) {
-       return ((sop->so_owner.len == owner->len) && 
-        !memcmp(sop->so_owner.data, owner->data, owner->len) && 
-         (sop->so_client->cl_clientid.cl_id == clid->cl_id));
+same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
+                                                       clientid_t *clid)
+{
+       return (sop->so_owner.len == owner->len) &&
+               0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
+               (sop->so_client->cl_clientid.cl_id == clid->cl_id);
 }
 
 static struct nfs4_stateowner *
@@ -1219,7 +1204,7 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
        struct nfs4_stateowner *so = NULL;
 
        list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
-               if (cmp_owner_str(so, &open->op_owner, &open->op_clientid))
+               if (same_owner_str(so, &open->op_owner, &open->op_clientid))
                        return so;
        }
        return NULL;
@@ -1360,6 +1345,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
         * lock) we know the server hasn't removed the lease yet, we know
         * it's safe to take a reference: */
        atomic_inc(&dp->dl_count);
+       atomic_inc(&dp->dl_client->cl_count);
 
        spin_lock(&recall_lock);
        list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
@@ -1368,8 +1354,12 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
        /* only place dl_time is set. protected by lock_kernel*/
        dp->dl_time = get_seconds();
 
-       /* XXX need to merge NFSD_LEASE_TIME with fs/locks.c:lease_break_time */
-       fl->fl_break_time = jiffies + NFSD_LEASE_TIME * HZ;
+       /*
+        * We don't want the locks code to timeout the lease for us;
+        * we'll remove it ourself if the delegation isn't returned
+        * in time.
+        */
+       fl->fl_break_time = 0;
 
        t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall");
        if (IS_ERR(t)) {
@@ -1378,6 +1368,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
                printk(KERN_INFO "NFSD: Callback thread failed for "
                        "for client (clientid %08x/%08x)\n",
                        clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+               put_nfs4_client(dp->dl_client);
                nfs4_put_delegation(dp);
        }
 }
@@ -1738,7 +1729,7 @@ out:
        if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
                        && flag == NFS4_OPEN_DELEGATE_NONE
                        && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
-               printk("NFSD: WARNING: refusing delegation reclaim\n");
+               dprintk("NFSD: WARNING: refusing delegation reclaim\n");
        open->op_delegate_type = flag;
 }
 
@@ -2147,7 +2138,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
        *sopp = NULL;
 
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
-               printk("NFSD: preprocess_seqid_op: magic stateid!\n");
+               dprintk("NFSD: preprocess_seqid_op: magic stateid!\n");
                return nfserr_bad_stateid;
        }
 
@@ -2181,25 +2172,24 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                lkflg = setlkflg(lock->lk_type);
 
                if (lock->lk_is_new) {
-                       if (!sop->so_is_open_owner)
-                              return nfserr_bad_stateid;
-                       if (!cmp_clid(&clp->cl_clientid, lockclid))
+                       if (!sop->so_is_open_owner)
+                               return nfserr_bad_stateid;
+                       if (!same_clid(&clp->cl_clientid, lockclid))
                               return nfserr_bad_stateid;
-                       /* stp is the open stateid */
-                       status = nfs4_check_openmode(stp, lkflg);
-                       if (status)
-                              return status;
-               } else {
-                       /* stp is the lock stateid */
-                       status = nfs4_check_openmode(stp->st_openstp, lkflg);
-                       if (status)
-                              return status;
+                       /* stp is the open stateid */
+                       status = nfs4_check_openmode(stp, lkflg);
+                       if (status)
+                               return status;
+               } else {
+                       /* stp is the lock stateid */
+                       status = nfs4_check_openmode(stp->st_openstp, lkflg);
+                       if (status)
+                               return status;
                }
-
        }
 
        if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
-               printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
+               dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
                return nfserr_bad_stateid;
        }
 
@@ -2215,22 +2205,22 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                goto check_replay;
 
        if (sop->so_confirmed && flags & CONFIRM) {
-               printk("NFSD: preprocess_seqid_op: expected"
+               dprintk("NFSD: preprocess_seqid_op: expected"
                                " unconfirmed stateowner!\n");
                return nfserr_bad_stateid;
        }
        if (!sop->so_confirmed && !(flags & CONFIRM)) {
-               printk("NFSD: preprocess_seqid_op: stateowner not"
+               dprintk("NFSD: preprocess_seqid_op: stateowner not"
                                " confirmed yet!\n");
                return nfserr_bad_stateid;
        }
        if (stateid->si_generation > stp->st_stateid.si_generation) {
-               printk("NFSD: preprocess_seqid_op: future stateid?!\n");
+               dprintk("NFSD: preprocess_seqid_op: future stateid?!\n");
                return nfserr_bad_stateid;
        }
 
        if (stateid->si_generation < stp->st_stateid.si_generation) {
-               printk("NFSD: preprocess_seqid_op: old stateid!\n");
+               dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
                return nfserr_old_stateid;
        }
        renew_client(sop->so_client);
@@ -2242,7 +2232,7 @@ check_replay:
                /* indicate replay to calling function */
                return nfserr_replay_me;
        }
-       printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+       dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
                        sop->so_seqid, seqid);
        *sopp = NULL;
        return nfserr_bad_seqid;
@@ -2561,7 +2551,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
        struct nfs4_stateowner *op;
 
        list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
-               if (cmp_owner_str(op, owner, clid))
+               if (same_owner_str(op, owner, clid))
                        return op;
        }
        return NULL;
@@ -2855,7 +2845,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        file_lock.fl_type = F_WRLCK;
                break;
                default:
-                       printk("NFSD: nfs4_lockt: bad lock type!\n");
+                       dprintk("NFSD: nfs4_lockt: bad lock type!\n");
                        status = nfserr_inval;
                goto out;
        }
@@ -3025,7 +3015,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        INIT_LIST_HEAD(&matches);
        for (i = 0; i < LOCK_HASH_SIZE; i++) {
                list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
-                       if (!cmp_owner_str(sop, owner, clid))
+                       if (!same_owner_str(sop, owner, clid))
                                continue;
                        list_for_each_entry(stp, &sop->so_stateids,
                                        st_perstateowner) {
@@ -3149,11 +3139,14 @@ nfs4_check_open_reclaim(clientid_t *clid)
 
 /* initialization to perform at module load time: */
 
-void
+int
 nfs4_state_init(void)
 {
-       int i;
+       int i, status;
 
+       status = nfsd4_init_slabs();
+       if (status)
+               return status;
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                INIT_LIST_HEAD(&conf_id_hashtbl[i]);
                INIT_LIST_HEAD(&conf_str_hashtbl[i]);
@@ -3182,6 +3175,7 @@ nfs4_state_init(void)
        for (i = 0; i < CLIENT_HASH_SIZE; i++)
                INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
        reclaim_str_hashtbl_size = 0;
+       return 0;
 }
 
 static void
@@ -3242,20 +3236,15 @@ __nfs4_state_start(void)
        set_max_delegations();
 }
 
-int
+void
 nfs4_state_start(void)
 {
-       int status;
-
        if (nfs4_init)
-               return 0;
-       status = nfsd4_init_slabs();
-       if (status)
-               return status;
+               return;
        nfsd4_load_reboot_recovery_data();
        __nfs4_state_start();
        nfs4_init = 1;
-       return 0;
+       return;
 }
 
 int
@@ -3313,7 +3302,6 @@ nfs4_state_shutdown(void)
        nfs4_lock_state();
        nfs4_release_reclaim();
        __nfs4_state_shutdown();
-       nfsd4_free_slabs();
        nfs4_unlock_state();
 }
 
index 8ef0964179bcf4482d7123b5a53bf727f79e77d6..57333944af7fe5c63937472088c29b4725f006d2 100644 (file)
@@ -102,7 +102,8 @@ check_filename(char *str, int len, __be32 err)
 out:                                           \
        return status;                          \
 xdr_error:                                     \
-       printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+       dprintk("NFSD: xdr error (%s:%d)\n",    \
+                       __FILE__, __LINE__);    \
        status = nfserr_bad_xdr;                \
        goto out
 
@@ -124,7 +125,8 @@ xdr_error:                                  \
        if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
                savemem(argp, p, nbytes) :      \
                (char *)p)) {                   \
-               printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+               dprintk("NFSD: xdr error (%s:%d)\n", \
+                               __FILE__, __LINE__); \
                goto xdr_error;                 \
                }                               \
        p += XDR_QUADLEN(nbytes);               \
@@ -140,7 +142,8 @@ xdr_error:                                  \
                p = argp->p;                    \
                argp->p += XDR_QUADLEN(nbytes); \
        } else if (!(p = read_buf(argp, nbytes))) { \
-               printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+               dprintk("NFSD: xdr error (%s:%d)\n", \
+                               __FILE__, __LINE__); \
                goto xdr_error;                 \
        }                                       \
 } while (0)
@@ -948,7 +951,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
         */
        avail = (char*)argp->end - (char*)argp->p;
        if (avail + argp->pagelen < write->wr_buflen) {
-               printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); 
+               dprintk("NFSD: xdr error (%s:%d)\n",
+                               __FILE__, __LINE__);
                goto xdr_error;
        }
        argp->rqstp->rq_vec[0].iov_base = p;
@@ -1019,7 +1023,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
                if (!argp->ops) {
                        argp->ops = argp->iops;
-                       printk(KERN_INFO "nfsd: couldn't allocate room for COMPOUND\n");
+                       dprintk("nfsd: couldn't allocate room for COMPOUND\n");
                        goto xdr_error;
                }
        }
@@ -1326,7 +1330,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
        path = exp->ex_path;
 
        if (strncmp(path, rootpath, strlen(rootpath))) {
-               printk("nfsd: fs_locations failed;"
+               dprintk("nfsd: fs_locations failed;"
                        "%s is not contained in %s\n", path, rootpath);
                *stat = nfserr_notsupp;
                return NULL;
@@ -1475,7 +1479,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        err = vfs_getattr(exp->ex_mnt, dentry, &stat);
        if (err)
                goto out_nfserr;
-       if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
+       if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |
+                       FATTR4_WORD0_MAXNAME)) ||
            (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
                       FATTR4_WORD1_SPACE_TOTAL))) {
                err = vfs_statfs(dentry, &statfs);
@@ -1679,7 +1684,7 @@ out_acl:
        if (bmval0 & FATTR4_WORD0_FILEID) {
                if ((buflen -= 8) < 0)
                        goto out_resource;
-               WRITE64((u64) stat.ino);
+               WRITE64(stat.ino);
        }
        if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
                if ((buflen -= 8) < 0)
@@ -1721,7 +1726,7 @@ out_acl:
        if (bmval0 & FATTR4_WORD0_MAXNAME) {
                if ((buflen -= 4) < 0)
                        goto out_resource;
-               WRITE32(~(u32) 0);
+               WRITE32(statfs.f_namelen);
        }
        if (bmval0 & FATTR4_WORD0_MAXREAD) {
                if ((buflen -= 8) < 0)
@@ -1821,16 +1826,15 @@ out_acl:
                WRITE32(stat.mtime.tv_nsec);
        }
        if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
-               struct dentry *mnt_pnt, *mnt_root;
-
                if ((buflen -= 8) < 0)
                        goto out_resource;
-               mnt_root = exp->ex_mnt->mnt_root;
-               if (mnt_root->d_inode == dentry->d_inode) {
-                       mnt_pnt = exp->ex_mnt->mnt_mountpoint;
-                       WRITE64((u64) mnt_pnt->d_inode->i_ino);
-               } else
-                       WRITE64((u64) stat.ino);
+               if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
+                       err = vfs_getattr(exp->ex_mnt->mnt_parent,
+                               exp->ex_mnt->mnt_mountpoint, &stat);
+                       if (err)
+                               goto out_nfserr;
+               }
+               WRITE64(stat.ino);
        }
        *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
        *countp = p - buffer;
index baac89d917ca9d708cbaf2b643414afb4e076e0e..77dc9893b7bab462b65ebd751d9cc0c01273891f 100644 (file)
@@ -298,7 +298,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
         * qword quoting is used, so filehandle will be \x....
         */
        char *dname, *path;
-       int maxsize;
+       int uninitialized_var(maxsize);
        char *mesg = buf;
        int len;
        struct auth_domain *dom;
@@ -679,11 +679,13 @@ static int __init init_nfsd(void)
        int retval;
        printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
+       retval = nfs4_state_init(); /* nfs4 locking state */
+       if (retval)
+               return retval;
        nfsd_stat_init();       /* Statistics */
        nfsd_cache_init();      /* RPC reply cache */
        nfsd_export_init();     /* Exports table */
        nfsd_lockd_init();      /* lockd->nfsd callbacks */
-       nfs4_state_init();      /* NFSv4 locking state */
        nfsd_idmap_init();      /* Name to ID mapping */
        if (proc_mkdir("fs/nfs", NULL)) {
                struct proc_dir_entry *entry;
@@ -712,6 +714,7 @@ static void __exit exit_nfsd(void)
        nfsd_stat_shutdown();
        nfsd_lockd_shutdown();
        nfsd_idmap_shutdown();
+       nfsd4_free_slabs();
        unregister_filesystem(&nfsd_fs_type);
 }
 
index a8c89ae4c7437bef113f3107ee28e726959b1ebc..1190aeaa92be2e4563c759d04fe96bbc46a0b393 100644 (file)
@@ -349,9 +349,7 @@ nfsd_svc(unsigned short port, int nrservs)
        error = nfsd_racache_init(2*nrservs);
        if (error<0)
                goto out;
-       error = nfs4_state_start();
-       if (error<0)
-               goto out;
+       nfs4_state_start();
 
        nfsd_reset_versions();
 
@@ -546,10 +544,8 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
        /* Now call the procedure handler, and encode NFS status. */
        nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
        nfserr = map_new_errors(rqstp->rq_vers, nfserr);
-       if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2)
-               nfserr = nfserr_dropit;
        if (nfserr == nfserr_dropit) {
-               dprintk("nfsd: Dropping request due to malloc failure!\n");
+               dprintk("nfsd: Dropping request; may be revisited later\n");
                nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
                return 0;
        }
index cb3e7fadb772127975898e14a43c6bd3dd4c4d92..986f9b32083c655f792ada9476d3658a71bb37d7 100644 (file)
@@ -523,6 +523,10 @@ nfssvc_encode_entry(void *ccdv, const char *name,
                cd->common.err = nfserr_toosmall;
                return -EINVAL;
        }
+       if (ino > ~((u32) 0)) {
+               cd->common.err = nfserr_fbig;
+               return -EINVAL;
+       }
        *p++ = xdr_one;                         /* mark entry present */
        *p++ = htonl((u32) ino);                /* file id */
        p    = xdr_encode_array(p, name, namlen);/* name length & name */
index 7867151ebb83b16c6c3bcd446acfead317ec282e..cec78c82b1f9ab11354498fa931f66cd2325a153 100644 (file)
@@ -295,7 +295,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        if (!iap->ia_valid)
                goto out;
 
-       /* NFSv2 does not differentiate between "set-[ac]time-to-now"
+       /*
+        * NFSv2 does not differentiate between "set-[ac]time-to-now"
         * which only requires access, and "set-[ac]time-to-X" which
         * requires ownership.
         * So if it looks like it might be "set both to the same time which
@@ -308,25 +309,33 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
         */
 #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
 #define        MAX_TOUCH_TIME_ERROR (30*60)
-       if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET
-           && iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec
-           ) {
-           /* Looks probable.  Now just make sure time is in the right ballpark.
-            * Solaris, at least, doesn't seem to care what the time request is.
-            * We require it be within 30 minutes of now.
-            */
-           time_t delta = iap->ia_atime.tv_sec - get_seconds();
-           if (delta<0) delta = -delta;
-           if (delta < MAX_TOUCH_TIME_ERROR &&
-               inode_change_ok(inode, iap) != 0) {
-               /* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME
-                * this will cause notify_change to set these times to "now"
+       if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
+           iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
+               /*
+                * Looks probable.
+                *
+                * Now just make sure time is in the right ballpark.
+                * Solaris, at least, doesn't seem to care what the time
+                * request is.  We require it be within 30 minutes of now.
                 */
-               iap->ia_valid &= ~BOTH_TIME_SET;
-           }
+               time_t delta = iap->ia_atime.tv_sec - get_seconds();
+               if (delta < 0)
+                       delta = -delta;
+               if (delta < MAX_TOUCH_TIME_ERROR &&
+                   inode_change_ok(inode, iap) != 0) {
+                       /*
+                        * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
+                        * This will cause notify_change to set these times
+                        * to "now"
+                        */
+                       iap->ia_valid &= ~BOTH_TIME_SET;
+               }
        }
            
-       /* The size case is special. It changes the file as well as the attributes.  */
+       /*
+        * The size case is special.
+        * It changes the file as well as the attributes.
+        */
        if (iap->ia_valid & ATTR_SIZE) {
                if (iap->ia_size < inode->i_size) {
                        err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
index 794118da4ef3ee04877a1bb2122bf81c977f61fd..c95e6a62c01deb623ac1d817a3dda72b5706671b 100644 (file)
@@ -95,8 +95,8 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev)
         * So that old Linux-Sun partitions continue to work,
         * alow the VTOC to be used under the additional condition ...
         */
-       use_vtoc = use_vtoc || !(label->vtoc.sanity |
-                                label->vtoc.version | label->vtoc.nparts);
+       use_vtoc = use_vtoc || !(label->vtoc.sanity ||
+                                label->vtoc.version || label->vtoc.nparts);
        spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
        for (i = 0; i < nparts; i++, p++) {
                unsigned long st_sector;
index 6b3d91a691bf146edeeb7934a366e6ab4c0ff100..e66ec48e95d8f44223ba960e5fe82a9c7acd962d 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -45,8 +45,7 @@ void pipe_wait(struct pipe_inode_info *pipe)
         * Pipes are system-local resources, so sleeping on them
         * is considered a noninteractive wait:
         */
-       prepare_to_wait(&pipe->wait, &wait,
-                       TASK_INTERRUPTIBLE | TASK_NONINTERACTIVE);
+       prepare_to_wait(&pipe->wait, &wait, TASK_INTERRUPTIBLE);
        if (pipe->inode)
                mutex_unlock(&pipe->inode->i_mutex);
        schedule();
@@ -383,7 +382,7 @@ redo:
 
        /* Signal writers asynchronously that there is more room. */
        if (do_wakeup) {
-               wake_up_interruptible(&pipe->wait);
+               wake_up_interruptible_sync(&pipe->wait);
                kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
        }
        if (ret > 0)
@@ -556,7 +555,7 @@ redo2:
 out:
        mutex_unlock(&inode->i_mutex);
        if (do_wakeup) {
-               wake_up_interruptible(&pipe->wait);
+               wake_up_interruptible_sync(&pipe->wait);
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
        }
        if (ret > 0)
@@ -650,7 +649,7 @@ pipe_release(struct inode *inode, int decr, int decw)
        if (!pipe->readers && !pipe->writers) {
                free_pipe_info(inode);
        } else {
-               wake_up_interruptible(&pipe->wait);
+               wake_up_interruptible_sync(&pipe->wait);
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
                kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
        }
index ee4814dd98f9cb5745e2195db44ade96b85cdd5d..27b59f5f3bd1f382ab16401671b5316dd867841d 100644 (file)
@@ -370,6 +370,11 @@ static cputime_t task_stime(struct task_struct *p)
 }
 #endif
 
+static cputime_t task_gtime(struct task_struct *p)
+{
+       return p->gtime;
+}
+
 static int do_task_stat(struct task_struct *task, char *buffer, int whole)
 {
        unsigned long vsize, eip, esp, wchan = ~0UL;
@@ -385,6 +390,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
        unsigned long cmin_flt = 0, cmaj_flt = 0;
        unsigned long  min_flt = 0,  maj_flt = 0;
        cputime_t cutime, cstime, utime, stime;
+       cputime_t cgtime, gtime;
        unsigned long rsslim = 0;
        char tcomm[sizeof(task->comm)];
        unsigned long flags;
@@ -403,6 +409,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
        sigemptyset(&sigign);
        sigemptyset(&sigcatch);
        cutime = cstime = utime = stime = cputime_zero;
+       cgtime = gtime = cputime_zero;
 
        rcu_read_lock();
        if (lock_task_sighand(task, &flags)) {
@@ -420,6 +427,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
                cmaj_flt = sig->cmaj_flt;
                cutime = sig->cutime;
                cstime = sig->cstime;
+               cgtime = sig->cgtime;
                rsslim = sig->rlim[RLIMIT_RSS].rlim_cur;
 
                /* add up live thread stats at the group level */
@@ -430,6 +438,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
                                maj_flt += t->maj_flt;
                                utime = cputime_add(utime, task_utime(t));
                                stime = cputime_add(stime, task_stime(t));
+                               gtime = cputime_add(gtime, task_gtime(t));
                                t = next_thread(t);
                        } while (t != task);
 
@@ -437,6 +446,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
                        maj_flt += sig->maj_flt;
                        utime = cputime_add(utime, sig->utime);
                        stime = cputime_add(stime, sig->stime);
+                       gtime += cputime_add(gtime, sig->gtime);
                }
 
                sid = signal_session(sig);
@@ -454,6 +464,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
                maj_flt = task->maj_flt;
                utime = task_utime(task);
                stime = task_stime(task);
+               gtime = task_gtime(task);
        }
 
        /* scale priority and nice values from timeslices to -20..20 */
@@ -471,7 +482,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
 
        res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n",
                task->pid,
                tcomm,
                state,
@@ -516,7 +527,9 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
                task_cpu(task),
                task->rt_priority,
                task->policy,
-               (unsigned long long)delayacct_blkio_ticks(task));
+               (unsigned long long)delayacct_blkio_ticks(task),
+               cputime_to_clock_t(gtime),
+               cputime_to_clock_t(cgtime));
        if (mm)
                mmput(mm);
        return res;
index 19489b0d5554860e28a1b7e6aeefc5d23fa0d992..e5d0953d4db17f0b81f8f588a02b36887ff4ef5c 100644 (file)
@@ -304,7 +304,7 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer)
        return sprintf(buffer, "%llu %llu %lu\n",
                        task->sched_info.cpu_time,
                        task->sched_info.run_delay,
-                       task->sched_info.pcnt);
+                       task->sched_info.pcount);
 }
 #endif
 
index bee251cb87c8c42c3d051ec2ea53df209e422c52..b872a01ad3af09a335eb7da19818aa533550486e 100644 (file)
@@ -443,6 +443,7 @@ static int show_stat(struct seq_file *p, void *v)
        int i;
        unsigned long jif;
        cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
+       cputime64_t guest;
        u64 sum = 0;
        struct timespec boottime;
        unsigned int *per_irq_sum;
@@ -453,6 +454,7 @@ static int show_stat(struct seq_file *p, void *v)
 
        user = nice = system = idle = iowait =
                irq = softirq = steal = cputime64_zero;
+       guest = cputime64_zero;
        getboottime(&boottime);
        jif = boottime.tv_sec;
 
@@ -467,6 +469,7 @@ static int show_stat(struct seq_file *p, void *v)
                irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq);
                softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
                steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
+               guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
                for (j = 0; j < NR_IRQS; j++) {
                        unsigned int temp = kstat_cpu(i).irqs[j];
                        sum += temp;
@@ -474,7 +477,7 @@ static int show_stat(struct seq_file *p, void *v)
                }
        }
 
-       seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu\n",
+       seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
                (unsigned long long)cputime64_to_clock_t(user),
                (unsigned long long)cputime64_to_clock_t(nice),
                (unsigned long long)cputime64_to_clock_t(system),
@@ -482,7 +485,8 @@ static int show_stat(struct seq_file *p, void *v)
                (unsigned long long)cputime64_to_clock_t(iowait),
                (unsigned long long)cputime64_to_clock_t(irq),
                (unsigned long long)cputime64_to_clock_t(softirq),
-               (unsigned long long)cputime64_to_clock_t(steal));
+               (unsigned long long)cputime64_to_clock_t(steal),
+               (unsigned long long)cputime64_to_clock_t(guest));
        for_each_online_cpu(i) {
 
                /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
@@ -494,7 +498,9 @@ static int show_stat(struct seq_file *p, void *v)
                irq = kstat_cpu(i).cpustat.irq;
                softirq = kstat_cpu(i).cpustat.softirq;
                steal = kstat_cpu(i).cpustat.steal;
-               seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu\n",
+               guest = kstat_cpu(i).cpustat.guest;
+               seq_printf(p,
+                       "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
                        i,
                        (unsigned long long)cputime64_to_clock_t(user),
                        (unsigned long long)cputime64_to_clock_t(nice),
@@ -503,7 +509,8 @@ static int show_stat(struct seq_file *p, void *v)
                        (unsigned long long)cputime64_to_clock_t(iowait),
                        (unsigned long long)cputime64_to_clock_t(irq),
                        (unsigned long long)cputime64_to_clock_t(softirq),
-                       (unsigned long long)cputime64_to_clock_t(steal));
+                       (unsigned long long)cputime64_to_clock_t(steal),
+                       (unsigned long long)cputime64_to_clock_t(guest));
        }
        seq_printf(p, "intr %llu", (unsigned long long)sum);
 
index 67176af8515f816e28c9d013d5cda91ad9e3afe8..283c5720c9de1801e6484173f86df376a49894b9 100644 (file)
@@ -45,7 +45,7 @@ static LIST_HEAD(smb_servers);
 static DEFINE_SPINLOCK(servers_lock);
 
 #define SMBIOD_DATA_READY      (1<<0)
-static long smbiod_flags;
+static unsigned long smbiod_flags;
 
 static int smbiod(void *);
 static int smbiod_start(void);
diff --git a/include/asm-arm/arch-davinci/i2c.h b/include/asm-arm/arch-davinci/i2c.h
new file mode 100644 (file)
index 0000000..e2f5416
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * DaVinci I2C controller platfrom_device info
+ *
+ * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+*/
+
+#ifndef __ASM_ARCH_I2C_H
+#define __ASM_ARCH_I2C_H
+
+/* All frequencies are expressed in kHz */
+struct davinci_i2c_platform_data {
+       unsigned int    bus_freq;       /* standard bus frequency */
+       unsigned int    bus_delay;      /* transaction delay */
+};
+
+#endif /* __ASM_ARCH_I2C_H */
index 1d3caa42a3869b262e05d96a3e7010aa4006c840..eebe56e74d6d9f4ca922ebf7c1ad667a2c66d879 100644 (file)
@@ -228,12 +228,12 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
  */
 #ifndef ioread8
 #define ioread8(p)     ({ unsigned int __v = __raw_readb(p); __v; })
-#define ioread16(p)    ({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; })
-#define ioread32(p)    ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
+#define ioread16(p)    ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __v; })
+#define ioread32(p)    ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __v; })
 
 #define iowrite8(v,p)  __raw_writeb(v, p)
-#define iowrite16(v,p) __raw_writew(cpu_to_le16(v), p)
-#define iowrite32(v,p) __raw_writel(cpu_to_le32(v), p)
+#define iowrite16(v,p) __raw_writew((__force __u16)cpu_to_le16(v), p)
+#define iowrite32(v,p) __raw_writel((__force __u32)cpu_to_le32(v), p)
 
 #define ioread8_rep(p,d,c)     __raw_readsb(p,d,c)
 #define ioread16_rep(p,d,c)    __raw_readsw(p,d,c)
index fcc8b4c34c6a628fedb54ce01f9c44d4dbe4a9df..14cb10cc24ae587cce7ec774ce57767e8f37cde3 100644 (file)
@@ -55,6 +55,7 @@
 #define CH_SPORT3_RX           20
 #define CH_SPORT3_TX           21
 #define CH_SDH                 22
+#define CH_NFC                 22
 #define CH_SPI2                        23
 
 #define CH_MEM_STREAM0_DEST    24
diff --git a/include/asm-blackfin/nand.h b/include/asm-blackfin/nand.h
new file mode 100644 (file)
index 0000000..afbaafa
--- /dev/null
@@ -0,0 +1,47 @@
+/* linux/include/asm-blackfin/nand.h
+ *
+ * Copyright (c) 2007 Analog Devices, Inc.
+ *     Bryan Wu <bryan.wu@analog.com>
+ *
+ * BF5XX - NAND flash controller platfrom_device info
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* struct bf5xx_nand_platform
+ *
+ * define a interface between platfrom board specific code and
+ * bf54x NFC driver.
+ *
+ * nr_partitions = number of partitions pointed to be partitoons (or zero)
+ * partitions   = mtd partition list
+ */
+
+#define NFC_PG_SIZE_256                0
+#define NFC_PG_SIZE_512                1
+#define NFC_PG_SIZE_OFFSET     9
+
+#define NFC_NWIDTH_8           0
+#define NFC_NWIDTH_16          1
+#define NFC_NWIDTH_OFFSET      8
+
+#define NFC_RDDLY_OFFSET       4
+#define NFC_WRDLY_OFFSET       0
+
+#define NFC_STAT_NBUSY         1
+
+struct bf5xx_nand_platform {
+       /* NAND chip information */
+       unsigned short          page_size;
+       unsigned short          data_width;
+
+       /* RD/WR strobe delay timing information, all times in SCLK cycles */
+       unsigned short          rd_dly;
+       unsigned short          wr_dly;
+
+       /* NAND MTD partition information */
+       int                     nr_partitions;
+       struct mtd_partition    *partitions;
+};
index 6931af525da3201873274337a993d342d2c9b14b..9f5663ba19f8eaad3ee4680d81894b18b1748ba0 100644 (file)
@@ -253,7 +253,10 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
        __typeof__(*(ptr)) __xg_new = (new);                                    \
                                                                                \
        switch (sizeof(__xg_orig)) {                                            \
-       case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break; \
+       case 4: __xg_orig = (__force __typeof__(*ptr))                          \
+                       __cmpxchg_32((__force uint32_t *)__xg_ptr,              \
+                                        (__force uint32_t)__xg_test,           \
+                                        (__force uint32_t)__xg_new); break;    \
        default:                                                                \
                __xg_orig = 0;                                                  \
                asm volatile("break");                                          \
index 0240e0506a078582e6544aa7b2d4ab57ef711df2..5615440027ec545b069f6477e61d85273b4a674a 100644 (file)
 #define TEXT_TEXT                                                      \
                ALIGN_FUNCTION();                                       \
                *(.text)                                                \
-               *(.text.init.refok)
+               *(.text.init.refok)                                     \
+               *(.exit.text.refok)
 
 /* sched.text is aling to function alignment to secure we have same
  * address even at second ld pass when generating System.map */
index edd5d01028df93d8d88ad68dbdd1322261bee790..823553bf12e6681861297cbcbcf746a1c0a1a460 100644 (file)
@@ -151,6 +151,8 @@ extern void ia64_mca_cmc_vector_setup(void);
 extern int  ia64_reg_MCA_extension(int (*fn)(void *, struct ia64_sal_os_state *));
 extern void ia64_unreg_MCA_extension(void);
 extern u64 ia64_get_rnat(u64 *);
+extern void ia64_mca_printk(const char * fmt, ...)
+        __attribute__ ((format (printf, 1, 2)));
 
 struct ia64_mca_notify_die {
        struct ia64_sal_os_state *sos;
index 46cadf5aaac57a3dd1136f2e140905103c4188e0..1f5412d6f9bb67c97ca25ff51937dfc2e0a34ec4 100644 (file)
 extern spinlock_t sal_lock;
 
 /* SAL spec _requires_ eight args for each call. */
-#define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7)     \
-       result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7)
+#define __IA64_FW_CALL(entry,result,a0,a1,a2,a3,a4,a5,a6,a7)   \
+       result = (*entry)(a0,a1,a2,a3,a4,a5,a6,a7)
 
-# define SAL_CALL(result,args...) do {                         \
+# define IA64_FW_CALL(entry,result,args...) do {               \
        unsigned long __ia64_sc_flags;                          \
        struct ia64_fpreg __ia64_sc_fr[6];                      \
        ia64_save_scratch_fpregs(__ia64_sc_fr);                 \
        spin_lock_irqsave(&sal_lock, __ia64_sc_flags);          \
-       __SAL_CALL(result, args);                               \
+       __IA64_FW_CALL(entry, result, args);                    \
        spin_unlock_irqrestore(&sal_lock, __ia64_sc_flags);     \
        ia64_load_scratch_fpregs(__ia64_sc_fr);                 \
 } while (0)
 
+# define SAL_CALL(result,args...)                      \
+       IA64_FW_CALL(ia64_sal, result, args);
+
 # define SAL_CALL_NOLOCK(result,args...) do {          \
        unsigned long __ia64_scn_flags;                 \
        struct ia64_fpreg __ia64_scn_fr[6];             \
        ia64_save_scratch_fpregs(__ia64_scn_fr);        \
        local_irq_save(__ia64_scn_flags);               \
-       __SAL_CALL(result, args);                       \
+       __IA64_FW_CALL(ia64_sal, result, args);         \
        local_irq_restore(__ia64_scn_flags);            \
        ia64_load_scratch_fpregs(__ia64_scn_fr);        \
 } while (0)
@@ -73,7 +76,7 @@ extern spinlock_t sal_lock;
        struct ia64_fpreg __ia64_scs_fr[6];             \
        ia64_save_scratch_fpregs(__ia64_scs_fr);        \
        preempt_disable();                              \
-       __SAL_CALL(result, args);                       \
+       __IA64_FW_CALL(ia64_sal, result, args);         \
        preempt_enable();                               \
        ia64_load_scratch_fpregs(__ia64_scs_fr);        \
 } while (0)
index c68e1680da0173d5754d1a1df4944120a5239e58..1a922fad76f753aa66e8d212828935861892865a 100644 (file)
@@ -1 +1,2 @@
 include include/asm-generic/Kbuild.asm
+header-y += cachectl.h
index a30fe9c64143e4d5505b9c85adabf30074c85888..87f77b11931772245001d68e10ea863d3de446eb 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 
+/* whitelist for checksyscalls */
+#define __IGNORE_restart_syscall
+
 /*
  * "Conditional" syscalls
  *
index 41cf050b68104060f20fca1e750885bd7bd8b38d..1003e7156bfcbf08d039ad130e69d017dde7bc1c 100644 (file)
@@ -154,7 +154,7 @@ int64_t cfe_getticks(void);
 #define cfe_readblk(a, b, c, d)                __cfe_readblk(a, b, c, d)
 #define cfe_setenv(a, b)               __cfe_setenv(a, b)
 #define cfe_write(a, b, c)             __cfe_write(a, b, c)
-#define cfe_writeblk(a, b, c, d                __cfe_writeblk(a, b, c, d)
+#define cfe_writeblk(a, b, c, d)       __cfe_writeblk(a, b, c, d)
 #endif                         /* CFE_API_IMPL_NAMESPACE */
 
 int cfe_close(int handle);
diff --git a/include/asm-mips/mach-au1x00/prom.h b/include/asm-mips/mach-au1x00/prom.h
new file mode 100644 (file)
index 0000000..e387155
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __AU1X00_PROM_H
+#define __AU1X00_PROM_H
+
+extern int prom_argc;
+extern char **prom_argv;
+extern char **prom_envp;
+
+extern void prom_init_cmdline(void);
+extern char *prom_getcmdline(void);
+extern char *prom_getenv(char *envname);
+extern int prom_get_ethernet_addr(char *ethernet_addr);
+
+#endif
index 6b82c3ba495a37c14b0d9b3df4d426fc4b78e5b7..08532ff1899ca8947f44243ad1e7792bb6d2c3f9 100644 (file)
@@ -33,16 +33,16 @@ typedef struct {
 
 extern dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
                          unsigned int dcr_c);
-extern void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c);
+extern void dcr_unmap(dcr_host_t host, unsigned int dcr_c);
 
 static inline u32 dcr_read(dcr_host_t host, unsigned int dcr_n)
 {
-       return in_be32(host.token + dcr_n * host.stride);
+       return in_be32(host.token + ((host.base + dcr_n) * host.stride));
 }
 
 static inline void dcr_write(dcr_host_t host, unsigned int dcr_n, u32 value)
 {
-       out_be32(host.token + dcr_n * host.stride, value);
+       out_be32(host.token + ((host.base + dcr_n) * host.stride), value);
 }
 
 extern u64 of_translate_dcr_address(struct device_node *dev,
index f41058c0f6cb95ebc2d18db98ac7d5210b65b2c8..8dbb1ab0aa04d2fce6a0e4c858ee0357875e2cc1 100644 (file)
@@ -29,9 +29,9 @@ typedef struct {
 #define DCR_MAP_OK(host)       (1)
 
 #define dcr_map(dev, dcr_n, dcr_c)     ((dcr_host_t){ .base = (dcr_n) })
-#define dcr_unmap(host, dcr_n, dcr_c)  do {} while (0)
-#define dcr_read(host, dcr_n)          mfdcr(dcr_n)
-#define dcr_write(host, dcr_n, value)  mtdcr(dcr_n, value)
+#define dcr_unmap(host, dcr_c)         do {} while (0)
+#define dcr_read(host, dcr_n)          mfdcr(dcr_n + host.base)
+#define dcr_write(host, dcr_n, value)  mtdcr(dcr_n + host.base, value)
 
 /* Device Control Registers */
 void __mtdcr(int reg, unsigned int val);
index affba7052fb6dc935cc9fa41594306b9dcf13f0a..0d0589ef8ea68314ae6c8af77413a5022b50326a 100644 (file)
@@ -138,12 +138,12 @@ DEF_MMIO_IN_BE(in_be64, 64, ld);
 /* There is no asm instructions for 64 bits reverse loads and stores */
 static inline u64 in_le64(const volatile u64 __iomem *addr)
 {
-       return le64_to_cpu(in_be64(addr));
+       return swab64(in_be64(addr));
 }
 
 static inline void out_le64(volatile u64 __iomem *addr, u64 val)
 {
-       out_be64(addr, cpu_to_le64(val));
+       out_be64(addr, swab64(val));
 }
 #endif /* __powerpc64__ */
 
index 07f62ec9ff0c8b9309d223f0424b0926afb86f4b..aa558da084715874d5169f5b3a58863db83849ee 100644 (file)
@@ -1,16 +1,47 @@
 #ifndef __ASM_SH_CACHEFLUSH_H
 #define __ASM_SH_CACHEFLUSH_H
+
 #ifdef __KERNEL__
 
-#include <linux/mm.h>
+#ifdef CONFIG_CACHE_OFF
+/*
+ * Nothing to do when the cache is disabled, initial flush and explicit
+ * disabling is handled at CPU init time.
+ *
+ * See arch/sh/kernel/cpu/init.c:cache_init().
+ */
+#define p3_cache_init()                                do { } while (0)
+#define flush_cache_all()                      do { } while (0)
+#define flush_cache_mm(mm)                     do { } while (0)
+#define flush_cache_dup_mm(mm)                 do { } while (0)
+#define flush_cache_range(vma, start, end)     do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define flush_dcache_page(page)                        do { } while (0)
+#define flush_icache_range(start, end)         do { } while (0)
+#define flush_icache_page(vma,pg)              do { } while (0)
+#define flush_dcache_mmap_lock(mapping)                do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
+#define flush_cache_sigtramp(vaddr)            do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
+#define __flush_wback_region(start, size)      do { (void)(start); } while (0)
+#define __flush_purge_region(start, size)      do { (void)(start); } while (0)
+#define __flush_invalidate_region(start, size) do { (void)(start); } while (0)
+#else
 #include <asm/cpu/cacheflush.h>
 
+/*
+ * Consistent DMA requires that the __flush_xxx() primitives must be set
+ * for any of the enabled non-coherent caches (most of the UP CPUs),
+ * regardless of PIPT or VIPT cache configurations.
+ */
+
 /* Flush (write-back only) a region (smaller than a page) */
 extern void __flush_wback_region(void *start, int size);
 /* Flush (write-back & invalidate) a region (smaller than a page) */
 extern void __flush_purge_region(void *start, int size);
 /* Flush (invalidate only) a region (smaller than a page) */
 extern void __flush_invalidate_region(void *start, int size);
+#endif
 
 #define flush_cache_vmap(start, end)           flush_cache_all()
 #define flush_cache_vunmap(start, end)         flush_cache_all()
index ffe08d2813f996152b5cdba1fb626372ecbcabdb..255016fc91f09b7eecd1e725379881e65b4e9571 100644 (file)
@@ -26,7 +26,9 @@
 #define CCR_CACHE_ENABLE       CCR_CACHE_CE
 #define CCR_CACHE_INVALIDATE   CCR_CACHE_CF
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720)
 #define CCR3   0xa40000b4
 #define CCR_CACHE_16KB  0x00010000
 #define CCR_CACHE_32KB 0x00020000
index 3a66dc458023ecb371e4496664fa9caf67b7cf66..54bfece328c2724df33f44cf52e44ff8d96adc93 100644 (file)
@@ -1,7 +1,20 @@
 #ifndef __ASM_CPU_SH3_DMA_H
 #define __ASM_CPU_SH3_DMA_H
 
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+#define SH_DMAC_BASE   0xa4010020
+
+#define DMTE0_IRQ      48
+#define DMTE1_IRQ      49
+#define DMTE2_IRQ      50
+#define DMTE3_IRQ      51
+#define DMTE4_IRQ      76
+#define DMTE5_IRQ      77
+
+#else
 #define SH_DMAC_BASE   0xa4000020
+#endif
 
 /* Definitions for the SuperH DMAC */
 #define TM_BURST       0x00000020
diff --git a/include/asm-sh/cpu-sh3/gpio.h b/include/asm-sh/cpu-sh3/gpio.h
new file mode 100644 (file)
index 0000000..48770c1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  include/asm-sh/cpu-sh3/gpio.h
+ *
+ *  Copyright (C) 2007  Markus Brunner, Mark Jonas
+ *
+ *  Addresses for the Pin Function Controller
+ *
+ * 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 more details.
+ */
+#ifndef _CPU_SH3_GPIO_H
+#define _CPU_SH3_GPIO_H
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+
+/* Control registers */
+#define PORT_PACR      0xA4050100UL
+#define PORT_PBCR      0xA4050102UL
+#define PORT_PCCR      0xA4050104UL
+#define PORT_PDCR      0xA4050106UL
+#define PORT_PECR      0xA4050108UL
+#define PORT_PFCR      0xA405010AUL
+#define PORT_PGCR      0xA405010CUL
+#define PORT_PHCR      0xA405010EUL
+#define PORT_PJCR      0xA4050110UL
+#define PORT_PKCR      0xA4050112UL
+#define PORT_PLCR      0xA4050114UL
+#define PORT_PMCR      0xA4050116UL
+#define PORT_PPCR      0xA4050118UL
+#define PORT_PRCR      0xA405011AUL
+#define PORT_PSCR      0xA405011CUL
+#define PORT_PTCR      0xA405011EUL
+#define PORT_PUCR      0xA4050120UL
+#define PORT_PVCR      0xA4050122UL
+
+/* Data registers */
+#define PORT_PADR      0xA4050140UL
+/* Address of PORT_PBDR is wrong in the datasheet, see errata 2005-09-21 */
+#define PORT_PBDR      0xA4050142UL
+#define PORT_PCDR      0xA4050144UL
+#define PORT_PDDR      0xA4050146UL
+#define PORT_PEDR      0xA4050148UL
+#define PORT_PFDR      0xA405014AUL
+#define PORT_PGDR      0xA405014CUL
+#define PORT_PHDR      0xA405014EUL
+#define PORT_PJDR      0xA4050150UL
+#define PORT_PKDR      0xA4050152UL
+#define PORT_PLDR      0xA4050154UL
+#define PORT_PMDR      0xA4050156UL
+#define PORT_PPDR      0xA4050158UL
+#define PORT_PRDR      0xA405015AUL
+#define PORT_PSDR      0xA405015CUL
+#define PORT_PTDR      0xA405015EUL
+#define PORT_PUDR      0xA4050160UL
+#define PORT_PVDR      0xA4050162UL
+
+/* Pin Select Registers */
+#define PORT_PSELA     0xA4050124UL
+#define PORT_PSELB     0xA4050126UL
+#define PORT_PSELC     0xA4050128UL
+#define PORT_PSELD     0xA405012AUL
+
+#endif
+
+#endif
index b20786d42d0919adbd1d14f7e11c7ff07041dd40..16c2d63b7e39ef7b392eb7662739a1aef7791cc6 100644 (file)
 #define TRA    0xffffffd0
 #define EXPEVT 0xffffffd4
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
     defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7710) || \
     defined(CONFIG_CPU_SUBTYPE_SH7712) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7710)
+    defined(CONFIG_CPU_SUBTYPE_SH7720)
 #define INTEVT 0xa4000000      /* INTEVTE2(0xa4000000) */
 #else
 #define INTEVT 0xffffffd8
index b6c2020a2ad3b1a6d1f995d189434050353dbf38..3880ce047fe0c1b02af1dba8cc1c049c6a99db1b 100644 (file)
  * ---------------------------------------------------------------------------
  */
 
-#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+#if  !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
+     !defined(CONFIG_CPU_SUBTYPE_SH7727)
 #define TMU_TOCR       0xfffffe90      /* Byte access */
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720)
 #define TMU_012_TSTR   0xa412fe92      /* Byte access */
 
 #define TMU0_TCOR      0xa412fe94      /* Long access */
@@ -56,7 +58,8 @@
 #define TMU2_TCOR      0xfffffeac      /* Long access */
 #define TMU2_TCNT      0xfffffeb0      /* Long access */
 #define TMU2_TCR       0xfffffeb4      /* Word access */
-#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
+    !defined(CONFIG_CPU_SUBTYPE_SH7727)
 #define TMU2_TCPR2     0xfffffeb8      /* Long access */
 #endif
 #endif
index 9d308cbe9b29240064030fb9004a456123e46dba..18467c574534aebf55d65d03c9756d368219057d 100644 (file)
@@ -11,7 +11,8 @@
 #ifndef __ASM_CPU_SH3_UBC_H
 #define __ASM_CPU_SH3_UBC_H
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720)
 #define UBC_BARA               0xa4ffffb0
 #define UBC_BAMRA              0xa4ffffb4
 #define UBC_BBRA               0xa4ffffb8
index 36e26a964765ebcb0bd994d31ffbe742d0d83ef3..aaf71b018c281399ade954200171fc60400c8f33 100644 (file)
@@ -31,7 +31,7 @@
 #define TS_32          0x00000030
 #define TS_64          0x00000000
 
-#define CHCR_TS_MASK   0x30
+#define CHCR_TS_MASK   0x70
 #define CHCR_TS_SHIFT  4
 
 #define DMAOR_COD      0x00000008
index ff4c5fbbfaf038206de9b33e93f2c6a27bb5f738..979acddc0f8ebe76cda3d3ece1c51d378c7b2667 100644 (file)
 #define MMU_UTLB_ADDRESS_ARRAY 0xF6000000
 #define MMU_PAGE_ASSOC_BIT     0x80
 
-#define MMU_NTLB_ENTRIES       64      /* for 7750 */
+#ifdef CONFIG_X2TLB
+#define MMUCR_ME               (1 << 7)
+#else
+#define MMUCR_ME               (0)
+#endif
+
 #ifdef CONFIG_SH_STORE_QUEUES
-#define MMU_CONTROL_INIT       0x05    /* SQMD=0, SV=0, TI=1, AT=1 */
+#define MMUCR_SQMD             (1 << 9)
 #else
-#define MMU_CONTROL_INIT       0x205   /* SQMD=1, SV=0, TI=1, AT=1 */
+#define MMUCR_SQMD             (0)
 #endif
 
+#define MMU_NTLB_ENTRIES       64
+#define MMU_CONTROL_INIT       (0x05|MMUCR_SQMD|MMUCR_ME)
+
 #define MMU_ITLB_DATA_ARRAY    0xF3000000
 #define MMU_UTLB_DATA_ARRAY    0xF7000000
 
index 4c75b70b64143be6a1cb7de0234e9633b3e06a95..a65b02fd186ef4ec2bf2976846c4bdcd6b9f2201 100644 (file)
@@ -152,14 +152,9 @@ extern struct dma_info *get_dma_info_by_name(const char *dmac_name);
 extern int dma_extend(unsigned int chan, unsigned long op, void *param);
 extern int register_chan_caps(const char *dmac, struct dma_chan_caps *capslist);
 
-#ifdef CONFIG_SYSFS
 /* arch/sh/drivers/dma/dma-sysfs.c */
 extern int dma_create_sysfs_files(struct dma_channel *, struct dma_info *);
 extern void dma_remove_sysfs_files(struct dma_channel *, struct dma_info *);
-#else
-#define dma_create_sysfs_file(channel, info)           do { } while (0)
-#define dma_remove_sysfs_file(channel, info)           do { } while (0)
-#endif
 
 #ifdef CONFIG_PCI
 extern int isa_dma_bridge_buggy;
diff --git a/include/asm-sh/dreamcast/maple.h b/include/asm-sh/dreamcast/maple.h
new file mode 100644 (file)
index 0000000..51f6a87
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __ASM_MAPLE_H
+#define __ASM_MAPLE_H
+
+#define MAPLE_PORTS 4
+#define MAPLE_PNP_INTERVAL HZ
+#define MAPLE_MAXPACKETS 8
+#define MAPLE_DMA_ORDER 14
+#define MAPLE_DMA_SIZE (1 << MAPLE_DMA_ORDER)
+#define MAPLE_DMA_PAGES ((MAPLE_DMA_ORDER > PAGE_SHIFT) ? \
+                         MAPLE_DMA_ORDER - PAGE_SHIFT : 0)
+
+/* Maple Bus registers */
+#define MAPLE_BASE     0xa05f6c00
+#define MAPLE_DMAADDR  (MAPLE_BASE+0x04)
+#define MAPLE_TRIGTYPE (MAPLE_BASE+0x10)
+#define MAPLE_ENABLE   (MAPLE_BASE+0x14)
+#define MAPLE_STATE    (MAPLE_BASE+0x18)
+#define MAPLE_SPEED    (MAPLE_BASE+0x80)
+#define MAPLE_RESET    (MAPLE_BASE+0x8c)
+
+#define MAPLE_MAGIC    0x6155404f
+#define MAPLE_2MBPS    0
+#define MAPLE_TIMEOUT(n) ((n)<<15)
+
+/* Function codes */
+#define MAPLE_FUNC_CONTROLLER 0x001
+#define MAPLE_FUNC_MEMCARD    0x002
+#define MAPLE_FUNC_LCD        0x004
+#define MAPLE_FUNC_CLOCK      0x008
+#define MAPLE_FUNC_MICROPHONE 0x010
+#define MAPLE_FUNC_ARGUN      0x020
+#define MAPLE_FUNC_KEYBOARD   0x040
+#define MAPLE_FUNC_LIGHTGUN   0x080
+#define MAPLE_FUNC_PURUPURU   0x100
+#define MAPLE_FUNC_MOUSE      0x200
+
+#endif /* __ASM_MAPLE_H */
diff --git a/include/asm-sh/gpio.h b/include/asm-sh/gpio.h
new file mode 100644 (file)
index 0000000..9bb27e0
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *  include/asm-sh/gpio.h
+ *
+ *  Copyright (C) 2007 Markus Brunner, Mark Jonas
+ *
+ *  Addresses for the Pin Function Controller
+ *
+ * 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 more details.
+ */
+#ifndef __ASM_SH_GPIO_H
+#define __ASM_SH_GPIO_H
+
+#if defined(CONFIG_CPU_SH3)
+#include <asm/cpu/gpio.h>
+#endif
+
+#endif /* __ASM_SH_GPIO_H */
index 4dd8592ca014c7ada908196761623e980817fd1b..342ca55a266aab883d6f7dc615e40b9ead49a5f1 100644 (file)
 #define        HD64461_NIMR            (CONFIG_HD64461_IOBASE + 0x5002)
 
 #define        HD64461_IRQBASE         OFFCHIP_IRQ_BASE
+#define        OFFCHIP_IRQ_BASE        64
 #define        HD64461_IRQ_NUM         16
 
 #define        HD64461_IRQ_UART        (HD64461_IRQBASE+5)
diff --git a/include/asm-sh/heartbeat.h b/include/asm-sh/heartbeat.h
new file mode 100644 (file)
index 0000000..724a43e
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __ASM_SH_HEARTBEAT_H
+#define __ASM_SH_HEARTBEAT_H
+
+#include <linux/timer.h>
+
+#define HEARTBEAT_INVERTED     (1 << 0)
+
+struct heartbeat_data {
+       void __iomem *base;
+       unsigned char *bit_pos;
+       unsigned int nr_bits;
+       struct timer_list timer;
+       unsigned int regsize;
+       unsigned long flags;
+};
+
+#endif /* __ASM_SH_HEARTBEAT_H */
index 20d42959f52ad25d3da5a7c5824b03a96cbffb73..cb0b6c9f7020232c71f9e4d6ad8d033e18e2f3d5 100644 (file)
@@ -6,24 +6,6 @@
 
 extern atomic_t irq_err_count;
 
-struct intc2_data {
-       unsigned short irq;
-       unsigned char ipr_offset, ipr_shift;
-       unsigned char msk_offset, msk_shift;
-       unsigned char priority;
-};
-
-struct intc2_desc {
-       unsigned long prio_base;
-       unsigned long msk_base;
-       unsigned long mskclr_base;
-       struct intc2_data *intc2_data;
-       unsigned int nr_irqs;
-       struct irq_chip chip;
-};
-
-void register_intc2_controller(struct intc2_desc *);
-
 struct ipr_data {
        unsigned char irq;
        unsigned char ipr_idx;          /* Index for the IPR registered */
@@ -41,11 +23,6 @@ struct ipr_desc {
 
 void register_ipr_controller(struct ipr_desc *);
 
-/*
- * Enable individual interrupt mode for external IPR IRQs.
- */
-void __init ipr_irq_enable_irlm(void);
-
 typedef unsigned char intc_enum;
 
 struct intc_vect {
@@ -54,6 +31,7 @@ struct intc_vect {
 };
 
 #define INTC_VECT(enum_id, vect) { enum_id, vect }
+#define INTC_IRQ(enum_id, irq) INTC_VECT(enum_id, irq2evt(irq))
 
 struct intc_prio {
        intc_enum enum_id;
@@ -64,19 +42,25 @@ struct intc_prio {
 
 struct intc_group {
        intc_enum enum_id;
-       intc_enum *enum_ids;
+       intc_enum enum_ids[32];
 };
 
-#define INTC_GROUP(enum_id, ids...) { enum_id, (intc_enum []) { ids, 0 } }
+#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } }
 
 struct intc_mask_reg {
        unsigned long set_reg, clr_reg, reg_width;
        intc_enum enum_ids[32];
+#ifdef CONFIG_SMP
+       unsigned long smp;
+#endif
 };
 
 struct intc_prio_reg {
-       unsigned long reg, reg_width, field_width;
+       unsigned long set_reg, clr_reg, reg_width, field_width;
        intc_enum enum_ids[16];
+#ifdef CONFIG_SMP
+       unsigned long smp;
+#endif
 };
 
 struct intc_sense_reg {
@@ -84,6 +68,12 @@ struct intc_sense_reg {
        intc_enum enum_ids[16];
 };
 
+#ifdef CONFIG_SMP
+#define INTC_SMP(stride, nr) .smp = (stride) | ((nr) << 8)
+#else
+#define INTC_SMP(stride, nr)
+#endif
+
 struct intc_desc {
        struct intc_vect *vectors;
        unsigned int nr_vectors;
@@ -97,25 +87,28 @@ struct intc_desc {
        unsigned int nr_prio_regs;
        struct intc_sense_reg *sense_regs;
        unsigned int nr_sense_regs;
-       struct irq_chip chip;
+       char *name;
 };
 
 #define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
 #define DECLARE_INTC_DESC(symbol, chipname, vectors, groups,           \
        priorities, mask_regs, prio_regs, sense_regs)                   \
-struct intc_desc symbol = {                                            \
+struct intc_desc symbol __initdata = {                                 \
        _INTC_ARRAY(vectors), _INTC_ARRAY(groups),                      \
        _INTC_ARRAY(priorities),                                        \
        _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs),                 \
        _INTC_ARRAY(sense_regs),                                        \
-       .chip.name = chipname,                                          \
+       chipname,                                                       \
 }
 
 void __init register_intc_controller(struct intc_desc *desc);
+int intc_set_priority(unsigned int irq, unsigned int prio);
 
 void __init plat_irq_setup(void);
 
-enum { IRQ_MODE_IRQ, IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
+enum { IRQ_MODE_IRQ, IRQ_MODE_IRQ7654, IRQ_MODE_IRQ3210,
+       IRQ_MODE_IRL7654_MASK, IRQ_MODE_IRL3210_MASK,
+       IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
 void __init plat_irq_setup_pins(int mode);
 
 #endif /* __ASM_SH_HW_IRQ_H */
diff --git a/include/asm-sh/ilsel.h b/include/asm-sh/ilsel.h
new file mode 100644 (file)
index 0000000..e3d304b
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __ASM_SH_ILSEL_H
+#define __ASM_SH_ILSEL_H
+
+typedef enum {
+       ILSEL_NONE,
+       ILSEL_LAN,
+       ILSEL_USBH_I,
+       ILSEL_USBH_S,
+       ILSEL_USBH_V,
+       ILSEL_RTC,
+       ILSEL_USBP_I,
+       ILSEL_USBP_S,
+       ILSEL_USBP_V,
+       ILSEL_KEY,
+
+       /*
+        * ILSEL Aliases - corner cases for interleaved level tables.
+        *
+        * Someone thought this was a good idea and less hassle than
+        * demuxing a shared vector, really.
+        */
+
+       /* ILSEL0 and 2 */
+       ILSEL_FPGA0,
+       ILSEL_FPGA1,
+       ILSEL_EX1,
+       ILSEL_EX2,
+       ILSEL_EX3,
+       ILSEL_EX4,
+
+       /* ILSEL1 and 3 */
+       ILSEL_FPGA2 = ILSEL_FPGA0,
+       ILSEL_FPGA3 = ILSEL_FPGA1,
+       ILSEL_EX5 = ILSEL_EX1,
+       ILSEL_EX6 = ILSEL_EX2,
+       ILSEL_EX7 = ILSEL_EX3,
+       ILSEL_EX8 = ILSEL_EX4,
+} ilsel_source_t;
+
+/* arch/sh/boards/renesas/x3proto/ilsel.c */
+int ilsel_enable(ilsel_source_t set);
+int ilsel_enable_fixed(ilsel_source_t set, unsigned int level);
+void ilsel_disable(unsigned int irq);
+
+#endif /* __ASM_SH_ILSEL_H */
index e6a1877dcb205a79c4b7baa62371c27399a51795..1a336cdc75fed1a5a3e9bca2a90178eeb21bca2c 100644 (file)
@@ -135,6 +135,32 @@ void __raw_readsl(unsigned long addr, void *data, int longlen);
 # define writel(v,a)   ({ __raw_writel((v),(a)); mb(); })
 #endif
 
+#define __BUILD_MEMORY_STRING(bwlq, type)                              \
+                                                                       \
+static inline void writes##bwlq(volatile void __iomem *mem,            \
+                               const void *addr, unsigned int count)   \
+{                                                                      \
+       const volatile type *__addr = addr;                             \
+                                                                       \
+       while (count--) {                                               \
+               __raw_write##bwlq(*__addr, mem);                        \
+               __addr++;                                               \
+       }                                                               \
+}                                                                      \
+                                                                       \
+static inline void reads##bwlq(volatile void __iomem *mem, void *addr, \
+                              unsigned int count)                      \
+{                                                                      \
+       volatile type *__addr = addr;                                   \
+                                                                       \
+       while (count--) {                                               \
+               *__addr = __raw_read##bwlq(mem);                        \
+               __addr++;                                               \
+       }                                                               \
+}
+
+__BUILD_MEMORY_STRING(b, u8)
+__BUILD_MEMORY_STRING(w, u16)
 #define writesl __raw_writesl
 #define readsl  __raw_readsl
 
index 74bd0953e5ceb81bcc5c8be0cdf77cb65cabdcd1..4bc8cb187d119a8d66bff3995b9f7add0d79e09d 100644 (file)
@@ -17,9 +17,6 @@
 #define __KGDB_H
 
 #include <asm/ptrace.h>
-#include <asm/cacheflush.h>
-
-struct console;
 
 /* Same as pt_regs but has vbr in place of syscall_nr */
 struct kgdb_regs {
@@ -35,10 +32,7 @@ struct kgdb_regs {
 
 /* State info */
 extern char kgdb_in_gdb_mode;
-extern int kgdb_done_init;
-extern int kgdb_enabled;
 extern int kgdb_nofault;       /* Ignore bus errors (in gdb mem access) */
-extern int kgdb_halt;          /* Execute initial breakpoint at startup */
 extern char in_nmi;            /* Debounce flag to prevent NMI reentry*/
 
 /* SCI */
@@ -59,6 +53,7 @@ extern kgdb_debug_hook_t  *kgdb_debug_hook;
 extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
 
 /* Console */
+struct console;
 void kgdb_console_write(struct console *co, const char *s, unsigned count);
 extern int kgdb_console_setup(struct console *, char *);
 
@@ -69,22 +64,7 @@ extern void    longjmp(jmp_buf __jmpb, int __retval);
 extern int     setjmp(jmp_buf __jmpb);
 
 /* Forced breakpoint */
-#define breakpoint()                                   \
-do {                                                   \
-       if (kgdb_enabled)                               \
-               __asm__ __volatile__("trapa   #0x3c");  \
-} while (0)
-
-/* KGDB should be able to flush all kernel text space */
-#if defined(CONFIG_CPU_SH4)
-#define kgdb_flush_icache_range(start, end) \
-{                                                                      \
-       __flush_purge_region((void*)(start), (int)(end) - (int)(start));\
-       flush_icache_range((start), (end));                             \
-}
-#else
-#define kgdb_flush_icache_range(start, end)    do { } while (0)
-#endif
+#define breakpoint()   __asm__ __volatile__("trapa   #0x3c")
 
 /* Taken from sh-stub.c of GDB 4.18 */
 static const char hexchars[] = "0123456789abcdef";
diff --git a/include/asm-sh/magicpanelr2.h b/include/asm-sh/magicpanelr2.h
new file mode 100644 (file)
index 0000000..c644a77
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  include/asm-sh/magicpanelr2.h
+ *
+ *  Copyright (C) 2007  Markus Brunner, Mark Jonas
+ *
+ *  I/O addresses and bitmasks for Magic Panel Release 2 board
+ *
+ * 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 more details.
+ */
+
+#ifndef __ASM_SH_MAGICPANELR2_H
+#define __ASM_SH_MAGICPANELR2_H
+
+#include <asm/gpio.h>
+
+#define __IO_PREFIX mpr2
+#include <asm/io_generic.h>
+
+
+#define SETBITS_OUTB(mask, reg)   ctrl_outb(ctrl_inb(reg) | mask, reg)
+#define SETBITS_OUTW(mask, reg)   ctrl_outw(ctrl_inw(reg) | mask, reg)
+#define SETBITS_OUTL(mask, reg)   ctrl_outl(ctrl_inl(reg) | mask, reg)
+#define CLRBITS_OUTB(mask, reg)   ctrl_outb(ctrl_inb(reg) & ~mask, reg)
+#define CLRBITS_OUTW(mask, reg)   ctrl_outw(ctrl_inw(reg) & ~mask, reg)
+#define CLRBITS_OUTL(mask, reg)   ctrl_outl(ctrl_inl(reg) & ~mask, reg)
+
+
+#define PA_LED          PORT_PADR      /* LED */
+
+
+/* BSC */
+#define CMNCR           0xA4FD0000UL
+#define CS0BCR          0xA4FD0004UL
+#define CS2BCR          0xA4FD0008UL
+#define CS3BCR          0xA4FD000CUL
+#define CS4BCR          0xA4FD0010UL
+#define CS5ABCR         0xA4FD0014UL
+#define CS5BBCR         0xA4FD0018UL
+#define CS6ABCR         0xA4FD001CUL
+#define CS6BBCR         0xA4FD0020UL
+#define CS0WCR          0xA4FD0024UL
+#define CS2WCR          0xA4FD0028UL
+#define CS3WCR          0xA4FD002CUL
+#define CS4WCR          0xA4FD0030UL
+#define CS5AWCR         0xA4FD0034UL
+#define CS5BWCR         0xA4FD0038UL
+#define CS6AWCR         0xA4FD003CUL
+#define CS6BWCR         0xA4FD0040UL
+
+
+/* usb */
+
+#define PORT_UTRCTL            0xA405012CUL
+#define PORT_UCLKCR_W          0xA40A0008UL
+
+#define INTC_ICR0              0xA414FEE0UL
+#define INTC_ICR1              0xA4140010UL
+#define INTC_ICR2              0xA4140012UL
+
+/* MTD */
+
+#define MPR2_MTD_BOOTLOADER_SIZE       0x00060000UL
+#define MPR2_MTD_KERNEL_SIZE           0x00200000UL
+
+#endif  /* __ASM_SH_MAGICPANELR2_H */
index 6bc9bba101059f2641d78ecbde2019f143581b98..cb3d46c59eabe28e627a41d19d00e471ba13454f 100644 (file)
@@ -70,14 +70,14 @@ extern void clear_page_nommu(void *to);
 extern void copy_page_nommu(void *to, void *from);
 #endif
 
-#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
-       defined(CONFIG_SH7705_CACHE_32KB))
+#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \
+       (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB))
 struct page;
 extern void clear_user_page(void *to, unsigned long address, struct page *pg);
 extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
 extern void __clear_user_page(void *to, void *orig_to);
 extern void __copy_user_page(void *to, void *from, void *orig_to);
-#elif defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH3) || !defined(CONFIG_MMU)
+#else
 #define clear_user_page(page, vaddr, pg)       clear_page(page)
 #define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
 #endif
@@ -88,6 +88,7 @@ extern void __copy_user_page(void *to, void *from, void *orig_to);
 #ifdef CONFIG_X2TLB
 typedef struct { unsigned long pte_low, pte_high; } pte_t;
 typedef struct { unsigned long long pgprot; } pgprot_t;
+typedef struct { unsigned long long pgd; } pgd_t;
 #define pte_val(x) \
        ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
 #define __pte(x) \
@@ -95,12 +96,11 @@ typedef struct { unsigned long long pgprot; } pgprot_t;
 #else
 typedef struct { unsigned long pte_low; } pte_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long pgd; } pgd_t;
 #define pte_val(x)     ((x).pte_low)
 #define __pte(x) ((pte_t) { (x) } )
 #endif
 
-typedef struct { unsigned long pgd; } pgd_t;
-
 #define pgd_val(x)     ((x).pgd)
 #define pgprot_val(x)  ((x).pgprot)
 
index e3fae12c0e499574f62e0300391ebd7a5328dbf0..cf0dd2b648c230c3d2a81e68ee2bdb2969d2d59e 100644 (file)
@@ -42,13 +42,12 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 
 /* PGD bits */
 #define PGDIR_SHIFT    (PTE_SHIFT + PTE_BITS)
-#define PGDIR_BITS     (32 - PGDIR_SHIFT)
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
 /* Entries per level */
 #define PTRS_PER_PTE   (PAGE_SIZE / (1 << PTE_MAGNITUDE))
-#define PTRS_PER_PGD   (PAGE_SIZE / 4)
+#define PTRS_PER_PGD   (PAGE_SIZE / sizeof(pgd_t))
 
 #define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
 #define FIRST_USER_ADDRESS     0
@@ -100,17 +99,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 #define _PAGE_HW_SHARED        0x002           /* SH-bit  : shared among processes */
 #define _PAGE_DIRTY    0x004           /* D-bit   : page changed */
 #define _PAGE_CACHABLE 0x008           /* C-bit   : cachable */
-#ifndef CONFIG_X2TLB
-# define _PAGE_SZ0     0x010           /* SZ0-bit : Size of page */
-# define _PAGE_RW      0x020           /* PR0-bit : write access allowed */
-# define _PAGE_USER    0x040           /* PR1-bit : user space access allowed*/
-# define _PAGE_SZ1     0x080           /* SZ1-bit : Size of page (on SH-4) */
-#endif
+#define _PAGE_SZ0      0x010           /* SZ0-bit : Size of page */
+#define _PAGE_RW       0x020           /* PR0-bit : write access allowed */
+#define _PAGE_USER     0x040           /* PR1-bit : user space access allowed*/
+#define _PAGE_SZ1      0x080           /* SZ1-bit : Size of page (on SH-4) */
 #define _PAGE_PRESENT  0x100           /* V-bit   : page is valid */
 #define _PAGE_PROTNONE 0x200           /* software: if not present  */
 #define _PAGE_ACCESSED 0x400           /* software: page referenced */
 #define _PAGE_FILE     _PAGE_WT        /* software: pagecache or swap? */
 
+#define _PAGE_SZ_MASK  (_PAGE_SZ0 | _PAGE_SZ1)
+#define _PAGE_PR_MASK  (_PAGE_RW | _PAGE_USER)
+
 /* Extended mode bits */
 #define _PAGE_EXT_ESZ0         0x0010  /* ESZ0-bit: Size of page */
 #define _PAGE_EXT_ESZ1         0x0020  /* ESZ1-bit: Size of page */
@@ -126,11 +126,7 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 #define _PAGE_EXT_KERN_READ    0x2000  /* EPR5-bit: Kernel space readable */
 
 /* Wrapper for extended mode pgprot twiddling */
-#ifdef CONFIG_X2TLB
-# define _PAGE_EXT(x)          ((unsigned long long)(x) << 32)
-#else
-# define _PAGE_EXT(x)          (0)
-#endif
+#define _PAGE_EXT(x)           ((unsigned long long)(x) << 32)
 
 /* software: moves to PTEA.TC (Timing Control) */
 #define _PAGE_PCC_AREA5        0x00000000      /* use BSC registers for area5 */
@@ -146,10 +142,14 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 #define _PAGE_PCC_ATR16        0x60000001      /* Attribute Memory space, 6 bit bus */
 
 /* Mask which drops unused bits from the PTEL value */
-#ifdef CONFIG_CPU_SH3
+#if defined(CONFIG_CPU_SH3)
 #define _PAGE_CLEAR_FLAGS      (_PAGE_PROTNONE | _PAGE_ACCESSED| \
                                 _PAGE_FILE     | _PAGE_SZ1     | \
                                 _PAGE_HW_SHARED)
+#elif defined(CONFIG_X2TLB)
+/* Get rid of the legacy PR/SZ bits when using extended mode */
+#define _PAGE_CLEAR_FLAGS      (_PAGE_PROTNONE | _PAGE_ACCESSED | \
+                                _PAGE_FILE | _PAGE_PR_MASK | _PAGE_SZ_MASK)
 #else
 #define _PAGE_CLEAR_FLAGS      (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
 #endif
@@ -212,27 +212,36 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 
 #define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
                                 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
-                                _PAGE_EXT(_PAGE_EXT_USER_READ | \
+                                _PAGE_EXT(_PAGE_EXT_KERN_READ  | \
+                                          _PAGE_EXT_KERN_WRITE | \
+                                          _PAGE_EXT_USER_READ  | \
                                           _PAGE_EXT_USER_WRITE))
 
 #define PAGE_EXECREAD  __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
                                 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
-                                _PAGE_EXT(_PAGE_EXT_USER_EXEC | \
+                                _PAGE_EXT(_PAGE_EXT_KERN_EXEC | \
+                                          _PAGE_EXT_KERN_READ | \
+                                          _PAGE_EXT_USER_EXEC | \
                                           _PAGE_EXT_USER_READ))
 
 #define PAGE_COPY      PAGE_EXECREAD
 
 #define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
                                 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
-                                _PAGE_EXT(_PAGE_EXT_USER_READ))
+                                _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+                                          _PAGE_EXT_USER_READ))
 
 #define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
                                 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
-                                _PAGE_EXT(_PAGE_EXT_USER_WRITE))
+                                _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
+                                          _PAGE_EXT_USER_WRITE))
 
 #define PAGE_RWX       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
                                 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
-                                _PAGE_EXT(_PAGE_EXT_USER_WRITE | \
+                                _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
+                                          _PAGE_EXT_KERN_READ  | \
+                                          _PAGE_EXT_KERN_EXEC  | \
+                                          _PAGE_EXT_USER_WRITE | \
                                           _PAGE_EXT_USER_READ  | \
                                           _PAGE_EXT_USER_EXEC))
 
@@ -373,11 +382,15 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
 
 #define pte_pfn(x)             ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
-#define pfn_pte(pfn, prot)     __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
-#define pfn_pmd(pfn, prot)     __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
-#define pte_none(x)    (!pte_val(x))
-#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+#define pfn_pte(pfn, prot) \
+       __pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot) \
+       __pmd(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
+#define pte_none(x)            (!pte_val(x))
+#define pte_present(x)         ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
+
 #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
 
 #define pmd_none(x)    (!pmd_val(x))
@@ -392,15 +405,15 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-#define pte_not_present(pte)   (!(pte_val(pte) & _PAGE_PRESENT))
-#define pte_dirty(pte)         (pte_val(pte) & _PAGE_DIRTY)
-#define pte_young(pte)         (pte_val(pte) & _PAGE_ACCESSED)
-#define pte_file(pte)          (pte_val(pte) & _PAGE_FILE)
+#define pte_not_present(pte)   (!((pte).pte_low & _PAGE_PRESENT))
+#define pte_dirty(pte)         ((pte).pte_low & _PAGE_DIRTY)
+#define pte_young(pte)         ((pte).pte_low & _PAGE_ACCESSED)
+#define pte_file(pte)          ((pte).pte_low & _PAGE_FILE)
 
 #ifdef CONFIG_X2TLB
 #define pte_write(pte)         ((pte).pte_high & _PAGE_EXT_USER_WRITE)
 #else
-#define pte_write(pte)         (pte_val(pte) & _PAGE_RW)
+#define pte_write(pte)         ((pte).pte_low & _PAGE_RW)
 #endif
 
 #define PTE_BIT_FUNC(h,fn,op) \
@@ -429,17 +442,10 @@ PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
 /*
  * Macro and implementation to make a page protection as uncachable.
  */
-#define pgprot_noncached pgprot_noncached
+#define pgprot_writecombine(prot) \
+       __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
 
-static inline pgprot_t pgprot_noncached(pgprot_t _prot)
-{
-       unsigned long prot = pgprot_val(_prot);
-
-       prot &= ~_PAGE_CACHABLE;
-       return __pgprot(prot);
-}
-
-#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
+#define pgprot_noncached        pgprot_writecombine
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -451,28 +457,33 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot)
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-       set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) |
-                           pgprot_val(newprot)));
+       pte.pte_low &= _PAGE_CHG_MASK;
+       pte.pte_low |= pgprot_val(newprot);
+
+#ifdef CONFIG_X2TLB
+       pte.pte_high |= pgprot_val(newprot) >> 32;
+#endif
+
        return pte;
 }
 
-#define pmd_page_vaddr(pmd)    pmd_val(pmd)
+#define pmd_page_vaddr(pmd)    ((unsigned long)pmd_val(pmd))
 #define pmd_page(pmd)          (virt_to_page(pmd_val(pmd)))
 
 /* to find an entry in a page-table-directory. */
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
+#define pgd_index(address)     (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pgd_offset(mm, address)        ((mm)->pgd+pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define pgd_offset_k(address)  pgd_offset(&init_mm, address)
 
 /* Find an entry in the third-level page table.. */
-#define pte_index(address) \
-               ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_index(address)     ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 #define pte_offset_kernel(dir, address) \
        ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
-#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
+#define pte_offset_map(dir, address)           pte_offset_kernel(dir, address)
+#define pte_offset_map_nested(dir, address)    pte_offset_kernel(dir, address)
+
 #define pte_unmap(pte)         do { } while (0)
 #define pte_unmap_nested(pte)  do { } while (0)
 
@@ -480,13 +491,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pte_ERROR(e) \
        printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, \
               &(e), (e).pte_high, (e).pte_low)
+#define pgd_ERROR(e) \
+       printk("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
 #else
 #define pte_ERROR(e) \
        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
-#endif
-
 #define pgd_ERROR(e) \
        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+#endif
 
 struct vm_area_struct;
 extern void update_mmu_cache(struct vm_area_struct * vma,
@@ -563,7 +575,8 @@ struct mm_struct;
 extern unsigned int kobjsize(const void *objp);
 #endif /* !CONFIG_MMU */
 
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
+       defined(CONFIG_SH7705_CACHE_32KB))
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
 #endif
index 26d52174f4b4bed687b67b9e27a96b4251c03730..4f2922a1979c5fef654b9444c818123773cd4eab 100644 (file)
@@ -45,7 +45,7 @@ enum cpu_type {
        CPU_SH7705, CPU_SH7706, CPU_SH7707,
        CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
        CPU_SH7709, CPU_SH7709A, CPU_SH7710, CPU_SH7712,
-       CPU_SH7729,
+       CPU_SH7720, CPU_SH7729,
 
        /* SH-4 types */
        CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R,
@@ -73,15 +73,10 @@ struct sh_cpuinfo {
        unsigned long flags;
 } __attribute__ ((aligned(SMP_CACHE_BYTES)));
 
-extern struct sh_cpuinfo boot_cpu_data;
-
-#ifdef CONFIG_SMP
 extern struct sh_cpuinfo cpu_data[];
+#define boot_cpu_data cpu_data[0]
 #define current_cpu_data cpu_data[smp_processor_id()]
-#else
-#define cpu_data (&boot_cpu_data)
-#define current_cpu_data boot_cpu_data
-#endif
+#define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
 
 /*
  * User space process size: 2GB.
index 4083b59499286f402046345eebb5d12037f796b5..de37f933aa42049505fe17a08f96516b6e33aee2 100644 (file)
 #define PA_PMR          (PA_BCR+0x0900) /*  */
 
 #define IRLCNTR1        (PA_BCR + 0)    /* Interrupt Control Register1 */
-
-#define IRQ_PCISLOT1    65              /* PCI Slot #1 IRQ */
-#define IRQ_PCISLOT2    66              /* PCI Slot #2 IRQ */
-#define IRQ_PCISLOT3    67              /* PCI Slot #3 IRQ */
-#define IRQ_PCISLOT4    68              /* PCI Slot #4 IRQ */
-#define IRQ_TP          2               /* Touch Panel IRQ */
-#define IRQ_SCI1        3               /* SCI1 IRQ */
-#define IRQ_SCI0        4               /* SCI0 IRQ */
-#define IRQ_2SERIAL     5               /* Serial IRQ */
-#define IRQ_RTC         6               /* RTC A / B IRQ */
-#define IRQ_EXTENTION6  7               /* EXT6n IRQ */
-#define IRQ_EXTENTION5  8               /* EXT5n IRQ */
-#define IRQ_EXTENTION4  9               /* EXT4n IRQ */
-#define IRQ_EXTENTION2  10              /* EXT2n IRQ */
-#define IRQ_EXTENTION1  11              /* EXT1n IRQ */
-#define IRQ_ONETH       13              /* On board Ethernet IRQ */
-#define IRQ_PSW         14              /* Push Switch IRQ */
-
 #define IVDR_CK_ON     8               /* iVDR Clock ON */
 
 #elif defined(CONFIG_SH_R7780RP)
 #define PA_MMSR                (PA_BCR+0x0400)
 
 #define IVDR_CK_ON     4               /* iVDR Clock ON */
+#endif
 
+#define HL_FPGA_IRQ_BASE       200
+#define HL_NR_IRL              15
+
+#define IRQ_AX88796            (HL_FPGA_IRQ_BASE + 0)
+#define IRQ_CF                 (HL_FPGA_IRQ_BASE + 1)
+#ifndef IRQ_PSW
+#define IRQ_PSW                        (HL_FPGA_IRQ_BASE + 2)
 #endif
+#define IRQ_EXT1               (HL_FPGA_IRQ_BASE + 3)
+#define IRQ_EXT4               (HL_FPGA_IRQ_BASE + 4)
 
 void make_r7780rp_irq(unsigned int irq);
-void highlander_init_irq(void);
+
+unsigned char *highlander_init_irq_r7780mp(void);
+unsigned char *highlander_init_irq_r7780rp(void);
+unsigned char *highlander_init_irq_r7785rp(void);
 
 #define __IO_PREFIX    r7780rp
 #include <asm/io_generic.h>
index 91aacc96151b2fab63a10aa1eb87f92bf0a80d66..858da99d37e0f7f07c1a4b79439aec70fad67cc6 100644 (file)
@@ -5,4 +5,10 @@ extern void (*board_time_init)(void);
 extern void (*rtc_sh_get_time)(struct timespec *);
 extern int (*rtc_sh_set_time)(const time_t);
 
+#define RTC_CAP_4_DIGIT_YEAR   (1 << 0)
+
+struct sh_rtc_platform_info {
+       unsigned long capabilities;
+};
+
 #endif /* _ASM_RTC_H */
index 5d7800aa31b514df1954f128481569549388c622..83b9c111f171d9682f3382b1fd4a6fb666174e12 100644 (file)
@@ -9,7 +9,7 @@
  * Renesas Technology Sales RTS7751R2D support
  */
 
-/* Box specific addresses.  */
+/* Board specific addresses.  */
 
 #define PA_BCR         0xa4000000      /* FPGA */
 #define PA_IRLMON      0xa4000002      /* Interrupt Status control */
 #define PA_RTCCE       0xa400000c      /* RTC(9701) Enable control */
 #define PA_PCICD       0xa400000e      /* PCI Extention detect control */
 #define PA_VOYAGERRTS  0xa4000020      /* VOYAGER Reset control */
-#if defined(CONFIG_RTS7751R2D_REV11)
-#define PA_AXRST       0xa4000022      /* AX_LAN Reset control */
-#define PA_CFRST       0xa4000024      /* CF Reset control */
-#define        PA_ADMRTS       0xa4000026      /* SD Reset control */
-#define PA_EXTRST      0xa4000028      /* Extention Reset control */
-#define PA_CFCDINTCLR  0xa400002a      /* CF Insert Interrupt clear */
-#else
-#define PA_CFRST       0xa4000022      /* CF Reset control */
-#define        PA_ADMRTS       0xa4000024      /* SD Reset control */
-#define PA_EXTRST      0xa4000026      /* Extention Reset control */
-#define PA_CFCDINTCLR  0xa4000028      /* CF Insert Interrupt clear */
-#define        PA_KEYCTLCLR    0xa400002a      /* Key Interrupt clear */
-#endif
+
+#define PA_R2D1_AXRST          0xa4000022      /* AX_LAN Reset control */
+#define PA_R2D1_CFRST          0xa4000024      /* CF Reset control */
+#define PA_R2D1_ADMRTS         0xa4000026      /* SD Reset control */
+#define PA_R2D1_EXTRST         0xa4000028      /* Extention Reset control */
+#define PA_R2D1_CFCDINTCLR     0xa400002a      /* CF Insert Interrupt clear */
+
+#define PA_R2DPLUS_CFRST       0xa4000022      /* CF Reset control */
+#define PA_R2DPLUS_ADMRTS      0xa4000024      /* SD Reset control */
+#define PA_R2DPLUS_EXTRST      0xa4000026      /* Extention Reset control */
+#define PA_R2DPLUS_CFCDINTCLR  0xa4000028      /* CF Insert Interrupt clear */
+#define PA_R2DPLUS_KEYCTLCLR   0xa400002a      /* Key Interrupt clear */
+
 #define PA_POWOFF      0xa4000030      /* Board Power OFF control */
 #define PA_VERREG      0xa4000032      /* FPGA Version Register */
 #define PA_INPORT      0xa4000034      /* KEY Input Port control */
 
 #define IRLCNTR1       (PA_BCR + 0)    /* Interrupt Control Register1 */
 
-#if defined(CONFIG_RTS7751R2D_REV11)
-#define IRQ_PCIETH     0               /* PCI Ethernet IRQ */
-#define IRQ_CFCARD     1               /* CF Card IRQ */
-#define IRQ_CFINST     2               /* CF Card Insert IRQ */
-#define IRQ_PCMCIA     3               /* PCMCIA IRQ */
-#define IRQ_VOYAGER    4               /* VOYAGER IRQ */
-#define IRQ_ONETH      5               /* On board Ethernet IRQ */
-#else
-#define IRQ_KEYIN      0               /* Key Input IRQ */
-#define IRQ_PCIETH     1               /* PCI Ethernet IRQ */
-#define IRQ_CFCARD     2               /* CF Card IRQ */
-#define IRQ_CFINST     3               /* CF Card Insert IRQ */
-#define IRQ_PCMCIA     4               /* PCMCIA IRQ */
-#define IRQ_VOYAGER    5               /* VOYAGER IRQ */
-#endif
-#define IRQ_RTCALM     6               /* RTC Alarm IRQ */
-#define IRQ_RTCTIME    7               /* RTC Timer IRQ */
-#define IRQ_SDCARD     8               /* SD Card IRQ */
-#define IRQ_PCISLOT1   9               /* PCI Slot #1 IRQ */
-#define IRQ_PCISLOT2   10              /* PCI Slot #2 IRQ */
-#define        IRQ_EXTENTION   11              /* EXTn IRQ */
+#define R2D_FPGA_IRQ_BASE      100
+
+#define IRQ_VOYAGER            (R2D_FPGA_IRQ_BASE + 0)
+#define IRQ_EXT                        (R2D_FPGA_IRQ_BASE + 1)
+#define IRQ_TP                 (R2D_FPGA_IRQ_BASE + 2)
+#define IRQ_RTC_T              (R2D_FPGA_IRQ_BASE + 3)
+#define IRQ_RTC_A              (R2D_FPGA_IRQ_BASE + 4)
+#define IRQ_SDCARD             (R2D_FPGA_IRQ_BASE + 5)
+#define IRQ_CF_CD              (R2D_FPGA_IRQ_BASE + 6)
+#define IRQ_CF_IDE             (R2D_FPGA_IRQ_BASE + 7)
+#define IRQ_AX88796            (R2D_FPGA_IRQ_BASE + 8)
+#define IRQ_KEY                        (R2D_FPGA_IRQ_BASE + 9)
+#define IRQ_PCI_INTA           (R2D_FPGA_IRQ_BASE + 10)
+#define IRQ_PCI_INTB           (R2D_FPGA_IRQ_BASE + 11)
+#define IRQ_PCI_INTC           (R2D_FPGA_IRQ_BASE + 12)
+#define IRQ_PCI_INTD           (R2D_FPGA_IRQ_BASE + 13)
 
 /* arch/sh/boards/renesas/rts7751r2d/irq.c */
 void init_rts7751r2d_IRQ(void);
index 2a696b8ee4f55d690d1370abd840d865a24d4c68..bd9cbc967c2ab0548b64d080825fd27d4708b3df 100644 (file)
@@ -4,6 +4,7 @@
 #include <asm-generic/sections.h>
 
 extern long __machvec_start, __machvec_end;
+extern char _ebss[];
 
 #endif /* __ASM_SH_SECTIONS_H */
 
index 4ff1eb9003013370b4ed062ec601d0bd1d7609cc..c39c785bba9491ce1cdfd97a406a4028b979f710 100644 (file)
 
 #include <linux/time.h>
 
-#define INTC_IPRD      0xffd00010UL
-
 #define IRL0_IRQ       2
-#define IRL0_IPR_POS   3
 #define IRL0_PRIORITY  13
-
 #define IRL1_IRQ       5
-#define IRL1_IPR_POS   2
 #define IRL1_PRIORITY  10
-
 #define IRL2_IRQ       8
-#define IRL2_IPR_POS   1
 #define IRL2_PRIORITY  7
-
 #define IRL3_IRQ       11
-#define IRL3_IPR_POS   0
 #define IRL3_PRIORITY  4
 
 void heartbeat_sh03(void);
index b99ca786c0c1986c028c7dc325e91ca97ae26e7b..9c8d34b07ebf19cac5a07ce711419410b6209320 100644 (file)
@@ -1,12 +1,3 @@
-/*
- * include/asm-sh/smp.h
- *
- * Copyright (C) 2002, 2003  Paul Mundt
- *
- * 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
- * more details.
- */
 #ifndef __ASM_SH_SMP_H
 #define __ASM_SH_SMP_H
 
 #include <asm/current.h>
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
+#define hard_smp_processor_id()        plat_smp_processor_id()
+
+/* Map from cpu id to sequential logical cpu number. */
+extern int __cpu_number_map[NR_CPUS];
+#define cpu_number_map(cpu)  __cpu_number_map[cpu]
+
+/* The reverse map from sequential logical cpu number to cpu id.  */
+extern int __cpu_logical_map[NR_CPUS];
+#define cpu_logical_map(cpu)  __cpu_logical_map[cpu]
 
 /* I've no idea what the real meaning of this is */
 #define PROC_CHANGE_PENALTY    20
@@ -35,10 +35,22 @@ struct smp_fn_call_struct {
 
 extern struct smp_fn_call_struct smp_fn_call;
 
-#define SMP_MSG_RESCHEDULE     0x0001
+#define SMP_MSG_FUNCTION       0
+#define SMP_MSG_RESCHEDULE     1
+#define SMP_MSG_NR             2
 
-#endif /* CONFIG_SMP */
+void plat_smp_setup(void);
+void plat_prepare_cpus(unsigned int max_cpus);
+int plat_smp_processor_id(void);
+void plat_start_cpu(unsigned int cpu, unsigned long entry_point);
+void plat_send_ipi(unsigned int cpu, unsigned int message);
+int plat_register_ipi_handler(unsigned int message,
+                             void (*handler)(void *), void *arg);
+
+#else
 
 #define hard_smp_processor_id()        (0)
 
+#endif /* CONFIG_SMP */
+
 #endif /* __ASM_SH_SMP_H */
index 3554e3a74e99703e06adb84c7b1b3ed618fac2f3..042d95f51c4dc35c3cc5ac9558feb1026f1c99b9 100644 (file)
  * is the interrupt :-)
  */
 
-#define IRL0_IRQ               2
-#define IRL0_IPR_POS   3
+#define IRL0_IRQ       2
 #define IRL0_PRIORITY  13
 
-#define IRL1_IRQ               5
-#define IRL1_IPR_POS   2
+#define IRL1_IRQ       5
 #define IRL1_PRIORITY  10
 
-#define IRL2_IRQ               8
-#define IRL2_IPR_POS   1
+#define IRL2_IRQ       8
 #define IRL2_PRIORITY  7
 
-#define IRL3_IRQ               11
-#define IRL3_IPR_POS   0
+#define IRL3_IRQ       11
 #define IRL3_PRIORITY  4
 #endif
 
index 92f6e2008b2e00963a4fc6a7da2bea95d7b82594..e793181d64da33395ee432189d112fd6b821c0cc 100644 (file)
@@ -2,6 +2,7 @@
  * include/asm-sh/spinlock.h
  *
  * Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2006, 2007 Akio Idehara
  *
  * 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
 #ifndef __ASM_SH_SPINLOCK_H
 #define __ASM_SH_SPINLOCK_H
 
-#include <asm/atomic.h>
-#include <asm/spinlock_types.h>
+/*
+ * The only locking implemented here uses SH-4A opcodes. For others,
+ * split this out as per atomic-*.h.
+ */
+#ifndef CONFIG_CPU_SH4A
+#error "Need movli.l/movco.l for spinlocks"
+#endif
 
 /*
  * Your basic SMP spinlocks, allowing only a single CPU anywhere
  */
 
-#define __raw_spin_is_locked(x)        ((x)->lock != 0)
+#define __raw_spin_is_locked(x)                ((x)->lock <= 0)
 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
 #define __raw_spin_unlock_wait(x) \
-       do { cpu_relax(); } while (__raw_spin_is_locked(x))
+       do { cpu_relax(); } while ((x)->lock)
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  */
 static inline void __raw_spin_lock(raw_spinlock_t *lock)
 {
+       unsigned long tmp;
+       unsigned long oldval;
+
        __asm__ __volatile__ (
-               "1:\n\t"
-               "tas.b @%0\n\t"
-               "bf/s 1b\n\t"
-               "nop\n\t"
-               : "=r" (lock->lock)
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! __raw_spin_lock       \n\t"
+               "mov            %0, %1                          \n\t"
+               "mov            #0, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "cmp/pl         %1                              \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
                : "r" (&lock->lock)
                : "t", "memory"
        );
@@ -43,12 +56,36 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
 
 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
 {
-       //assert_spin_locked(lock);
+       unsigned long tmp;
 
-       lock->lock = 0;
+       __asm__ __volatile__ (
+               "mov            #1, %0 ! __raw_spin_unlock      \n\t"
+               "mov.l          %0, @%1                         \n\t"
+               : "=&z" (tmp)
+               : "r" (&lock->lock)
+               : "t", "memory"
+       );
 }
 
-#define __raw_spin_trylock(x) (!test_and_set_bit(0, &(x)->lock))
+static inline int __raw_spin_trylock(raw_spinlock_t *lock)
+{
+       unsigned long tmp, oldval;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! __raw_spin_trylock    \n\t"
+               "mov            %0, %1                          \n\t"
+               "mov            #0, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "synco                                          \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
+               : "r" (&lock->lock)
+               : "t", "memory"
+       );
+
+       return oldval;
+}
 
 /*
  * Read-write spinlocks, allowing multiple readers but only one writer.
@@ -59,58 +96,124 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
  * read-locks.
  */
 
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_read_can_lock(x) ((x)->lock > 0)
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_write_can_lock(x)        ((x)->lock == RW_LOCK_BIAS)
+
 static inline void __raw_read_lock(raw_rwlock_t *rw)
 {
-       __raw_spin_lock(&rw->lock);
-
-       atomic_inc(&rw->counter);
+       unsigned long tmp;
 
-       __raw_spin_unlock(&rw->lock);
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%1, %0 ! __raw_read_lock       \n\t"
+               "cmp/pl         %0                              \n\t"
+               "bf             1b                              \n\t"
+               "add            #-1, %0                         \n\t"
+               "movco.l        %0, @%1                         \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp)
+               : "r" (&rw->lock)
+               : "t", "memory"
+       );
 }
 
 static inline void __raw_read_unlock(raw_rwlock_t *rw)
 {
-       __raw_spin_lock(&rw->lock);
-
-       atomic_dec(&rw->counter);
+       unsigned long tmp;
 
-       __raw_spin_unlock(&rw->lock);
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%1, %0 ! __raw_read_unlock     \n\t"
+               "add            #1, %0                          \n\t"
+               "movco.l        %0, @%1                         \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp)
+               : "r" (&rw->lock)
+               : "t", "memory"
+       );
 }
 
 static inline void __raw_write_lock(raw_rwlock_t *rw)
 {
-       __raw_spin_lock(&rw->lock);
-       atomic_set(&rw->counter, -1);
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%1, %0 ! __raw_write_lock      \n\t"
+               "cmp/hs         %2, %0                          \n\t"
+               "bf             1b                              \n\t"
+               "sub            %2, %0                          \n\t"
+               "movco.l        %0, @%1                         \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp)
+               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+               : "t", "memory"
+       );
 }
 
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
 {
-       atomic_set(&rw->counter, 0);
-       __raw_spin_unlock(&rw->lock);
+       __asm__ __volatile__ (
+               "mov.l          %1, @%0 ! __raw_write_unlock    \n\t"
+               :
+               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+               : "t", "memory"
+       );
 }
 
-static inline int __raw_write_can_lock(raw_rwlock_t *rw)
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
 {
-       return (atomic_read(&rw->counter) == RW_LOCK_BIAS);
-}
+       unsigned long tmp, oldval;
 
-static inline int __raw_read_trylock(raw_rwlock_t *lock)
-{
-       atomic_t *count = (atomic_t*)lock;
-       if (atomic_dec_return(count) >= 0)
-               return 1;
-       atomic_inc(count);
-       return 0;
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! __raw_read_trylock    \n\t"
+               "mov            %0, %1                          \n\t"
+               "cmp/pl         %0                              \n\t"
+               "bf             2f                              \n\t"
+               "add            #-1, %0                         \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "2:                                             \n\t"
+               "synco                                          \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
+               : "r" (&rw->lock)
+               : "t", "memory"
+       );
+
+       return (oldval > 0);
 }
 
 static inline int __raw_write_trylock(raw_rwlock_t *rw)
 {
-       if (atomic_sub_and_test(RW_LOCK_BIAS, &rw->counter))
-               return 1;
-       
-       atomic_add(RW_LOCK_BIAS, &rw->counter);
+       unsigned long tmp, oldval;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! __raw_write_trylock   \n\t"
+               "mov            %0, %1                          \n\t"
+               "cmp/hs         %3, %0                          \n\t"
+               "bf             2f                              \n\t"
+               "sub            %3, %0                          \n\t"
+               "2:                                             \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "synco                                          \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
+               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+               : "t", "memory"
+       );
 
-       return 0;
+       return (oldval > (RW_LOCK_BIAS - 1));
 }
 
 #define _raw_spin_relax(lock)  cpu_relax()
index 5c58134f2c4e35a31a402f69c3368e2a9033c326..b4d244e7b60ca7532f7193e7365a9a67a293482f 100644 (file)
@@ -6,19 +6,16 @@
 #endif
 
 typedef struct {
-       volatile unsigned long lock;
+       volatile unsigned int lock;
 } raw_spinlock_t;
 
-#define __RAW_SPIN_LOCK_UNLOCKED       { 1 }
-
-#include <asm/atomic.h>
+#define __RAW_SPIN_LOCK_UNLOCKED               { 1 }
 
 typedef struct {
-       raw_spinlock_t lock;
-       atomic_t counter;
+       volatile unsigned int lock;
 } raw_rwlock_t;
 
 #define RW_LOCK_BIAS                   0x01000000
-#define __RAW_RW_LOCK_UNLOCKED         { { 0 }, { RW_LOCK_BIAS } }
+#define __RAW_RW_LOCK_UNLOCKED         { RW_LOCK_BIAS }
 
 #endif
index 24504253720529433225b41abe9fe9647f449492..9d849e6df268b8138252e29f11126f31c21ee2b7 100644 (file)
@@ -266,6 +266,7 @@ void disable_hlt(void);
 void enable_hlt(void);
 
 void default_idle(void);
+void per_cpu_trap_init(void);
 
 asmlinkage void break_point_trap(void);
 asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
index 64c936b22715e89283213cf6b9058117b3fdc3a2..d825596562dfa92017469e4da171e530bac7cdd1 100644 (file)
 #define VOYAGER_UART_BASE              (0x30000 + VOYAGER_BASE)
 #define        VOYAGER_AC97_BASE               (0xa0000 + VOYAGER_BASE)
 
-#define VOYAGER_IRQ_NUM                        32
-#define VOYAGER_IRQ_BASE               50
-#define VOYAGER_USBH_IRQ               VOYAGER_IRQ_BASE + 6
-#define VOYAGER_8051_IRQ               VOYAGER_IRQ_BASE + 10
-#define VOYAGER_UART0_IRQ              VOYAGER_IRQ_BASE + 12
-#define VOYAGER_UART1_IRQ              VOYAGER_IRQ_BASE + 13
-#define        VOYAGER_AC97_IRQ                VOYAGER_IRQ_BASE + 17
+#define VOYAGER_IRQ_NUM                        26
+#define VOYAGER_IRQ_BASE               200
+
+#define IRQ_SM501_UP                   (VOYAGER_IRQ_BASE + 0)
+#define IRQ_SM501_G54                  (VOYAGER_IRQ_BASE + 1)
+#define IRQ_SM501_G53                  (VOYAGER_IRQ_BASE + 2)
+#define IRQ_SM501_G52                  (VOYAGER_IRQ_BASE + 3)
+#define IRQ_SM501_G51                  (VOYAGER_IRQ_BASE + 4)
+#define IRQ_SM501_G50                  (VOYAGER_IRQ_BASE + 5)
+#define IRQ_SM501_G49                  (VOYAGER_IRQ_BASE + 6)
+#define IRQ_SM501_G48                  (VOYAGER_IRQ_BASE + 7)
+#define IRQ_SM501_I2C                  (VOYAGER_IRQ_BASE + 8)
+#define IRQ_SM501_PW                   (VOYAGER_IRQ_BASE + 9)
+#define IRQ_SM501_DMA                  (VOYAGER_IRQ_BASE + 10)
+#define IRQ_SM501_PCI                  (VOYAGER_IRQ_BASE + 11)
+#define IRQ_SM501_I2S                  (VOYAGER_IRQ_BASE + 12)
+#define IRQ_SM501_AC                   (VOYAGER_IRQ_BASE + 13)
+#define IRQ_SM501_US                   (VOYAGER_IRQ_BASE + 14)
+#define IRQ_SM501_U1                   (VOYAGER_IRQ_BASE + 15)
+#define IRQ_SM501_U0                   (VOYAGER_IRQ_BASE + 16)
+#define IRQ_SM501_CV                   (VOYAGER_IRQ_BASE + 17)
+#define IRQ_SM501_MC                   (VOYAGER_IRQ_BASE + 18)
+#define IRQ_SM501_S1                   (VOYAGER_IRQ_BASE + 19)
+#define IRQ_SM501_S0                   (VOYAGER_IRQ_BASE + 20)
+#define IRQ_SM501_UH                   (VOYAGER_IRQ_BASE + 21)
+#define IRQ_SM501_2D                   (VOYAGER_IRQ_BASE + 22)
+#define IRQ_SM501_ZD                   (VOYAGER_IRQ_BASE + 23)
+#define IRQ_SM501_PV                   (VOYAGER_IRQ_BASE + 24)
+#define IRQ_SM501_CI                   (VOYAGER_IRQ_BASE + 25)
 
 /* ----- MISC controle  register ------------------------------ */
 #define MISC_CTRL                      (0x000004 + VOYAGER_BASE)
 void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
 int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
 
+/* arch/sh/cchips/voyagergx/irq.c */
+void setup_voyagergx_irq(void);
+
 #endif /* _VOYAGER_GX_REG_H */
diff --git a/include/asm-sh64/gpio.h b/include/asm-sh64/gpio.h
new file mode 100644 (file)
index 0000000..6bc5a13
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_SH64_GPIO_H
+#define __ASM_SH64_GPIO_H
+
+/*
+ * This is just a stub, so that every arch using sh-sci has a gpio.h
+ */
+
+#endif /* __ASM_SH64_GPIO_H */
index 1f37b6931922fe3dc73a0ace95558e447e86cbec..3de3ad99f45789d29f5b5c0eb496fed3bf9c762c 100644 (file)
@@ -119,6 +119,13 @@ void insw(unsigned long port, void *addr, unsigned long count);
 void outsl(unsigned long port, const void *addr, unsigned long count);
 void insl(unsigned long port, void *addr, unsigned long count);
 
+#define inb_p(addr)    inb(addr)
+#define inw_p(addr)    inw(addr)
+#define inl_p(addr)    inl(addr)
+#define outb_p(x,addr) outb(x,addr)
+#define outw_p(x,addr) outw(x,addr)
+#define outl_p(x,addr) outl(x,addr)
+
 #define __raw_readb            readb
 #define __raw_readw            readw
 #define __raw_readl            readl
diff --git a/include/asm-sparc/irqflags.h b/include/asm-sparc/irqflags.h
new file mode 100644 (file)
index 0000000..db398fb
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * include/asm-sparc/irqflags.h
+ *
+ * IRQ flags handling
+ *
+ * This file gets included from lowlevel asm headers too, to provide
+ * wrapped versions of the local_irq_*() APIs, based on the
+ * raw_local_irq_*() functions from the lowlevel headers.
+ */
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#ifndef __ASSEMBLY__
+
+extern void raw_local_irq_restore(unsigned long);
+extern unsigned long __raw_local_irq_save(void);
+extern void raw_local_irq_enable(void);
+
+static inline unsigned long getipl(void)
+{
+        unsigned long retval;
+
+        __asm__ __volatile__("rd        %%psr, %0" : "=r" (retval));
+        return retval;
+}
+
+#define raw_local_save_flags(flags) ((flags) = getipl())
+#define raw_local_irq_save(flags)   ((flags) = __raw_local_irq_save())
+#define raw_local_irq_disable()     ((void) __raw_local_irq_save())
+#define raw_irqs_disabled()         ((getipl() & PSR_PIL) != 0)
+
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+        return ((flags & PSR_PIL) != 0);
+}
+
+#endif /* (__ASSEMBLY__) */
+
+#endif /* !(_ASM_IRQFLAGS_H) */
index d1a2572e3f553d8a58da30e10b0f0ac84da477af..8c259de02614be6ab1e8053f124b332a613a6456 100644 (file)
@@ -15,6 +15,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/irqflags.h>
+
 /*
  * Sparc (general) CPU types
  */
@@ -164,26 +166,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
          "o0", "o1", "o2", "o3",                   "o7");      \
        } while(0)
 
-/*
- * Changing the IRQ level on the Sparc.
- */
-extern void local_irq_restore(unsigned long);
-extern unsigned long __local_irq_save(void);
-extern void local_irq_enable(void);
-
-static inline unsigned long getipl(void)
-{
-       unsigned long retval;
-
-       __asm__ __volatile__("rd        %%psr, %0" : "=r" (retval));
-       return retval;
-}
-
-#define local_save_flags(flags)        ((flags) = getipl())
-#define local_irq_save(flags)  ((flags) = __local_irq_save())
-#define local_irq_disable()    ((void) __local_irq_save())
-#define irqs_disabled()                ((getipl() & PSR_PIL) != 0)
-
 /* XXX Change this if we ever use a PSO mode kernel. */
 #define mb()   __asm__ __volatile__ ("" : : : "memory")
 #define rmb()  mb()
index 98a6e609163e7cb149324682fb82df0c735a71ce..542421460a125f1edb80b5c136638be721aa1ff6 100644 (file)
@@ -75,12 +75,11 @@ struct trap_per_cpu {
        unsigned long           tsb_huge_temp;
 
 /* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size.  */
-       unsigned int            irq_worklist;
+       unsigned long           irq_worklist_pa;
        unsigned int            cpu_mondo_qmask;
        unsigned int            dev_mondo_qmask;
        unsigned int            resum_qmask;
        unsigned int            nonresum_qmask;
-       unsigned int            __pad2[1];
        void                    *hdesc;
 } __attribute__((aligned(64)));
 extern struct trap_per_cpu trap_block[NR_CPUS];
@@ -128,11 +127,11 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
 #define TRAP_PER_CPU_CPU_LIST_PA       0xc8
 #define TRAP_PER_CPU_TSB_HUGE          0xd0
 #define TRAP_PER_CPU_TSB_HUGE_TEMP     0xd8
-#define TRAP_PER_CPU_IRQ_WORKLIST      0xe0
-#define TRAP_PER_CPU_CPU_MONDO_QMASK   0xe4
-#define TRAP_PER_CPU_DEV_MONDO_QMASK   0xe8
-#define TRAP_PER_CPU_RESUM_QMASK       0xec
-#define TRAP_PER_CPU_NONRESUM_QMASK    0xf0
+#define TRAP_PER_CPU_IRQ_WORKLIST_PA   0xe0
+#define TRAP_PER_CPU_CPU_MONDO_QMASK   0xe8
+#define TRAP_PER_CPU_DEV_MONDO_QMASK   0xec
+#define TRAP_PER_CPU_RESUM_QMASK       0xf0
+#define TRAP_PER_CPU_NONRESUM_QMASK    0xf4
 
 #define TRAP_BLOCK_SZ_SHIFT            8
 
@@ -184,9 +183,9 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
        ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
 
 /* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
-#define TRAP_LOAD_IRQ_WORK(DEST, TMP)          \
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
        TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST;
+       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
 
 /* Clobbers TMP, loads DEST with current thread info pointer.  */
 #define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
@@ -223,9 +222,9 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
        ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
 
 /* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
-#define TRAP_LOAD_IRQ_WORK(DEST, TMP)          \
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
        TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST;
+       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
 
 #define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
        TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
index c00ad152771b04f7787310d4b7300c2ce7da8032..182dba05c702634ec8758a070380d9f668257882 100644 (file)
@@ -51,10 +51,19 @@ extern unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
                                    unsigned int msi_devino_start,
                                    unsigned int msi_devino_end);
 extern void sun4v_destroy_msi(unsigned int virt_irq);
+extern unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
+                                   unsigned int msi_devino_start,
+                                   unsigned int msi_devino_end,
+                                   unsigned long imap_base,
+                                   unsigned long iclr_base);
+extern void sun4u_destroy_msi(unsigned int virt_irq);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 
-extern void sparc64_set_msi(unsigned int virt_irq, u32 msi);
-extern u32 sparc64_get_msi(unsigned int virt_irq);
+extern unsigned char virt_irq_alloc(unsigned int dev_handle,
+                                   unsigned int dev_ino);
+#ifdef CONFIG_PCI_MSI
+extern void virt_irq_free(unsigned int virt_irq);
+#endif
 
 extern void fixup_irqs(void);
 
index 2983501e8b3e4dc88f05bbf0f3b3dc0de83449d7..e18496b7b85079cf9023680688c1866079cef6f1 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef __ASM_X8664_CPUFEATURE_H
 #define __ASM_X8664_CPUFEATURE_H
 
-#include <asm/cpufeature_32.h>
+#include "cpufeature_32.h"
 
 #undef  cpu_has_vme
 #define cpu_has_vme            0
index dbe734ddf2aff833f69cb3081d2ce2b2ee14bdc1..3f087883ea4886fd8a2e2abee9fbd205d5ccdff9 100644 (file)
@@ -11,8 +11,6 @@
  * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
  */
 
-#ifdef CONFIG_X86_IO_APIC
-
 /*
  * The structure of the IO-APIC:
  */
@@ -55,12 +53,6 @@ union IO_APIC_reg_03 {
        } __attribute__ ((packed)) bits;
 };
 
-/*
- * # of IO-APICs and # of IRQ routing registers
- */
-extern int nr_ioapics;
-extern int nr_ioapic_registers[MAX_IO_APICS];
-
 enum ioapic_irq_destination_types {
        dest_Fixed = 0,
        dest_LowestPrio = 1,
@@ -100,6 +92,14 @@ struct IO_APIC_route_entry {
 
 } __attribute__ ((packed));
 
+#ifdef CONFIG_X86_IO_APIC
+
+/*
+ * # of IO-APICs and # of IRQ routing registers
+ */
+extern int nr_ioapics;
+extern int nr_ioapic_registers[MAX_IO_APICS];
+
 /*
  * MP-BIOS irq configuration table structures:
  */
index eff8585cb741f777b91c518c63666d59d3a6d4a2..d058b04e0083a2e1aa02f59b6ea6c42987188f8a 100644 (file)
@@ -160,4 +160,17 @@ static inline int raw_irqs_disabled(void)
 # define TRACE_IRQS_OFF
 #endif
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define LOCKDEP_SYS_EXIT                      \
+       pushl %eax;                             \
+       pushl %ecx;                             \
+       pushl %edx;                             \
+       call lockdep_sys_exit;                  \
+       popl %edx;                              \
+       popl %ecx;                              \
+       popl %eax;
+#else
+# define LOCKDEP_SYS_EXIT
+#endif
+
 #endif
index 86e70fe23659bded0499fc85b0bb359aa7e3387c..5341ea1f815ac1728dd9dab6e06f068ebfa5bdea 100644 (file)
@@ -137,6 +137,20 @@ static inline void halt(void)
 #  define TRACE_IRQS_ON
 #  define TRACE_IRQS_OFF
 # endif
+# ifdef CONFIG_DEBUG_LOCK_ALLOC
+#  define LOCKDEP_SYS_EXIT     call lockdep_sys_exit_thunk
+#  define LOCKDEP_SYS_EXIT_IRQ \
+       TRACE_IRQS_ON; \
+       sti; \
+       SAVE_REST; \
+       LOCKDEP_SYS_EXIT; \
+       RESTORE_REST; \
+       cli; \
+       TRACE_IRQS_OFF;
+# else
+#  define LOCKDEP_SYS_EXIT
+#  define LOCKDEP_SYS_EXIT_IRQ
+# endif
 #endif
 
 #endif
index 5404e90edd57907e776e13b80e460863ac07bf7e..199cab107d85d134d697dcc3b6ab4227513a2bb9 100644 (file)
@@ -63,7 +63,7 @@
 /*
  * x86-64 Task Priority Register, CR8
  */
-#define X86_CR8_TPR    0x00000007 /* task priority register */
+#define X86_CR8_TPR    0x0000000F /* task priority register */
 
 /*
  * AMD and Transmeta use MSRs for configuration; see <asm/msr-index.h>
index d69ba937e09251769e2f00d54c0c91562a4127e8..e7e5d426fef58c2b6892fea59c341528d827afaf 100644 (file)
@@ -216,6 +216,7 @@ static inline unsigned long get_limit(unsigned long segment)
 
 #define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
 #define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
+#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
 
 /**
  * read_barrier_depends - Flush all pending reads that subsequents reads
@@ -271,18 +272,18 @@ static inline unsigned long get_limit(unsigned long segment)
 
 #define read_barrier_depends() do { } while(0)
 
+#ifdef CONFIG_SMP
+#define smp_mb()       mb()
+#ifdef CONFIG_X86_PPRO_FENCE
+# define smp_rmb()     rmb()
+#else
+# define smp_rmb()     barrier()
+#endif
 #ifdef CONFIG_X86_OOSTORE
-/* Actually there are no OOO store capable CPUs for now that do SSE, 
-   but make it already an possibility. */
-#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
+# define smp_wmb()     wmb()
 #else
-#define wmb()  __asm__ __volatile__ ("": : :"memory")
+# define smp_wmb()     barrier()
 #endif
-
-#ifdef CONFIG_SMP
-#define smp_mb()       mb()
-#define smp_rmb()      rmb()
-#define smp_wmb()      wmb()
 #define smp_read_barrier_depends()     read_barrier_depends()
 #define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
 #else
index 02175aa1d16a8aea903a51e6b5e1c71fda57d075..5022aecc333d7bfe6b24037b3927f15e745e4d7a 100644 (file)
@@ -141,8 +141,8 @@ static inline void write_cr8(unsigned long val)
 
 #ifdef CONFIG_SMP
 #define smp_mb()       mb()
-#define smp_rmb()      rmb()
-#define smp_wmb()      wmb()
+#define smp_rmb()      barrier()
+#define smp_wmb()      barrier()
 #define smp_read_barrier_depends()     do {} while(0)
 #else
 #define smp_mb()       barrier()
@@ -159,12 +159,8 @@ static inline void write_cr8(unsigned long val)
  */
 #define mb()   asm volatile("mfence":::"memory")
 #define rmb()  asm volatile("lfence":::"memory")
-
-#ifdef CONFIG_UNORDERED_IO
 #define wmb()  asm volatile("sfence" ::: "memory")
-#else
-#define wmb()  asm volatile("" ::: "memory")
-#endif
+
 #define read_barrier_depends() do {} while(0)
 #define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
 
index bfb8ec791b7b6ef3596d1306f4b5ee6de36de898..09fbf7e5a6cbbbba0b3fe6991f4aefa494e937a4 100644 (file)
@@ -197,7 +197,7 @@ struct agp_file_private {
        struct agp_file_private *next;
        struct agp_file_private *prev;
        pid_t my_pid;
-       long access_flags;      /* long req'd for set_bit --RR */
+       unsigned long access_flags;     /* long req'd for set_bit --RR */
 };
 
 struct agp_front_data {
index d2ddea926895378effcf67862b5a875910018c52..c33b0dc28e4db5de75df8a2419c128d22c8e29d9 100644 (file)
@@ -31,6 +31,7 @@ enum clock_event_nofitiers {
        CLOCK_EVT_NOTIFY_ADD,
        CLOCK_EVT_NOTIFY_BROADCAST_ON,
        CLOCK_EVT_NOTIFY_BROADCAST_OFF,
+       CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
        CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
        CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
        CLOCK_EVT_NOTIFY_SUSPEND,
index 16421f662a7ad6074e107a47f8d9be92ad185064..6d760f1ad87521c932d12d649cc0171d8e14f696 100644 (file)
@@ -1302,8 +1302,14 @@ struct file_system_type {
        struct module *owner;
        struct file_system_type * next;
        struct list_head fs_supers;
+
        struct lock_class_key s_lock_key;
        struct lock_class_key s_umount_key;
+
+       struct lock_class_key i_lock_key;
+       struct lock_class_key i_mutex_key;
+       struct lock_class_key i_mutex_dir_key;
+       struct lock_class_key i_alloc_sem_key;
 };
 
 extern int get_sb_bdev(struct file_system_type *fs_type,
index 4f6ee3b267fa222ee03567b8452d16f1d0e0ef10..bf6302f6b5f88d44c2acdafa7f17022630d84cba 100644 (file)
@@ -200,7 +200,7 @@ struct hdlcdrv_state {
 
        struct hdlcdrv_hdlcrx {
                struct hdlcdrv_hdlcbuffer hbuf;
-               long in_hdlc_rx;
+               unsigned long in_hdlc_rx;
                /* 0 = sync hunt, != 0 receiving */
                int rx_state;   
                unsigned int bitstream;
index 898103b401f1309d68ee5f91b80b3627d8aaa98b..edb8024d744bff94c1fa4c3d3abc4adaaf863802 100644 (file)
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/input.h>
-
 /*
  * USB HID (Human Interface Device) interface class code
  */
 #define HID_DT_REPORT                  (USB_TYPE_CLASS | 0x02)
 #define HID_DT_PHYSICAL                        (USB_TYPE_CLASS | 0x03)
 
+#define HID_MAX_DESCRIPTOR_SIZE                4096
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+
 /*
  * We parse each description item into this structure. Short items data
  * values are expanded to 32-bit signed int, long items contain a pointer
@@ -276,6 +280,7 @@ struct hid_item {
 #define HID_QUIRK_HIDINPUT                     0x00200000
 #define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL        0x00400000
 #define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP     0x00800000
+#define HID_QUIRK_IGNORE_HIDINPUT              0x01000000
 
 /*
  * Separate quirks for runtime report descriptor fixup
@@ -285,6 +290,7 @@ struct hid_item {
 #define HID_QUIRK_RDESC_LOGITECH               0x00000002
 #define HID_QUIRK_RDESC_SWAPPED_MIN_MAX                0x00000004
 #define HID_QUIRK_RDESC_PETALYNX               0x00000008
+#define HID_QUIRK_RDESC_MACBOOK_JIS            0x00000010
 
 /*
  * This is the global environment of the parser. This information is
@@ -309,7 +315,6 @@ struct hid_global {
  * This is the local environment. It is persistent up the next main-item.
  */
 
-#define HID_MAX_DESCRIPTOR_SIZE                4096
 #define HID_MAX_USAGES                 8192
 #define HID_DEFAULT_NUM_COLLECTIONS    16
 
@@ -403,6 +408,7 @@ struct hid_control_fifo {
 
 #define HID_CLAIMED_INPUT      1
 #define HID_CLAIMED_HIDDEV     2
+#define HID_CLAIMED_HIDRAW     4
 
 #define HID_CTRL_RUNNING       1
 #define HID_OUT_RUNNING                2
@@ -438,6 +444,7 @@ struct hid_device {                                                 /* device report descriptor */
 
        struct list_head inputs;                                        /* The list of inputs */
        void *hiddev;                                                   /* The hiddev structure */
+       void *hidraw;
        int minor;                                                      /* Hiddev minor number */
 
        wait_queue_head_t wait;                                         /* For sleeping */
@@ -458,6 +465,9 @@ struct hid_device {                                                 /* device report descriptor */
        void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
                                  struct hid_usage *, __s32);
        void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
+
+       /* handler for raw output data, used by hidraw */
+       int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
 #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
        unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
        unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
@@ -553,4 +563,5 @@ static inline int hid_ff_init(struct hid_device *hid) { return -1; }
 #define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
                __FILE__ , ## arg)
 #endif
+#endif
 
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h
new file mode 100644 (file)
index 0000000..0536f29
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef _HIDRAW_H
+#define _HIDRAW_H
+
+/*
+ *  Copyright (c) 2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/hid.h>
+
+struct hidraw_report_descriptor {
+       __u32 size;
+       __u8 value[HID_MAX_DESCRIPTOR_SIZE];
+};
+
+struct hidraw_devinfo {
+       __u32 bustype;
+       __s16 vendor;
+       __s16 product;
+};
+
+/* ioctl interface */
+#define HIDIOCGRDESCSIZE       _IOR('H', 0x01, int)
+#define HIDIOCGRDESC           _IOR('H', 0x02, struct hidraw_report_descriptor)
+#define HIDIOCGRAWINFO         _IOR('H', 0x03, struct hidraw_devinfo)
+
+#define HIDRAW_FIRST_MINOR 0
+#define HIDRAW_MAX_DEVICES 64
+/* number of reports to buffer */
+#define HIDRAW_BUFFER_SIZE 64
+
+
+/* kernel-only API declarations */
+#ifdef __KERNEL__
+
+struct hidraw {
+       unsigned int minor;
+       int exist;
+       int open;
+       wait_queue_head_t wait;
+       struct hid_device *hid;
+       struct device *dev;
+       struct list_head list;
+};
+
+struct hidraw_report {
+       __u8 *value;
+       int len;
+};
+
+struct hidraw_list {
+       struct hidraw_report buffer[HIDRAW_BUFFER_SIZE];
+       int head;
+       int tail;
+       struct fasync_struct *fasync;
+       struct hidraw *hidraw;
+       struct list_head node;
+       struct mutex read_mutex;
+};
+
+#ifdef CONFIG_HIDRAW
+int hidraw_init(void);
+void hidraw_exit(void);
+void hidraw_report_event(struct hid_device *, u8 *, int);
+int hidraw_connect(struct hid_device *);
+void hidraw_disconnect(struct hid_device *);
+#else
+static inline int hidraw_init(void) { return 0; }
+static inline void hidraw_exit(void) { }
+static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
+static inline int hidraw_connect(struct hid_device *hid) { return -1; }
+static inline void hidraw_disconnect(struct hid_device *hid) { }
+#endif
+
+#endif
+
+#endif
index 0efd994c37f17112337a9b58eaf15cee389d6f93..6b6ee702b007406d44352f1104a43f4fb4d91cd7 100644 (file)
@@ -16,9 +16,9 @@
 
 #include <linux/device.h>
 
-struct class_device *hwmon_device_register(struct device *dev);
+struct device *hwmon_device_register(struct device *dev);
 
-void hwmon_device_unregister(struct class_device *cdev);
+void hwmon_device_unregister(struct device *dev);
 
 /* Scale user input to sensible values */
 static inline int SENSORS_LIMIT(long value, long low, long high)
index 81c229a0fbca220a275407894b751c8c6dc9ecbf..311315b56b611a7b2b9d44a2b930eb8c3b9b8def 100644 (file)
 #include <linux/types.h>
 #include <linux/compiler.h>
 
-/* Some IOCTL commands are defined in <linux/i2c.h> */
-/* Note: 10-bit addresses are NOT supported! */
+/* /dev/i2c-X ioctl commands.  The ioctl's parameter is always an
+ * unsigned long, except for:
+ *     - I2C_FUNCS, takes pointer to an unsigned long
+ *     - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data
+ *     - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data
+ */
+#define I2C_RETRIES    0x0701  /* number of times a device address should
+                                  be polled when not acknowledging */
+#define I2C_TIMEOUT    0x0702  /* set timeout in jiffies - call with int */
+
+/* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses
+ * are NOT supported! (due to code brokenness)
+ */
+#define I2C_SLAVE      0x0703  /* Use this slave address */
+#define I2C_SLAVE_FORCE        0x0706  /* Use this slave address, even if it
+                                  is already in use by a driver! */
+#define I2C_TENBIT     0x0704  /* 0 for 7 bit addrs, != 0 for 10 bit */
+
+#define I2C_FUNCS      0x0705  /* Get the adapter functionality mask */
+
+#define I2C_RDWR       0x0707  /* Combined R/W transfer (one STOP only) */
+
+#define I2C_PEC                0x0708  /* != 0 to use PEC with SMBus */
+#define I2C_SMBUS      0x0720  /* SMBus transfer */
+
 
 /* This is the structure as used in the I2C_SMBUS ioctl call */
 struct i2c_smbus_ioctl_data {
@@ -44,4 +67,8 @@ struct i2c_rdwr_ioctl_data {
 
 #define  I2C_RDRW_IOCTL_MAX_MSGS       42
 
+#ifdef __KERNEL__
+#define I2C_MAJOR      89              /* Device major number          */
+#endif
+
 #endif /* _LINUX_I2C_DEV_H */
index 2a32f2fd940d56fc6bf4d63ced9f9f75aa13995d..8033e6b33271d0fdc07088d1c10d3bf27df1d4ae 100644 (file)
@@ -35,8 +35,6 @@
 #include <linux/sched.h>       /* for completion */
 #include <linux/mutex.h>
 
-extern struct bus_type i2c_bus_type;
-
 /* --- General options ------------------------------------------------        */
 
 struct i2c_msg;
@@ -292,9 +290,6 @@ struct i2c_algorithm {
                           unsigned short flags, char read_write,
                           u8 command, int size, union i2c_smbus_data * data);
 
-       /* --- ioctl like call to set div. parameters. */
-       int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
-
        /* To determine what the adapter supports */
        u32 (*functionality) (struct i2c_adapter *);
 };
@@ -342,9 +337,10 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data)
 }
 
 /*flags for the client struct: */
-#define I2C_CLIENT_PEC  0x04                   /* Use Packet Error Checking */
-#define I2C_CLIENT_TEN 0x10                    /* we have a ten bit chip address       */
-                                               /* Must equal I2C_M_TEN below */
+#define I2C_CLIENT_PEC 0x04            /* Use Packet Error Checking */
+#define I2C_CLIENT_TEN 0x10            /* we have a ten bit chip address */
+                                       /* Must equal I2C_M_TEN below */
+#define I2C_CLIENT_WAKE        0x80            /* for board_info; true iff can wake */
 
 /* i2c adapter classes (bitmask) */
 #define I2C_CLASS_HWMON                (1<<0)  /* lm_sensors, ... */
@@ -417,10 +413,6 @@ extern int i2c_probe(struct i2c_adapter *adapter,
                struct i2c_client_address_data *address_data,
                int (*found_proc) (struct i2c_adapter *, int, int));
 
-/* An ioctl like call to set div. parameters of the adapter.
- */
-extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
-
 extern struct i2c_adapter* i2c_get_adapter(int id);
 extern void i2c_put_adapter(struct i2c_adapter *adap);
 
@@ -444,19 +436,52 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
 }
 #endif /* __KERNEL__ */
 
-/*
- * I2C Message - used for pure i2c transaction, also from /dev interface
+/**
+ * struct i2c_msg - an I2C transaction segment beginning with START
+ * @addr: Slave address, either seven or ten bits.  When this is a ten
+ *     bit address, I2C_M_TEN must be set in @flags and the adapter
+ *     must support I2C_FUNC_10BIT_ADDR.
+ * @flags: I2C_M_RD is handled by all adapters.  No other flags may be
+ *     provided unless the adapter exported the relevant I2C_FUNC_*
+ *     flags through i2c_check_functionality().
+ * @len: Number of data bytes in @buf being read from or written to the
+ *     I2C slave address.  For read transactions where I2C_M_RECV_LEN
+ *     is set, the caller guarantees that this buffer can hold up to
+ *     32 bytes in addition to the initial length byte sent by the
+ *     slave (plus, if used, the SMBus PEC); and this value will be
+ *     incremented by the number of block data bytes received.
+ * @buf: The buffer into which data is read, or from which it's written.
+ *
+ * An i2c_msg is the low level representation of one segment of an I2C
+ * transaction.  It is visible to drivers in the @i2c_transfer() procedure,
+ * to userspace from i2c-dev, and to I2C adapter drivers through the
+ * @i2c_adapter.@master_xfer() method.
+ *
+ * Except when I2C "protocol mangling" is used, all I2C adapters implement
+ * the standard rules for I2C transactions.  Each transaction begins with a
+ * START.  That is followed by the slave address, and a bit encoding read
+ * versus write.  Then follow all the data bytes, possibly including a byte
+ * with SMBus PEC.  The transfer terminates with a NAK, or when all those
+ * bytes have been transferred and ACKed.  If this is the last message in a
+ * group, it is followed by a STOP.  Otherwise it is followed by the next
+ * @i2c_msg transaction segment, beginning with a (repeated) START.
+ *
+ * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
+ * passing certain @flags may have changed those standard protocol behaviors.
+ * Those flags are only for use with broken/nonconforming slaves, and with
+ * adapters which are known to support the specific mangling options they
+ * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
  */
 struct i2c_msg {
        __u16 addr;     /* slave address                        */
        __u16 flags;
-#define I2C_M_TEN      0x10    /* we have a ten bit chip address       */
-#define I2C_M_RD       0x01
-#define I2C_M_NOSTART  0x4000
-#define I2C_M_REV_DIR_ADDR     0x2000
-#define I2C_M_IGNORE_NAK       0x1000
-#define I2C_M_NO_RD_ACK                0x0800
-#define I2C_M_RECV_LEN         0x0400 /* length will be first received byte */
+#define I2C_M_TEN              0x0010  /* this is a ten bit chip address */
+#define I2C_M_RD               0x0001  /* read data, from slave to master */
+#define I2C_M_NOSTART          0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_REV_DIR_ADDR     0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_IGNORE_NAK       0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_NO_RD_ACK                0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_RECV_LEN         0x0400  /* length will be first received byte */
        __u16 len;              /* msg length                           */
        __u8 *buf;              /* pointer to msg data                  */
 };
@@ -466,7 +491,7 @@ struct i2c_msg {
 #define I2C_FUNC_I2C                   0x00000001
 #define I2C_FUNC_10BIT_ADDR            0x00000002
 #define I2C_FUNC_PROTOCOL_MANGLING     0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
-#define I2C_FUNC_SMBUS_HWPEC_CALC      0x00000008 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_PEC             0x00000008
 #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
 #define I2C_FUNC_SMBUS_QUICK           0x00010000
 #define I2C_FUNC_SMBUS_READ_BYTE       0x00020000
@@ -502,7 +527,8 @@ struct i2c_msg {
                              I2C_FUNC_SMBUS_WORD_DATA | \
                              I2C_FUNC_SMBUS_PROC_CALL | \
                              I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
-                             I2C_FUNC_SMBUS_I2C_BLOCK)
+                            I2C_FUNC_SMBUS_I2C_BLOCK | \
+                            I2C_FUNC_SMBUS_PEC)
 
 /*
  * Data for SMBus Messages
@@ -532,38 +558,8 @@ union i2c_smbus_data {
 #define I2C_SMBUS_I2C_BLOCK_DATA    8
 
 
-/* ----- commands for the ioctl like i2c_command call:
- * note that additional calls are defined in the algorithm and hw
- *     dependent layers - these can be listed here, or see the
- *     corresponding header files.
- */
-                               /* -> bit-adapter specific ioctls       */
-#define I2C_RETRIES    0x0701  /* number of times a device address      */
-                               /* should be polled when not            */
-                                /* acknowledging                       */
-#define I2C_TIMEOUT    0x0702  /* set timeout - call with int          */
-
-
-/* this is for i2c-dev.c       */
-#define I2C_SLAVE      0x0703  /* Change slave address                 */
-                               /* Attn.: Slave address is 7 or 10 bits */
-#define I2C_SLAVE_FORCE        0x0706  /* Change slave address                 */
-                               /* Attn.: Slave address is 7 or 10 bits */
-                               /* This changes the address, even if it */
-                               /* is already taken!                    */
-#define I2C_TENBIT     0x0704  /* 0 for 7 bit addrs, != 0 for 10 bit   */
-
-#define I2C_FUNCS      0x0705  /* Get the adapter functionality */
-#define I2C_RDWR       0x0707  /* Combined R/W transfer (one stop only)*/
-#define I2C_PEC                0x0708  /* != 0 for SMBus PEC                   */
-
-#define I2C_SMBUS      0x0720  /* SMBus-level access */
-
-/* ----- I2C-DEV: char device interface stuff ------------------------- */
 #ifdef __KERNEL__
 
-#define I2C_MAJOR      89              /* Device major number          */
-
 /* These defines are used for probing i2c client addresses */
 /* The length of the option lists */
 #define I2C_CLIENT_MAX_OPTS 48
index 85d448b4abec739976bf654ad6b23ca306107731..02a27e8cbad2b250becd2edeb7d3c40102ac40bd 100644 (file)
@@ -681,7 +681,7 @@ typedef struct hwif_s {
        u8 straight8;   /* Alan's straight 8 check */
        u8 bus_state;   /* power state of the IDE bus */
 
-       u8 host_flags;
+       u16 host_flags;
 
        u8 pio_mask;
 
@@ -702,10 +702,10 @@ typedef struct hwif_s {
 #if 0
        ide_hwif_ops_t  *hwifops;
 #else
-       /* routine to set PIO mode for drives */
+       /* routine to program host for PIO mode */
        void    (*set_pio_mode)(ide_drive_t *, const u8);
-       /* routine to retune DMA modes for drives */
-       int     (*speedproc)(ide_drive_t *, const u8);
+       /* routine to program host for DMA mode */
+       void    (*set_dma_mode)(ide_drive_t *, const u8);
        /* tweaks hardware to select drive */
        void    (*selectproc)(ide_drive_t *);
        /* chipset polling based on hba specifics */
@@ -1079,16 +1079,7 @@ extern void ide_fix_driveid(struct hd_driveid *);
  */
 extern void ide_fixstring(u8 *, const int, const int);
 
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after doing "*startstop = ide_error()", and the
- * caller should return the updated value of "startstop" in this case.
- * "startstop" is unchanged when the function returns 0;
- * (startstop, drive, good, bad, timeout)
- */
-extern int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
+int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 /*
  * Start a reset operation for an IDE interface.
@@ -1162,7 +1153,6 @@ extern void SELECT_MASK(ide_drive_t *, int);
 extern void QUIRK_LIST(ide_drive_t *);
 
 extern int drive_is_ready(ide_drive_t *);
-extern int wait_for_ready(ide_drive_t *, int /* timeout */);
 
 /*
  * taskfile io for disks for now...and builds request from ide_ioctl
@@ -1262,6 +1252,15 @@ enum {
        IDE_HFLAG_ABUSE_FAST_DEVSEL     = (1 << 5),
        /* use 100-102 and 200-202 PIO values to set DMA modes */
        IDE_HFLAG_ABUSE_DMA_MODES       = (1 << 6),
+       /*
+        * keep DMA setting when programming PIO mode, may be used only
+        * for hosts which have separate PIO and DMA timings (ie. PMAC)
+        */
+       IDE_HFLAG_SET_PIO_MODE_KEEP_DMA = (1 << 7),
+       /* program host for the transfer mode after programming device */
+       IDE_HFLAG_POST_SET_MODE         = (1 << 8),
+       /* don't program host/device for the transfer mode ("smart" hosts) */
+       IDE_HFLAG_NO_SET_MODE           = (1 << 9),
 };
 
 typedef struct ide_pci_device_s {
@@ -1278,7 +1277,7 @@ typedef struct ide_pci_device_s {
        u8                      bootable;
        unsigned int            extra;
        struct ide_pci_device_s *next;
-       u                     host_flags;
+       u16                     host_flags;
        u8                      pio_mask;
        u8                      udma_mask;
 } ide_pci_device_t;
@@ -1301,7 +1300,6 @@ int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 int __ide_dma_bad_drive(ide_drive_t *);
-int __ide_dma_good_drive(ide_drive_t *);
 
 u8 ide_find_dma_mode(ide_drive_t *, u8);
 
@@ -1420,6 +1418,9 @@ unsigned int ide_pio_cycle_time(ide_drive_t *, u8);
 u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8);
 extern const ide_pio_timings_t ide_pio_timings[6];
 
+int ide_set_pio_mode(ide_drive_t *, u8);
+int ide_set_dma_mode(ide_drive_t *, u8);
+
 void ide_set_pio(ide_drive_t *, u8);
 
 static inline void ide_set_max_pio(ide_drive_t *drive)
index e1fc1d16d3cde35a0c150773cb950e0b09cbaebc..1246d46abbc089c6a87322b46fe6b03bde1f0189 100644 (file)
@@ -52,14 +52,14 @@ struct net_lro_desc {
        struct tcphdr *tcph;
        struct vlan_group *vgrp;
        __wsum  data_csum;
-       u32 tcp_rcv_tsecr;
-       u32 tcp_rcv_tsval;
-       u32 tcp_ack;
+       __be32 tcp_rcv_tsecr;
+       __be32 tcp_rcv_tsval;
+       __be32 tcp_ack;
        u32 tcp_next_seq;
        u32 skb_tot_frags_len;
        u16 ip_tot_len;
        u16 tcp_saw_tstamp;             /* timestamps enabled */
-       u16 tcp_window;
+       __be16 tcp_window;
        u16 vlan_tag;
        int pkt_aggr_cnt;               /* counts aggregated packets */
        int vlan_packet;
index 125e925320fdd611c9f7043d77f25a276cf1618d..f30da6fc08e3775dfa5b0945004711baae879a47 100644 (file)
@@ -523,6 +523,8 @@ struct input_absinfo {
 #define KEY_ADDRESSBOOK                0x1ad   /* AL Contacts/Address Book */
 #define KEY_MESSENGER          0x1ae   /* AL Instant Messaging */
 #define KEY_DISPLAYTOGGLE      0x1af   /* Turn display (LCD) on and off */
+#define KEY_SPELLCHECK         0x1b0   /* AL Spell Check */
+#define KEY_LOGOFF             0x1b1   /* AL Logoff */
 
 #define KEY_DEL_EOL            0x1c0
 #define KEY_DEL_EOS            0x1c1
index 452737551260ef1663caa93d6ca5d7526dacd275..700a93b79189b52584d0f9208503fd912fc9de73 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/bit_spinlock.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
+#include <linux/lockdep.h>
 
 #include <asm/semaphore.h>
 #endif
@@ -396,6 +397,10 @@ struct handle_s
        unsigned int    h_sync:         1;      /* sync-on-close */
        unsigned int    h_jdata:        1;      /* force data journaling */
        unsigned int    h_aborted:      1;      /* fatal error on handle */
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map      h_lockdep_map;
+#endif
 };
 
 
index 840631fa5ff16629b7e1490944447ea1c0c113ba..6b563cae23df22c768f63cbb5610d35cd6771a26 100644 (file)
@@ -46,6 +46,7 @@
 #define JFFS2_COMPR_COPY       0x04
 #define JFFS2_COMPR_DYNRUBIN   0x05
 #define JFFS2_COMPR_ZLIB       0x06
+#define JFFS2_COMPR_LZO                0x07
 /* Compatibility flags. */
 #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
 #define JFFS2_NODE_ACCURATE 0x2000
index d7a5e034c3a219197007df6923e9a79507762022..e757a74b9d17e53c5bb2fdbb7816f120d849a040 100644 (file)
@@ -109,6 +109,10 @@ static inline u64 get_jiffies_64(void)
         ((long)(a) - (long)(b) >= 0))
 #define time_before_eq(a,b)    time_after_eq(b,a)
 
+#define time_in_range(a,b,c) \
+       (time_after_eq(a,b) && \
+        time_before_eq(a,c))
+
 /* Same as above, but does so with platform independent 64bit types.
  * These must be used when utilizing jiffies_64 (i.e. return value of
  * get_jiffies_64() */
index 43e895f1cabef24137e213958eeef48bde70ff28..12bf44f083f53355ca785a663bd76422dafcdfc1 100644 (file)
@@ -23,6 +23,7 @@ struct cpu_usage_stat {
        cputime64_t idle;
        cputime64_t iowait;
        cputime64_t steal;
+       cputime64_t guest;
 };
 
 struct kernel_stat {
index e6edca81ab847f54ff920b2b4b346e3ec60400c1..057a7f34ee36b2aec3fdfad395b0f7c4323796ec 100644 (file)
@@ -4,8 +4,7 @@
 /*
  * Userspace interface for /dev/kvm - kernel based virtual machine
  *
- * Note: this interface is considered experimental and may change without
- *       notice.
+ * Note: you must update KVM_API_VERSION if you change this interface.
  */
 
 #include <asm/types.h>
 
 #define KVM_API_VERSION 12
 
-/*
- * Architectural interrupt line count, and the size of the bitmap needed
- * to hold them.
- */
+/* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
-#define KVM_IRQ_BITMAP_SIZE_BYTES    ((KVM_NR_INTERRUPTS + 7) / 8)
-#define KVM_IRQ_BITMAP_SIZE(type)    (KVM_IRQ_BITMAP_SIZE_BYTES / sizeof(type))
-
 
 /* for KVM_CREATE_MEMORY_REGION */
 struct kvm_memory_region {
@@ -41,20 +34,89 @@ struct kvm_memory_alias {
        __u64 target_phys_addr;
 };
 
-enum kvm_exit_reason {
-       KVM_EXIT_UNKNOWN          = 0,
-       KVM_EXIT_EXCEPTION        = 1,
-       KVM_EXIT_IO               = 2,
-       KVM_EXIT_HYPERCALL        = 3,
-       KVM_EXIT_DEBUG            = 4,
-       KVM_EXIT_HLT              = 5,
-       KVM_EXIT_MMIO             = 6,
-       KVM_EXIT_IRQ_WINDOW_OPEN  = 7,
-       KVM_EXIT_SHUTDOWN         = 8,
-       KVM_EXIT_FAIL_ENTRY       = 9,
-       KVM_EXIT_INTR             = 10,
+/* for KVM_IRQ_LINE */
+struct kvm_irq_level {
+       /*
+        * ACPI gsi notion of irq.
+        * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
+        * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+        */
+       __u32 irq;
+       __u32 level;
+};
+
+/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
+struct kvm_pic_state {
+       __u8 last_irr;  /* edge detection */
+       __u8 irr;               /* interrupt request register */
+       __u8 imr;               /* interrupt mask register */
+       __u8 isr;               /* interrupt service register */
+       __u8 priority_add;      /* highest irq priority */
+       __u8 irq_base;
+       __u8 read_reg_select;
+       __u8 poll;
+       __u8 special_mask;
+       __u8 init_state;
+       __u8 auto_eoi;
+       __u8 rotate_on_auto_eoi;
+       __u8 special_fully_nested_mode;
+       __u8 init4;             /* true if 4 byte init */
+       __u8 elcr;              /* PIIX edge/trigger selection */
+       __u8 elcr_mask;
+};
+
+#define KVM_IOAPIC_NUM_PINS  24
+struct kvm_ioapic_state {
+       __u64 base_address;
+       __u32 ioregsel;
+       __u32 id;
+       __u32 irr;
+       __u32 pad;
+       union {
+               __u64 bits;
+               struct {
+                       __u8 vector;
+                       __u8 delivery_mode:3;
+                       __u8 dest_mode:1;
+                       __u8 delivery_status:1;
+                       __u8 polarity:1;
+                       __u8 remote_irr:1;
+                       __u8 trig_mode:1;
+                       __u8 mask:1;
+                       __u8 reserve:7;
+                       __u8 reserved[4];
+                       __u8 dest_id;
+               } fields;
+       } redirtbl[KVM_IOAPIC_NUM_PINS];
 };
 
+#define KVM_IRQCHIP_PIC_MASTER   0
+#define KVM_IRQCHIP_PIC_SLAVE    1
+#define KVM_IRQCHIP_IOAPIC       2
+
+struct kvm_irqchip {
+       __u32 chip_id;
+       __u32 pad;
+        union {
+               char dummy[512];  /* reserving space */
+               struct kvm_pic_state pic;
+               struct kvm_ioapic_state ioapic;
+       } chip;
+};
+
+#define KVM_EXIT_UNKNOWN          0
+#define KVM_EXIT_EXCEPTION        1
+#define KVM_EXIT_IO               2
+#define KVM_EXIT_HYPERCALL        3
+#define KVM_EXIT_DEBUG            4
+#define KVM_EXIT_HLT              5
+#define KVM_EXIT_MMIO             6
+#define KVM_EXIT_IRQ_WINDOW_OPEN  7
+#define KVM_EXIT_SHUTDOWN         8
+#define KVM_EXIT_FAIL_ENTRY       9
+#define KVM_EXIT_INTR             10
+#define KVM_EXIT_SET_TPR          11
+
 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
 struct kvm_run {
        /* in */
@@ -106,11 +168,14 @@ struct kvm_run {
                } mmio;
                /* KVM_EXIT_HYPERCALL */
                struct {
+                       __u64 nr;
                        __u64 args[6];
                        __u64 ret;
                        __u32 longmode;
                        __u32 pad;
                } hypercall;
+               /* Fix the size of the union. */
+               char padding[256];
        };
 };
 
@@ -139,6 +204,12 @@ struct kvm_fpu {
        __u32 pad2;
 };
 
+/* for KVM_GET_LAPIC and KVM_SET_LAPIC */
+#define KVM_APIC_REG_SIZE 0x400
+struct kvm_lapic_state {
+       char regs[KVM_APIC_REG_SIZE];
+};
+
 struct kvm_segment {
        __u64 base;
        __u32 limit;
@@ -164,7 +235,7 @@ struct kvm_sregs {
        __u64 cr0, cr2, cr3, cr4, cr8;
        __u64 efer;
        __u64 apic_base;
-       __u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE(__u64)];
+       __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
 };
 
 struct kvm_msr_entry {
@@ -271,6 +342,12 @@ struct kvm_signal_mask {
  */
 #define KVM_GET_VCPU_MMAP_SIZE    _IO(KVMIO,   0x04) /* in bytes */
 
+/*
+ * Extension capability list.
+ */
+#define KVM_CAP_IRQCHIP          0
+#define KVM_CAP_HLT      1
+
 /*
  * ioctls for VM fds
  */
@@ -282,6 +359,11 @@ struct kvm_signal_mask {
 #define KVM_CREATE_VCPU           _IO(KVMIO,  0x41)
 #define KVM_GET_DIRTY_LOG         _IOW(KVMIO, 0x42, struct kvm_dirty_log)
 #define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO, 0x43, struct kvm_memory_alias)
+/* Device model IOC */
+#define KVM_CREATE_IRQCHIP       _IO(KVMIO,  0x60)
+#define KVM_IRQ_LINE             _IOW(KVMIO, 0x61, struct kvm_irq_level)
+#define KVM_GET_IRQCHIP                  _IOWR(KVMIO, 0x62, struct kvm_irqchip)
+#define KVM_SET_IRQCHIP                  _IOR(KVMIO,  0x63, struct kvm_irqchip)
 
 /*
  * ioctls for vcpu fds
@@ -300,5 +382,7 @@ struct kvm_signal_mask {
 #define KVM_SET_SIGNAL_MASK       _IOW(KVMIO,  0x8b, struct kvm_signal_mask)
 #define KVM_GET_FPU               _IOR(KVMIO,  0x8c, struct kvm_fpu)
 #define KVM_SET_FPU               _IOW(KVMIO,  0x8d, struct kvm_fpu)
+#define KVM_GET_LAPIC             _IOR(KVMIO,  0x8e, struct kvm_lapic_state)
+#define KVM_SET_LAPIC             _IOW(KVMIO,  0x8f, struct kvm_lapic_state)
 
 #endif
index 0e843bf658777114a3a664e1c978588ee623cc3f..f6279f68a8270c143196c1c0c09afbea2cff02be 100644 (file)
@@ -238,6 +238,7 @@ extern void lockdep_info(void);
 extern void lockdep_reset(void);
 extern void lockdep_reset_lock(struct lockdep_map *lock);
 extern void lockdep_free_key_range(void *start, unsigned long size);
+extern void lockdep_sys_exit(void);
 
 extern void lockdep_off(void);
 extern void lockdep_on(void);
@@ -251,6 +252,13 @@ extern void lockdep_on(void);
 extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
                             struct lock_class_key *key, int subclass);
 
+/*
+ * To initialize a lockdep_map statically use this macro.
+ * Note that _name must not be NULL.
+ */
+#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
+       { .name = (_name), .key = (void *)(_key), }
+
 /*
  * Reinitialize a lock key - for cases where there is special locking or
  * special initialization of locks so that the validator gets the scope
@@ -317,6 +325,7 @@ static inline void lockdep_on(void)
 # define INIT_LOCKDEP
 # define lockdep_reset()               do { debug_locks = 1; } while (0)
 # define lockdep_free_key_range(start, size)   do { } while (0)
+# define lockdep_sys_exit()                    do { } while (0)
 /*
  * The class key takes no space if lockdep is disabled:
  */
diff --git a/include/linux/maple.h b/include/linux/maple.h
new file mode 100644 (file)
index 0000000..bad9a7b
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef __LINUX_MAPLE_H
+#define __LINUX_MAPLE_H
+
+#include <linux/device.h>
+
+extern struct bus_type maple_bus_type;
+
+/* Maple Bus command and response codes */
+enum maple_code {
+       MAPLE_RESPONSE_FILEERR = -5,
+       MAPLE_RESPONSE_AGAIN = -4,      /* request should be retransmitted */
+       MAPLE_RESPONSE_BADCMD = -3,
+       MAPLE_RESPONSE_BADFUNC = -2,
+       MAPLE_RESPONSE_NONE = -1,       /* unit didn't respond at all */
+       MAPLE_COMMAND_DEVINFO = 1,
+       MAPLE_COMMAND_ALLINFO = 2,
+       MAPLE_COMMAND_RESET = 3,
+       MAPLE_COMMAND_KILL = 4,
+       MAPLE_RESPONSE_DEVINFO = 5,
+       MAPLE_RESPONSE_ALLINFO = 6,
+       MAPLE_RESPONSE_OK = 7,
+       MAPLE_RESPONSE_DATATRF = 8,
+       MAPLE_COMMAND_GETCOND = 9,
+       MAPLE_COMMAND_GETMINFO = 10,
+       MAPLE_COMMAND_BREAD = 11,
+       MAPLE_COMMAND_BWRITE = 12,
+       MAPLE_COMMAND_SETCOND = 14
+};
+
+struct mapleq {
+       struct list_head list;
+       struct maple_device *dev;
+       void *sendbuf, *recvbuf, *recvbufdcsp;
+       unsigned char length;
+       enum maple_code command;
+};
+
+struct maple_devinfo {
+       unsigned long function;
+       unsigned long function_data[3];
+       unsigned char area_code;
+       unsigned char connector_directon;
+       char product_name[31];
+       char product_licence[61];
+       unsigned short standby_power;
+       unsigned short max_power;
+};
+
+struct maple_device {
+       struct maple_driver *driver;
+       struct mapleq *mq;
+       void *private_data;
+       void (*callback) (struct mapleq * mq);
+       unsigned long when, interval, function;
+       struct maple_devinfo devinfo;
+       unsigned char port, unit;
+       char product_name[32];
+       char product_licence[64];
+       int registered;
+       struct device dev;
+};
+
+struct maple_driver {
+       unsigned long function;
+       int (*connect) (struct maple_device * dev);
+       void (*disconnect) (struct maple_device * dev);
+       struct device_driver drv;
+};
+
+void maple_getcond_callback(struct maple_device *dev,
+                           void (*callback) (struct mapleq * mq),
+                           unsigned long interval,
+                           unsigned long function);
+int maple_driver_register(struct device_driver *drv);
+void maple_add_packet(struct mapleq *mq);
+
+#define to_maple_dev(n) container_of(n, struct maple_device, dev)
+#define to_maple_driver(n) container_of(n, struct maple_driver, drv)
+
+#endif /* __LINUX_MAPLE_H */
index 74523d999f7a9a99f4e5890102e653c49f094ade..522b0dd836cf84672ff16d4b40247b9bfb80642b 100644 (file)
@@ -262,11 +262,6 @@ struct pcmcia_device_id {
 #define PCMCIA_DEV_ID_MATCH_FAKE_CIS   0x0200
 #define PCMCIA_DEV_ID_MATCH_ANONYMOUS  0x0400
 
-/* I2C */
-struct i2c_device_id {
-       __u16 id;
-};
-
 /* Input */
 #define INPUT_DEVICE_ID_EV_MAX         0x1f
 #define INPUT_DEVICE_ID_KEY_MIN_INTERESTING    0x71
index 123948b1454787401b63aefebb2dec1278f99a3f..e17c5343cf517e6938c93551e6878400b6a11046 100644 (file)
 #define cfi_interleave_is_8(cfi) (0)
 #endif
 
+#ifndef cfi_interleave
+#warning No CONFIG_MTD_CFI_Ix selected. No NOR chip support can work.
+static inline int cfi_interleave(void *cfi)
+{
+       BUG();
+       return 0;
+}
+#endif
+
 static inline int cfi_interleave_supported(int i)
 {
        switch (i) {
index a293a3b78e05741ff372229959aee31fb5b5e834..39e7d2a1be9a5a93657e3af6d62c8f9dd901ac88 100644 (file)
@@ -40,6 +40,7 @@ typedef enum {
        FL_POINT,
        FL_XIP_WHILE_ERASING,
        FL_XIP_WHILE_WRITING,
+       FL_SHUTDOWN,
        FL_UNKNOWN
 } flstate_t;
 
index 81f3a314dd76dfc6057ef9f7a82fff3b4d08c652..a9fae032ba8176db0a256aea1160f3c04e78720e 100644 (file)
 #endif
 
 #ifndef map_bankwidth
-#error "No bus width supported. What's the point?"
+#warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work"
+static inline int map_bankwidth(void *map)
+{
+       BUG();
+       return 0;
+}
+#define map_bankwidth_is_large(map) (0)
+#define map_words(map) (0)
+#define MAX_MAP_BANKWIDTH 1
 #endif
 
 static inline int map_bankwidth_supported(int w)
index fd64ccfbce02874fd2600b79dc02d84767bde7ae..783fc983417c9786c8d99eecca5dd19a36e4895d 100644 (file)
@@ -133,6 +133,13 @@ struct mtd_info {
        int numeraseregions;
        struct mtd_erase_region_info *eraseregions;
 
+       /*
+        * Erase is an asynchronous operation.  Device drivers are supposed
+        * to call instr->callback() whenever the operation completes, even
+        * if it completes with a failure.
+        * Callers are supposed to pass a callback function and wait for it
+        * to be called before writing to the block.
+        */
        int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
 
        /* This stuff for eXecute-In-Place */
index d2365c8dcacc86ebf872a2124b3dc16201c09877..c42bc7f533a5453362a2cd5e550a204e0eeb4e5f 100644 (file)
@@ -432,6 +432,7 @@ struct nand_chip {
 #define NAND_MFR_STMICRO       0x20
 #define NAND_MFR_HYNIX         0xad
 #define NAND_MFR_MICRON                0x2c
+#define NAND_MFR_AMD           0x01
 
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
index a56d24ada5057eacddc91cb51ee4254cfdcfed13..fd0a260e070b483b7be93288d088367949366b47 100644 (file)
@@ -60,6 +60,7 @@ struct onenand_bufferram {
  * @erase_shift:       [INTERN] number of address bits in a block
  * @page_shift:                [INTERN] number of address bits in a page
  * @page_mask:         [INTERN] a page per block mask
+ * @writesize:         [INTERN] a real page size
  * @bufferram_index:   [INTERN] BufferRAM index
  * @bufferram:         [INTERN] BufferRAM info
  * @readw:             [REPLACEABLE] hardware specific function for read short
@@ -100,6 +101,7 @@ struct onenand_chip {
        unsigned int            erase_shift;
        unsigned int            page_shift;
        unsigned int            page_mask;
+       unsigned int            writesize;
 
        unsigned int            bufferram_index;
        struct onenand_bufferram        bufferram[MAX_BUFFERRAM];
@@ -140,6 +142,8 @@ struct onenand_chip {
 #define ONENAND_NEXT_BUFFERRAM(this)           (this->bufferram_index ^ 1)
 #define ONENAND_SET_NEXT_BUFFERRAM(this)       (this->bufferram_index ^= 1)
 #define ONENAND_SET_PREV_BUFFERRAM(this)       (this->bufferram_index ^= 1)
+#define ONENAND_SET_BUFFERRAM0(this)           (this->bufferram_index = 0)
+#define ONENAND_SET_BUFFERRAM1(this)           (this->bufferram_index = 1)
 
 #define ONENAND_GET_SYS_CFG1(this)                                     \
        (this->read_word(this->base + ONENAND_REG_SYS_CFG1))
@@ -149,6 +153,13 @@ struct onenand_chip {
 #define ONENAND_IS_DDP(this)                                           \
        (this->device_id & ONENAND_DEVICE_IS_DDP)
 
+#ifdef CONFIG_MTD_ONENAND_2X_PROGRAM
+#define ONENAND_IS_2PLANE(this)                                                \
+       (this->options & ONENAND_HAS_2PLANE)
+#else
+#define ONENAND_IS_2PLANE(this)                        (0)
+#endif
+
 /* Check byte access in OneNAND */
 #define ONENAND_CHECK_BYTE_ACCESS(addr)                (addr & 0x1)
 
@@ -157,6 +168,7 @@ struct onenand_chip {
  */
 #define ONENAND_HAS_CONT_LOCK          (0x0001)
 #define ONENAND_HAS_UNLOCK_ALL         (0x0002)
+#define ONENAND_HAS_2PLANE             (0x0004)
 #define ONENAND_PAGEBUF_ALLOC          (0x1000)
 #define ONENAND_OOBBUF_ALLOC           (0x2000)
 
index af94719890e7676ea090620e6b6b24b50e24407f..c46161f4eee3836165e5733e41021605bd6f1357 100644 (file)
@@ -74,6 +74,8 @@
 
 #define ONENAND_DEVICE_DENSITY_512Mb   (0x002)
 #define ONENAND_DEVICE_DENSITY_1Gb     (0x003)
+#define ONENAND_DEVICE_DENSITY_2Gb     (0x004)
+#define ONENAND_DEVICE_DENSITY_4Gb     (0x005)
 
 /*
  * Version ID Register F002h (R)
 #define ONENAND_CMD_READOOB            (0x13)
 #define ONENAND_CMD_PROG               (0x80)
 #define ONENAND_CMD_PROGOOB            (0x1A)
+#define ONENAND_CMD_2X_PROG            (0x7D)
+#define ONENAND_CMD_2X_CACHE_PROG      (0x7F)
 #define ONENAND_CMD_UNLOCK             (0x23)
 #define ONENAND_CMD_LOCK               (0x2A)
 #define ONENAND_CMD_LOCK_TIGHT         (0x2C)
index 0d50ea3df6896ebcf9a60f216a0d72ba9bd14de8..6a735c72f23f1c2fd3b983af1c47d9b275879ff9 100644 (file)
@@ -120,14 +120,17 @@ static inline int fastcall mutex_is_locked(struct mutex *lock)
  * See kernel/mutex.c for detailed documentation of these APIs.
  * Also see Documentation/mutex-design.txt.
  */
-extern void fastcall mutex_lock(struct mutex *lock);
-extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
-
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
 extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
                                        unsigned int subclass);
+
+#define mutex_lock(lock) mutex_lock_nested(lock, 0)
+#define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0)
 #else
+extern void fastcall mutex_lock(struct mutex *lock);
+extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
+
 # define mutex_lock_nested(lock, subclass) mutex_lock(lock)
 # define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
 #endif
index 5a11f889e56a7f0780eb44572e4b9e2b68239c70..39dd83b183a91d0f8fa9ce27a4f8ed84c8a238a8 100644 (file)
@@ -1294,6 +1294,7 @@ static inline void netif_rx_complete(struct net_device *dev,
 /**
  *     netif_tx_lock - grab network device transmit lock
  *     @dev: network device
+ *     @cpu: cpu number of lock owner
  *
  * Get network device transmit lock
  */
index 7250eeadd7b5f703c6a401b8782b17886a36b9d0..c5164c257f71aa17ec51dda414a1921053d8ac5d 100644 (file)
 #include <linux/nfs3.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_xdr.h>
-
 #include <linux/nfs_fs_sb.h>
 
-#include <linux/rwsem.h>
 #include <linux/mempool.h>
 
 /*
@@ -77,6 +75,9 @@ struct nfs_open_context {
        struct nfs4_state *state;
        fl_owner_t lockowner;
        int mode;
+
+       unsigned long flags;
+#define NFS_CONTEXT_ERROR_WRITE                (0)
        int error;
 
        struct list_head list;
@@ -133,11 +134,6 @@ struct nfs_inode {
         * server.
         */
        unsigned long           cache_change_attribute;
-       /*
-        * Counter indicating the number of outstanding requests that
-        * will cause a file data update.
-        */
-       atomic_t                data_updates;
 
        struct rb_root          access_cache;
        struct list_head        access_cache_entry_lru;
@@ -205,27 +201,18 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
 #define NFS_CLIENT(inode)              (NFS_SERVER(inode)->client)
 #define NFS_PROTO(inode)               (NFS_SERVER(inode)->nfs_client->rpc_ops)
 #define NFS_COOKIEVERF(inode)          (NFS_I(inode)->cookieverf)
-#define NFS_READTIME(inode)            (NFS_I(inode)->read_cache_jiffies)
-#define NFS_CHANGE_ATTR(inode)         (NFS_I(inode)->change_attr)
-#define NFS_ATTRTIMEO(inode)           (NFS_I(inode)->attrtimeo)
 #define NFS_MINATTRTIMEO(inode) \
        (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
                               : NFS_SERVER(inode)->acregmin)
 #define NFS_MAXATTRTIMEO(inode) \
        (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
                               : NFS_SERVER(inode)->acregmax)
-#define NFS_ATTRTIMEO_UPDATE(inode)    (NFS_I(inode)->attrtimeo_timestamp)
 
 #define NFS_FLAGS(inode)               (NFS_I(inode)->flags)
 #define NFS_STALE(inode)               (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode)))
 
 #define NFS_FILEID(inode)              (NFS_I(inode)->fileid)
 
-static inline int nfs_caches_unstable(struct inode *inode)
-{
-       return atomic_read(&NFS_I(inode)->data_updates) != 0;
-}
-
 static inline void nfs_mark_for_revalidate(struct inode *inode)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -237,12 +224,6 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
        spin_unlock(&inode->i_lock);
 }
 
-static inline void NFS_CACHEINV(struct inode *inode)
-{
-       if (!nfs_caches_unstable(inode))
-               nfs_mark_for_revalidate(inode);
-}
-
 static inline int nfs_server_capable(struct inode *inode, int cap)
 {
        return NFS_SERVER(inode)->caps & cap;
@@ -253,28 +234,33 @@ static inline int NFS_USE_READDIRPLUS(struct inode *inode)
        return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
 }
 
+static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
+{
+       dentry->d_time = verf;
+}
+
 /**
  * nfs_save_change_attribute - Returns the inode attribute change cookie
- * @inode - pointer to inode
+ * @dir - pointer to parent directory inode
  * The "change attribute" is updated every time we finish an operation
  * that will result in a metadata change on the server.
  */
-static inline long nfs_save_change_attribute(struct inode *inode)
+static inline unsigned long nfs_save_change_attribute(struct inode *dir)
 {
-       return NFS_I(inode)->cache_change_attribute;
+       return NFS_I(dir)->cache_change_attribute;
 }
 
 /**
- * nfs_verify_change_attribute - Detects NFS inode cache updates
- * @inode - pointer to inode
+ * nfs_verify_change_attribute - Detects NFS remote directory changes
+ * @dir - pointer to parent directory inode
  * @chattr - previously saved change attribute
- * Return "false" if metadata has been updated (or is in the process of
- * being updated) since the change attribute was saved.
+ * Return "false" if the verifiers doesn't match the change attribute.
+ * This would usually indicate that the directory contents have changed on
+ * the server, and that any dentries need revalidating.
  */
-static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
+static inline int nfs_verify_change_attribute(struct inode *dir, unsigned long chattr)
 {
-       return !nfs_caches_unstable(inode)
-               && time_after_eq(chattr, NFS_I(inode)->cache_change_attribute);
+       return chattr == NFS_I(dir)->cache_change_attribute;
 }
 
 /*
@@ -283,15 +269,14 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long
 extern int nfs_sync_mapping(struct address_space *mapping);
 extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
 extern void nfs_zap_caches(struct inode *);
+extern void nfs_invalidate_atime(struct inode *);
 extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
                                struct nfs_fattr *);
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
+extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int nfs_permission(struct inode *, int, struct nameidata *);
-extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
-extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
-extern void nfs_access_zap_cache(struct inode *inode);
 extern int nfs_open(struct inode *, struct file *);
 extern int nfs_release(struct inode *, struct file *);
 extern int nfs_attribute_timeout(struct inode *inode);
@@ -301,13 +286,10 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map
 extern int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping);
 extern int nfs_setattr(struct dentry *, struct iattr *);
 extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
-extern void nfs_begin_attr_update(struct inode *);
-extern void nfs_end_attr_update(struct inode *);
-extern void nfs_begin_data_update(struct inode *);
-extern void nfs_end_data_update(struct inode *);
 extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
 extern void put_nfs_open_context(struct nfs_open_context *ctx);
 extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
+extern u64 nfs_compat_user_ino64(u64 fileid);
 
 /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
 extern __be32 root_nfs_parse_addr(char *name); /*__init*/
@@ -328,14 +310,15 @@ extern const struct inode_operations nfs3_file_inode_operations;
 extern const struct file_operations nfs_file_operations;
 extern const struct address_space_operations nfs_file_aops;
 
-static inline struct rpc_cred *nfs_file_cred(struct file *file)
+static inline struct nfs_open_context *nfs_file_open_context(struct file *filp)
 {
-       if (file != NULL) {
-               struct nfs_open_context *ctx;
+       return filp->private_data;
+}
 
-               ctx = (struct nfs_open_context*)file->private_data;
-               return ctx->cred;
-       }
+static inline struct rpc_cred *nfs_file_cred(struct file *file)
+{
+       if (file != NULL)
+               return nfs_file_open_context(file)->cred;
        return NULL;
 }
 
@@ -378,6 +361,8 @@ extern const struct file_operations nfs_dir_operations;
 extern struct dentry_operations nfs_dentry_operations;
 
 extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
+extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
+extern void nfs_access_zap_cache(struct inode *inode);
 
 /*
  * linux/fs/nfs/symlink.c
@@ -420,15 +405,14 @@ extern int  nfs_flush_incompatible(struct file *file, struct page *page);
 extern int  nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
 extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
 extern void nfs_writedata_release(void *);
-extern int nfs_set_page_dirty(struct page *);
 
 /*
  * Try to write back everything synchronously (but check the
  * return value!)
  */
 extern long nfs_sync_mapping_wait(struct address_space *, struct writeback_control *, int);
-extern int nfs_sync_mapping_range(struct address_space *, loff_t, loff_t, int);
 extern int nfs_wb_all(struct inode *inode);
+extern int nfs_wb_nocommit(struct inode *inode);
 extern int nfs_wb_page(struct inode *inode, struct page* page);
 extern int nfs_wb_page_priority(struct inode *inode, struct page* page, int how);
 extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
index 78e60798d10e39c513fe9978677dd67d9578d4a3..30dbcc185e6972829967562693eb75eb101f53b6 100644 (file)
@@ -30,7 +30,6 @@
 #define PG_BUSY                        0
 #define PG_NEED_COMMIT         1
 #define PG_NEED_RESCHED                2
-#define PG_NEED_FLUSH          3
 
 struct nfs_inode;
 struct nfs_page {
index cf74a4db84a57af5095467b38888cc5b402bb77d..daab252f2e5cf653e41bb39721596bfc7aa89315 100644 (file)
@@ -62,7 +62,8 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR         0x0002          /* post-op attributes */
 #define NFS_ATTR_FATTR_V3      0x0004          /* NFSv3 attributes */
 #define NFS_ATTR_FATTR_V4      0x0008          /* NFSv4 change attribute */
-#define NFS_ATTR_FATTR_V4_REFERRAL     0x0010          /* NFSv4 referral */
+#define NFS_ATTR_WCC_V4                0x0010          /* pre-op change attribute */
+#define NFS_ATTR_FATTR_V4_REFERRAL     0x0020          /* NFSv4 referral */
 
 /*
  * Info on the file system
@@ -538,10 +539,13 @@ typedef u64 clientid4;
 
 struct nfs4_accessargs {
        const struct nfs_fh *           fh;
+       const u32 *                     bitmask;
        u32                             access;
 };
 
 struct nfs4_accessres {
+       const struct nfs_server *       server;
+       struct nfs_fattr *              fattr;
        u32                             supported;
        u32                             access;
 };
index e452256d3f72a9347ed79ffda31f10d1113e5e80..604a0d786bc6a2699f3968eed506c6ec001ebc0a 100644 (file)
@@ -153,19 +153,21 @@ extern int nfsd_max_blksize;
  */
 #ifdef CONFIG_NFSD_V4
 extern unsigned int max_delegations;
-void nfs4_state_init(void);
-int nfs4_state_start(void);
+int nfs4_state_init(void);
+void nfsd4_free_slabs(void);
+void nfs4_state_start(void);
 void nfs4_state_shutdown(void);
 time_t nfs4_lease_time(void);
 void nfs4_reset_lease(time_t leasetime);
 int nfs4_reset_recoverydir(char *recdir);
 #else
-static inline void nfs4_state_init(void){};
-static inline int nfs4_state_start(void){return 0;}
-static inline void nfs4_state_shutdown(void){}
-static inline time_t nfs4_lease_time(void){return 0;}
-static inline void nfs4_reset_lease(time_t leasetime){}
-static inline int nfs4_reset_recoverydir(char *recdir) {return 0;}
+static inline int nfs4_state_init(void) { return 0; }
+static inline void nfsd4_free_slabs(void) { }
+static inline void nfs4_state_start(void) { }
+static inline void nfs4_state_shutdown(void) { }
+static inline time_t nfs4_lease_time(void) { return 0; }
+static inline void nfs4_reset_lease(time_t leasetime) { }
+static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
 #endif
 
 /*
index 11e568ee0eeb877b69ea1e78f320f203bffb6a39..d1941cb965e9497e5dd2e4f1161f0c06aed31b1d 100644 (file)
@@ -150,17 +150,7 @@ typedef struct svc_fh {
        struct timespec         fh_pre_ctime;   /* ctime before oper */
 
        /* Post-op attributes saved in fh_unlock */
-       umode_t                 fh_post_mode;   /* i_mode */
-       nlink_t                 fh_post_nlink;  /* i_nlink */
-       uid_t                   fh_post_uid;    /* i_uid */
-       gid_t                   fh_post_gid;    /* i_gid */
-       __u64                   fh_post_size;   /* i_size */
-       unsigned long           fh_post_blocks; /* i_blocks */
-       unsigned long           fh_post_blksize;/* i_blksize */
-       __be32                  fh_post_rdev[2];/* i_rdev */
-       struct timespec         fh_post_atime;  /* i_atime */
-       struct timespec         fh_post_mtime;  /* i_mtime */
-       struct timespec         fh_post_ctime;  /* i_ctime */
+       struct kstat            fh_post_attr;   /* full attrs after operation */
 #endif /* CONFIG_NFSD_V3 */
 
 } svc_fh;
@@ -297,36 +287,12 @@ fill_pre_wcc(struct svc_fh *fhp)
        if (!fhp->fh_pre_saved) {
                fhp->fh_pre_mtime = inode->i_mtime;
                fhp->fh_pre_ctime = inode->i_ctime;
-                       fhp->fh_pre_size  = inode->i_size;
-                       fhp->fh_pre_saved = 1;
+               fhp->fh_pre_size  = inode->i_size;
+               fhp->fh_pre_saved = 1;
        }
 }
 
-/*
- * Fill in the post_op attr for the wcc data
- */
-static inline void
-fill_post_wcc(struct svc_fh *fhp)
-{
-       struct inode    *inode = fhp->fh_dentry->d_inode;
-
-       if (fhp->fh_post_saved)
-               printk("nfsd: inode locked twice during operation.\n");
-
-       fhp->fh_post_mode       = inode->i_mode;
-       fhp->fh_post_nlink      = inode->i_nlink;
-       fhp->fh_post_uid        = inode->i_uid;
-       fhp->fh_post_gid        = inode->i_gid;
-       fhp->fh_post_size       = inode->i_size;
-       fhp->fh_post_blksize    = BLOCK_SIZE;
-       fhp->fh_post_blocks     = inode->i_blocks;
-       fhp->fh_post_rdev[0]    = htonl((u32)imajor(inode));
-       fhp->fh_post_rdev[1]    = htonl((u32)iminor(inode));
-       fhp->fh_post_atime      = inode->i_atime;
-       fhp->fh_post_mtime      = inode->i_mtime;
-       fhp->fh_post_ctime      = inode->i_ctime;
-       fhp->fh_post_saved      = 1;
-}
+extern void fill_post_wcc(struct svc_fh *);
 #else
 #define        fill_pre_wcc(ignored)
 #define fill_post_wcc(notused)
index 1b653267133af027daff4d1e6ab4d1b54c1ce9b0..b0ddfb41c790754034a9cb5cfe650c6c00602339 100644 (file)
@@ -428,8 +428,8 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
        cinfo->atomic = 1;
        cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
        cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
-       cinfo->after_ctime_sec = fhp->fh_post_ctime.tv_sec;
-       cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec;
+       cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
+       cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
 }
 
 int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
index 87439ad94685c639056377cf84762089ba590ef7..2aaf1c16ce981ed83e35caa1e16f7cef3beb5a3e 100644 (file)
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC    0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
 
+#define PCI_VENDOR_ID_ATTO             0x117c
+
 #define PCI_VENDOR_ID_RICOH            0x1180
 #define PCI_DEVICE_ID_RICOH_RL5C465    0x0465
 #define PCI_DEVICE_ID_RICOH_RL5C466    0x0466
 #define PCI_DEVICE_ID_ARECA_1130       0x1130
 #define PCI_DEVICE_ID_ARECA_1160       0x1160
 #define PCI_DEVICE_ID_ARECA_1170       0x1170
+#define PCI_DEVICE_ID_ARECA_1200       0x1200
+#define PCI_DEVICE_ID_ARECA_1201       0x1201
+#define PCI_DEVICE_ID_ARECA_1202       0x1202
 #define PCI_DEVICE_ID_ARECA_1210       0x1210
 #define PCI_DEVICE_ID_ARECA_1220       0x1220
 #define PCI_DEVICE_ID_ARECA_1230       0x1230
index fe17d7d750c2be05f545d51e5254f928d613ccca..76c1a530edc5784c9b5812d3d869e2ce89a03db0 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/percpu.h>
 #include <linux/cpumask.h>
 #include <linux/seqlock.h>
+#include <linux/lockdep.h>
 
 /**
  * struct rcu_head - callback structure for use with RCU
@@ -133,6 +134,15 @@ static inline void rcu_bh_qsctr_inc(int cpu)
 extern int rcu_pending(int cpu);
 extern int rcu_needs_cpu(int cpu);
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern struct lockdep_map rcu_lock_map;
+# define rcu_read_acquire()    lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_)
+# define rcu_read_release()    lock_release(&rcu_lock_map, 1, _THIS_IP_)
+#else
+# define rcu_read_acquire()    do { } while (0)
+# define rcu_read_release()    do { } while (0)
+#endif
+
 /**
  * rcu_read_lock - mark the beginning of an RCU read-side critical section.
  *
@@ -166,6 +176,7 @@ extern int rcu_needs_cpu(int cpu);
        do { \
                preempt_disable(); \
                __acquire(RCU); \
+               rcu_read_acquire(); \
        } while(0)
 
 /**
@@ -175,6 +186,7 @@ extern int rcu_needs_cpu(int cpu);
  */
 #define rcu_read_unlock() \
        do { \
+               rcu_read_release(); \
                __release(RCU); \
                preempt_enable(); \
        } while(0)
@@ -204,6 +216,7 @@ extern int rcu_needs_cpu(int cpu);
        do { \
                local_bh_disable(); \
                __acquire(RCU_BH); \
+               rcu_read_acquire(); \
        } while(0)
 
 /*
@@ -213,6 +226,7 @@ extern int rcu_needs_cpu(int cpu);
  */
 #define rcu_read_unlock_bh() \
        do { \
+               rcu_read_release(); \
                __release(RCU_BH); \
                local_bh_enable(); \
        } while(0)
index 1e5488ede037799e36d421547fbf0689471fcc16..ff9e9234f8ba64b77f2b7316e34fc69781919e2f 100644 (file)
@@ -120,7 +120,7 @@ struct reiserfs_journal_cnode {
        struct buffer_head *bh; /* real buffer head */
        struct super_block *sb; /* dev of real buffer head */
        __u32 blocknr;          /* block number of real buffer head, == 0 when buffer on disk */
-       long state;
+       unsigned long state;
        struct reiserfs_journal_list *jlist;    /* journal list this cnode lives in */
        struct reiserfs_journal_cnode *next;    /* next in transaction list */
        struct reiserfs_journal_cnode *prev;    /* prev in transaction list */
@@ -181,7 +181,7 @@ struct reiserfs_journal {
        struct block_device *j_dev_bd;
        int j_1st_reserved_block;       /* first block on s_dev of reserved area journal */
 
-       long j_state;
+       unsigned long j_state;
        unsigned long j_trans_id;
        unsigned long j_mount_id;
        unsigned long j_start;  /* start of current waiting commit (index into j_ap_blocks) */
index 833f7dc2b8de7ae5a822e15d1ce6c7d97564c9a4..228e0a8ce2487af241231439d919a7d1cb0b0e80 100644 (file)
@@ -87,6 +87,7 @@ struct sched_param {
 #include <linux/timer.h>
 #include <linux/hrtimer.h>
 #include <linux/task_io_accounting.h>
+#include <linux/kobject.h>
 
 #include <asm/processor.h>
 
@@ -136,6 +137,7 @@ extern unsigned long weighted_cpuload(const int cpu);
 
 struct seq_file;
 struct cfs_rq;
+struct task_group;
 #ifdef CONFIG_SCHED_DEBUG
 extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m);
 extern void proc_sched_set_task(struct task_struct *p);
@@ -174,8 +176,7 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 #define EXIT_ZOMBIE            16
 #define EXIT_DEAD              32
 /* in tsk->state again */
-#define TASK_NONINTERACTIVE    64
-#define TASK_DEAD              128
+#define TASK_DEAD              64
 
 #define __set_task_state(tsk, state_value)             \
        do { (tsk)->state = (state_value); } while (0)
@@ -516,6 +517,8 @@ struct signal_struct {
         * in __exit_signal, except for the group leader.
         */
        cputime_t utime, stime, cutime, cstime;
+       cputime_t gtime;
+       cputime_t cgtime;
        unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
        unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
        unsigned long inblock, oublock, cinblock, coublock;
@@ -596,8 +599,21 @@ struct user_struct {
        /* Hash table maintenance information */
        struct hlist_node uidhash_node;
        uid_t uid;
+
+#ifdef CONFIG_FAIR_USER_SCHED
+       struct task_group *tg;
+       struct kset kset;
+       struct subsys_attribute user_attr;
+       struct work_struct work;
+#endif
 };
 
+#ifdef CONFIG_FAIR_USER_SCHED
+extern int uids_kobject_init(void);
+#else
+static inline int uids_kobject_init(void) { return 0; }
+#endif
+
 extern struct user_struct *find_user(uid_t);
 
 extern struct user_struct root_user;
@@ -609,13 +625,17 @@ struct reclaim_state;
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
 struct sched_info {
        /* cumulative counters */
-       unsigned long pcnt;           /* # of times run on this cpu */
+       unsigned long pcount;         /* # of times run on this cpu */
        unsigned long long cpu_time,  /* time spent on the cpu */
                           run_delay; /* time spent waiting on a runqueue */
 
        /* timestamps */
        unsigned long long last_arrival,/* when we last ran on a cpu */
                           last_queued; /* when we were last queued to run */
+#ifdef CONFIG_SCHEDSTATS
+       /* BKL stats */
+       unsigned long bkl_count;
+#endif
 };
 #endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */
 
@@ -750,7 +770,7 @@ struct sched_domain {
 
 #ifdef CONFIG_SCHEDSTATS
        /* load_balance() stats */
-       unsigned long lb_cnt[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_count[CPU_MAX_IDLE_TYPES];
        unsigned long lb_failed[CPU_MAX_IDLE_TYPES];
        unsigned long lb_balanced[CPU_MAX_IDLE_TYPES];
        unsigned long lb_imbalance[CPU_MAX_IDLE_TYPES];
@@ -760,17 +780,17 @@ struct sched_domain {
        unsigned long lb_nobusyq[CPU_MAX_IDLE_TYPES];
 
        /* Active load balancing */
-       unsigned long alb_cnt;
+       unsigned long alb_count;
        unsigned long alb_failed;
        unsigned long alb_pushed;
 
        /* SD_BALANCE_EXEC stats */
-       unsigned long sbe_cnt;
+       unsigned long sbe_count;
        unsigned long sbe_balanced;
        unsigned long sbe_pushed;
 
        /* SD_BALANCE_FORK stats */
-       unsigned long sbf_cnt;
+       unsigned long sbf_count;
        unsigned long sbf_balanced;
        unsigned long sbf_pushed;
 
@@ -854,11 +874,11 @@ struct rq;
 struct sched_domain;
 
 struct sched_class {
-       struct sched_class *next;
+       const struct sched_class *next;
 
        void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
        void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
-       void (*yield_task) (struct rq *rq, struct task_struct *p);
+       void (*yield_task) (struct rq *rq);
 
        void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);
 
@@ -888,31 +908,22 @@ struct load_weight {
  *     4 se->block_start
  *     4 se->run_node
  *     4 se->sleep_start
- *     4 se->sleep_start_fair
  *     6 se->load.weight
- *     7 se->delta_fair
- *    15 se->wait_runtime
  */
 struct sched_entity {
-       long                    wait_runtime;
-       unsigned long           delta_fair_run;
-       unsigned long           delta_fair_sleep;
-       unsigned long           delta_exec;
-       s64                     fair_key;
        struct load_weight      load;           /* for load-balancing */
        struct rb_node          run_node;
        unsigned int            on_rq;
+       int                     peer_preempt;
 
        u64                     exec_start;
        u64                     sum_exec_runtime;
+       u64                     vruntime;
        u64                     prev_sum_exec_runtime;
-       u64                     wait_start_fair;
-       u64                     sleep_start_fair;
 
 #ifdef CONFIG_SCHEDSTATS
        u64                     wait_start;
        u64                     wait_max;
-       s64                     sum_wait_runtime;
 
        u64                     sleep_start;
        u64                     sleep_max;
@@ -921,9 +932,25 @@ struct sched_entity {
        u64                     block_start;
        u64                     block_max;
        u64                     exec_max;
-
-       unsigned long           wait_runtime_overruns;
-       unsigned long           wait_runtime_underruns;
+       u64                     slice_max;
+
+       u64                     nr_migrations;
+       u64                     nr_migrations_cold;
+       u64                     nr_failed_migrations_affine;
+       u64                     nr_failed_migrations_running;
+       u64                     nr_failed_migrations_hot;
+       u64                     nr_forced_migrations;
+       u64                     nr_forced2_migrations;
+
+       u64                     nr_wakeups;
+       u64                     nr_wakeups_sync;
+       u64                     nr_wakeups_migrate;
+       u64                     nr_wakeups_local;
+       u64                     nr_wakeups_remote;
+       u64                     nr_wakeups_affine;
+       u64                     nr_wakeups_affine_attempts;
+       u64                     nr_wakeups_passive;
+       u64                     nr_wakeups_idle;
 #endif
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -952,7 +979,7 @@ struct task_struct {
 
        int prio, static_prio, normal_prio;
        struct list_head run_list;
-       struct sched_class *sched_class;
+       const struct sched_class *sched_class;
        struct sched_entity se;
 
 #ifdef CONFIG_PREEMPT_NOTIFIERS
@@ -1023,6 +1050,7 @@ struct task_struct {
 
        unsigned int rt_priority;
        cputime_t utime, stime;
+       cputime_t gtime;
        unsigned long nvcsw, nivcsw; /* context switch counts */
        struct timespec start_time;             /* monotonic time */
        struct timespec real_start_time;        /* boot based time */
@@ -1314,6 +1342,7 @@ static inline void put_task_struct(struct task_struct *t)
 #define PF_STARTING    0x00000002      /* being created */
 #define PF_EXITING     0x00000004      /* getting shut down */
 #define PF_EXITPIDONE  0x00000008      /* pi exit done on shut down */
+#define PF_VCPU                0x00000010      /* I'm a virtual CPU */
 #define PF_FORKNOEXEC  0x00000040      /* forked but didn't exec */
 #define PF_SUPERPRIV   0x00000100      /* used super-user privileges */
 #define PF_DUMPCORE    0x00000200      /* dumped core */
@@ -1401,15 +1430,17 @@ static inline void idle_task_exit(void) {}
 
 extern void sched_idle_next(void);
 
+#ifdef CONFIG_SCHED_DEBUG
 extern unsigned int sysctl_sched_latency;
-extern unsigned int sysctl_sched_min_granularity;
+extern unsigned int sysctl_sched_nr_latency;
 extern unsigned int sysctl_sched_wakeup_granularity;
 extern unsigned int sysctl_sched_batch_wakeup_granularity;
-extern unsigned int sysctl_sched_stat_granularity;
-extern unsigned int sysctl_sched_runtime_limit;
-extern unsigned int sysctl_sched_compat_yield;
 extern unsigned int sysctl_sched_child_runs_first;
 extern unsigned int sysctl_sched_features;
+extern unsigned int sysctl_sched_migration_cost;
+#endif
+
+extern unsigned int sysctl_sched_compat_yield;
 
 #ifdef CONFIG_RT_MUTEXES
 extern int rt_mutex_getprio(struct task_struct *p);
@@ -1843,6 +1874,18 @@ extern int sched_mc_power_savings, sched_smt_power_savings;
 
 extern void normalize_rt_tasks(void);
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+extern struct task_group init_task_group;
+
+extern struct task_group *sched_create_group(void);
+extern void sched_destroy_group(struct task_group *tg);
+extern void sched_move_task(struct task_struct *tsk);
+extern int sched_group_set_shares(struct task_group *tg, unsigned long shares);
+extern unsigned long sched_group_shares(struct task_group *tg);
+
+#endif
+
 #ifdef CONFIG_TASK_XACCT
 static inline void add_rchar(struct task_struct *tsk, ssize_t amt)
 {
index d2b058130eb123586c95d843521f4cbbfdab6629..ece4e553e9ac26d61ce77eb31bc4e4a1b6874be3 100644 (file)
@@ -1,7 +1,7 @@
 u32 scx200_gpio_configure(unsigned index, u32 set, u32 clear);
 
 extern unsigned scx200_gpio_base;
-extern long scx200_gpio_shadow[2];
+extern unsigned long scx200_gpio_shadow[2];
 extern struct nsc_gpio_ops scx200_gpio_ops;
 
 #define scx200_gpio_present() (scx200_gpio_base!=0)
@@ -9,7 +9,7 @@ extern struct nsc_gpio_ops scx200_gpio_ops;
 /* Definitions to make sure I do the same thing in all functions */
 #define __SCx200_GPIO_BANK unsigned bank = index>>5
 #define __SCx200_GPIO_IOADDR unsigned short ioaddr = scx200_gpio_base+0x10*bank
-#define __SCx200_GPIO_SHADOW long *shadow = scx200_gpio_shadow+bank
+#define __SCx200_GPIO_SHADOW unsigned long *shadow = scx200_gpio_shadow+bank
 #define __SCx200_GPIO_INDEX index &= 31
 
 #define __SCx200_GPIO_OUT __asm__ __volatile__("outsl":"=mS" (shadow):"d" (ioaddr), "0" (shadow))
@@ -42,7 +42,7 @@ static inline void scx200_gpio_set_high(unsigned index) {
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
        __SCx200_GPIO_INDEX;
-       set_bit(index, shadow);
+       set_bit(index, shadow); /* __set_bit()? */
        __SCx200_GPIO_OUT;
 }
 
@@ -53,7 +53,7 @@ static inline void scx200_gpio_set_low(unsigned index) {
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
        __SCx200_GPIO_INDEX;
-       clear_bit(index, shadow);
+       clear_bit(index, shadow); /* __clear_bit()? */
        __SCx200_GPIO_OUT;
 }
 
index a656cecd373c812eb7057d844f74dd2c0ce189df..8101e8b0d7ba342ddffe0549e17c869506f63e35 100644 (file)
@@ -1781,6 +1781,11 @@ static inline int skb_is_gso(const struct sk_buff *skb)
        return skb_shinfo(skb)->gso_size;
 }
 
+static inline int skb_is_gso_v6(const struct sk_buff *skb)
+{
+       return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
+}
+
 static inline void skb_forward_csum(struct sk_buff *skb)
 {
        /* Unfortunately we don't support this one.  Any brave souls? */
index 4a0a329beafb5c39038473498aa60465fde05087..94b4a10b912f94661e3dba9c568d1ecf183abf40 100644 (file)
@@ -75,7 +75,7 @@ struct stlport {
        int                     ioaddr;
        int                     uartaddr;
        unsigned int            pagenr;
-       long                    istate;
+       unsigned long           istate;
        int                     flags;
        int                     baud_base;
        int                     custom_divisor;
index 3699dff7db8fd3c129488745f9e851d7abbf56e1..bd7a6b0a87af654e080093037915238b6fc4fd74 100644 (file)
@@ -136,16 +136,6 @@ sunrpc_cache_update(struct cache_detail *detail,
                    struct cache_head *new, struct cache_head *old, int hash);
 
 
-#define cache_for_each(pos, detail, index, member)                                             \
-       for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ;                \
-            ({if (index==0)read_unlock(&(detail)->hash_lock); index--;});                      \
-               )                                                                               \
-               for (pos = container_of((detail)->hash_table[index], typeof(*pos), member);     \
-                    &pos->member;                                                              \
-                    pos = container_of(pos->member.next, typeof(*pos), member))
-
-            
-
 extern void cache_clean_deferred(void *owner);
 
 static inline struct cache_head  *cache_get(struct cache_head *h)
index c0d9d14983b3f191679aed01ca729838aafa7a29..d9d5c5ad826c759c4c0853b5a53e1b8bbcb46366 100644 (file)
@@ -117,7 +117,7 @@ struct rpc_create_args {
 
 struct rpc_clnt *rpc_create(struct rpc_create_args *args);
 struct rpc_clnt        *rpc_bind_new_program(struct rpc_clnt *,
-                               struct rpc_program *, int);
+                               struct rpc_program *, u32);
 struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 void           rpc_shutdown_client(struct rpc_clnt *);
 void           rpc_release_client(struct rpc_clnt *);
index 3912cf16361ee98aa9334399fe6d8289e3270364..3347c72b848abaadd0f12fd0e650dbf8323729ce 100644 (file)
@@ -88,6 +88,11 @@ enum {
        CTL_SLOTTABLE_TCP,
        CTL_MIN_RESVPORT,
        CTL_MAX_RESVPORT,
+       CTL_SLOTTABLE_RDMA,
+       CTL_RDMA_MAXINLINEREAD,
+       CTL_RDMA_MAXINLINEWRITE,
+       CTL_RDMA_WRITEPADDING,
+       CTL_RDMA_MEMREG,
 };
 
 #endif /* _LINUX_SUNRPC_DEBUG_H_ */
index 784d4c3ef651126829b76083e898590d2e00314c..c4beb5775111c03a2c0f49fccb908d546ad8fb8f 100644 (file)
@@ -138,6 +138,19 @@ typedef __be32     rpc_fraghdr;
 #define RPC_MAX_HEADER_WITH_AUTH \
        (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
 
+/*
+ * RFC1833/RFC3530 rpcbind (v3+) well-known netid's.
+ */
+#define RPCBIND_NETID_UDP      "udp"
+#define RPCBIND_NETID_TCP      "tcp"
+#define RPCBIND_NETID_UDP6     "udp6"
+#define RPCBIND_NETID_TCP6     "tcp6"
+
+/*
+ * Note that RFC 1833 does not put any size restrictions on the
+ * netid string, but all currently defined netid's fit in 4 bytes.
+ */
+#define RPCBIND_MAXNETIDLEN    (4u)
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_MSGPROT_H_ */
diff --git a/include/linux/sunrpc/rpc_rdma.h b/include/linux/sunrpc/rpc_rdma.h
new file mode 100644 (file)
index 0000000..0013a0d
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      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.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_SUNRPC_RPC_RDMA_H
+#define _LINUX_SUNRPC_RPC_RDMA_H
+
+struct rpcrdma_segment {
+       uint32_t rs_handle;     /* Registered memory handle */
+       uint32_t rs_length;     /* Length of the chunk in bytes */
+       uint64_t rs_offset;     /* Chunk virtual address or offset */
+};
+
+/*
+ * read chunk(s), encoded as a linked list.
+ */
+struct rpcrdma_read_chunk {
+       uint32_t rc_discrim;    /* 1 indicates presence */
+       uint32_t rc_position;   /* Position in XDR stream */
+       struct rpcrdma_segment rc_target;
+};
+
+/*
+ * write chunk, and reply chunk.
+ */
+struct rpcrdma_write_chunk {
+       struct rpcrdma_segment wc_target;
+};
+
+/*
+ * write chunk(s), encoded as a counted array.
+ */
+struct rpcrdma_write_array {
+       uint32_t wc_discrim;    /* 1 indicates presence */
+       uint32_t wc_nchunks;    /* Array count */
+       struct rpcrdma_write_chunk wc_array[0];
+};
+
+struct rpcrdma_msg {
+       uint32_t rm_xid;        /* Mirrors the RPC header xid */
+       uint32_t rm_vers;       /* Version of this protocol */
+       uint32_t rm_credit;     /* Buffers requested/granted */
+       uint32_t rm_type;       /* Type of message (enum rpcrdma_proc) */
+       union {
+
+               struct {                        /* no chunks */
+                       uint32_t rm_empty[3];   /* 3 empty chunk lists */
+               } rm_nochunks;
+
+               struct {                        /* no chunks and padded */
+                       uint32_t rm_align;      /* Padding alignment */
+                       uint32_t rm_thresh;     /* Padding threshold */
+                       uint32_t rm_pempty[3];  /* 3 empty chunk lists */
+               } rm_padded;
+
+               uint32_t rm_chunks[0];  /* read, write and reply chunks */
+
+       } rm_body;
+};
+
+#define RPCRDMA_HDRLEN_MIN     28
+
+enum rpcrdma_errcode {
+       ERR_VERS = 1,
+       ERR_CHUNK = 2
+};
+
+struct rpcrdma_err_vers {
+       uint32_t rdma_vers_low; /* Version range supported by peer */
+       uint32_t rdma_vers_high;
+};
+
+enum rpcrdma_proc {
+       RDMA_MSG = 0,           /* An RPC call or reply msg */
+       RDMA_NOMSG = 1,         /* An RPC call or reply msg - separate body */
+       RDMA_MSGP = 2,          /* An RPC call or reply msg with padding */
+       RDMA_DONE = 3,          /* Client signals reply completion */
+       RDMA_ERROR = 4          /* An RPC RDMA encoding error */
+};
+
+#endif                         /* _LINUX_SUNRPC_RPC_RDMA_H */
index c6b53d181bfa9a4b23e091ed5fc0e36317d38629..0751c9464d0f84ff7291c7ca332c65dbde383cee 100644 (file)
@@ -70,7 +70,10 @@ struct xdr_buf {
 
        struct page **  pages;          /* Array of contiguous pages */
        unsigned int    page_base,      /* Start of page data */
-                       page_len;       /* Length of page data */
+                       page_len,       /* Length of page data */
+                       flags;          /* Flags for data disposition */
+#define XDRBUF_READ            0x01            /* target of file read */
+#define XDRBUF_WRITE           0x02            /* source of file write */
 
        unsigned int    buflen,         /* Total length of storage buffer */
                        len;            /* Length of XDR encoded message */
index d11cedd14f0f59a9e267b97beddbde1ae13aca74..30b17b3bc1a9b9eea991874d83a9a8f24799e4b8 100644 (file)
 
 #ifdef __KERNEL__
 
-extern unsigned int xprt_udp_slot_table_entries;
-extern unsigned int xprt_tcp_slot_table_entries;
-
 #define RPC_MIN_SLOT_TABLE     (2U)
 #define RPC_DEF_SLOT_TABLE     (16U)
 #define RPC_MAX_SLOT_TABLE     (128U)
 
-/*
- * Parameters for choosing a free port
- */
-extern unsigned int xprt_min_resvport;
-extern unsigned int xprt_max_resvport;
-
-#define RPC_MIN_RESVPORT       (1U)
-#define RPC_MAX_RESVPORT       (65535U)
-#define RPC_DEF_MIN_RESVPORT   (665U)
-#define RPC_DEF_MAX_RESVPORT   (1023U)
-
 /*
  * This describes a timeout strategy
  */
@@ -53,6 +39,10 @@ enum rpc_display_format_t {
        RPC_DISPLAY_PORT,
        RPC_DISPLAY_PROTO,
        RPC_DISPLAY_ALL,
+       RPC_DISPLAY_HEX_ADDR,
+       RPC_DISPLAY_HEX_PORT,
+       RPC_DISPLAY_UNIVERSAL_ADDR,
+       RPC_DISPLAY_NETID,
        RPC_DISPLAY_MAX,
 };
 
@@ -196,14 +186,22 @@ struct rpc_xprt {
        char *                  address_strings[RPC_DISPLAY_MAX];
 };
 
-struct rpc_xprtsock_create {
-       int                     proto;          /* IPPROTO_UDP or IPPROTO_TCP */
+struct xprt_create {
+       int                     ident;          /* XPRT_TRANSPORT identifier */
        struct sockaddr *       srcaddr;        /* optional local address */
        struct sockaddr *       dstaddr;        /* remote peer address */
        size_t                  addrlen;
        struct rpc_timeout *    timeout;        /* optional timeout parameters */
 };
 
+struct xprt_class {
+       struct list_head        list;
+       int                     ident;          /* XPRT_TRANSPORT identifier */
+       struct rpc_xprt *       (*setup)(struct xprt_create *);
+       struct module           *owner;
+       char                    name[32];
+};
+
 /*
  * Transport operations used by ULPs
  */
@@ -212,7 +210,7 @@ void                        xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long
 /*
  * Generic internal transport functions
  */
-struct rpc_xprt *      xprt_create_transport(struct rpc_xprtsock_create *args);
+struct rpc_xprt                *xprt_create_transport(struct xprt_create *args);
 void                   xprt_connect(struct rpc_task *task);
 void                   xprt_reserve(struct rpc_task *task);
 int                    xprt_reserve_xprt(struct rpc_task *task);
@@ -235,6 +233,8 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *
 /*
  * Transport switch helper functions
  */
+int                    xprt_register_transport(struct xprt_class *type);
+int                    xprt_unregister_transport(struct xprt_class *type);
 void                   xprt_set_retrans_timeout_def(struct rpc_task *task);
 void                   xprt_set_retrans_timeout_rtt(struct rpc_task *task);
 void                   xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
@@ -247,14 +247,6 @@ void                       xprt_complete_rqst(struct rpc_task *task, int copied);
 void                   xprt_release_rqst_cong(struct rpc_task *task);
 void                   xprt_disconnect(struct rpc_xprt *xprt);
 
-/*
- * Socket transport setup operations
- */
-struct rpc_xprt *      xs_setup_udp(struct rpc_xprtsock_create *args);
-struct rpc_xprt *      xs_setup_tcp(struct rpc_xprtsock_create *args);
-int                    init_socket_xprt(void);
-void                   cleanup_socket_xprt(void);
-
 /*
  * Reserved bit positions in xprt->state
  */
diff --git a/include/linux/sunrpc/xprtrdma.h b/include/linux/sunrpc/xprtrdma.h
new file mode 100644 (file)
index 0000000..4de56b1
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      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.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_SUNRPC_XPRTRDMA_H
+#define _LINUX_SUNRPC_XPRTRDMA_H
+
+/*
+ * RPC transport identifier for RDMA
+ */
+#define XPRT_TRANSPORT_RDMA    256
+
+/*
+ * rpcbind (v3+) RDMA netid.
+ */
+#define RPCBIND_NETID_RDMA     "rdma"
+
+/*
+ * Constants. Max RPC/NFS header is big enough to account for
+ * additional marshaling buffers passed down by Linux client.
+ *
+ * RDMA header is currently fixed max size, and is big enough for a
+ * fully-chunked NFS message (read chunks are the largest). Note only
+ * a single chunk type per message is supported currently.
+ */
+#define RPCRDMA_MIN_SLOT_TABLE (2U)
+#define RPCRDMA_DEF_SLOT_TABLE (32U)
+#define RPCRDMA_MAX_SLOT_TABLE (256U)
+
+#define RPCRDMA_DEF_INLINE  (1024)     /* default inline max */
+
+#define RPCRDMA_INLINE_PAD_THRESH  (512)/* payload threshold to pad (bytes) */
+
+#define RDMA_RESOLVE_TIMEOUT   (5*HZ)  /* TBD 5 seconds */
+#define RDMA_CONNECT_RETRY_MAX (2)     /* retries if no listener backlog */
+
+/* memory registration strategies */
+#define RPCRDMA_PERSISTENT_REGISTRATION (1)
+
+enum rpcrdma_memreg {
+       RPCRDMA_BOUNCEBUFFERS = 0,
+       RPCRDMA_REGISTER,
+       RPCRDMA_MEMWINDOWS,
+       RPCRDMA_MEMWINDOWS_ASYNC,
+       RPCRDMA_MTHCAFMR,
+       RPCRDMA_ALLPHYSICAL,
+       RPCRDMA_LAST
+};
+
+#endif /* _LINUX_SUNRPC_XPRTRDMA_H */
diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h
new file mode 100644 (file)
index 0000000..2c6c2c2
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  linux/include/linux/sunrpc/xprtsock.h
+ *
+ *  Declarations for the RPC transport socket provider.
+ */
+
+#ifndef _LINUX_SUNRPC_XPRTSOCK_H
+#define _LINUX_SUNRPC_XPRTSOCK_H
+
+#ifdef __KERNEL__
+
+/*
+ * Socket transport setup operations
+ */
+struct rpc_xprt *xs_setup_udp(struct xprt_create *args);
+struct rpc_xprt *xs_setup_tcp(struct xprt_create *args);
+
+int            init_socket_xprt(void);
+void           cleanup_socket_xprt(void);
+
+/*
+ * RPC transport identifiers for UDP, TCP
+ *
+ * To preserve compatibility with the historical use of raw IP protocol
+ * id's for transport selection, these are specified with the previous
+ * values. No such restriction exists for new transports, except that
+ * they may not collide with these values (17 and 6, respectively).
+ */
+#define XPRT_TRANSPORT_UDP     IPPROTO_UDP
+#define XPRT_TRANSPORT_TCP     IPPROTO_TCP
+
+/*
+ * RPC slot table sizes for UDP, TCP transports
+ */
+extern unsigned int xprt_udp_slot_table_entries;
+extern unsigned int xprt_tcp_slot_table_entries;
+
+/*
+ * Parameters for choosing a free port
+ */
+extern unsigned int xprt_min_resvport;
+extern unsigned int xprt_max_resvport;
+
+#define RPC_MIN_RESVPORT       (1U)
+#define RPC_MAX_RESVPORT       (65535U)
+#define RPC_DEF_MIN_RESVPORT   (665U)
+#define RPC_DEF_MAX_RESVPORT   (1023U)
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SUNRPC_XPRTSOCK_H */
index 525d437b12538ba780f5639a1fa73b3628ea40da..47729f18bfdf35b7943bd910401cd72a5350bae2 100644 (file)
        .imbalance_pct          = 125,                  \
        .cache_nice_tries       = 1,                    \
        .busy_idx               = 2,                    \
-       .idle_idx               = 0,                    \
-       .newidle_idx            = 0,                    \
+       .idle_idx               = 1,                    \
+       .newidle_idx            = 2,                    \
        .wake_idx               = 1,                    \
        .forkexec_idx           = 1,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_BALANCE_EXEC       \
                                | SD_WAKE_AFFINE        \
-                               | SD_WAKE_IDLE          \
                                | BALANCE_FOR_PKG_POWER,\
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
index c7c3337c3a88c62991194b2f6e87bbb81935d4be..d1321a81c9c444342981ef0aedd8e7fc257b6f00 100644 (file)
@@ -62,8 +62,6 @@ struct writeback_control {
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
        unsigned for_writepages:1;      /* This is a writepages() call */
        unsigned range_cyclic:1;        /* range_start is cyclic */
-
-       void *fs_private;               /* For use by ->writepages() */
 };
 
 /*
index 9fa09fb800a11d07c3913d319ac7a176a7ac8c28..0fa5d591255561b00e5cea79586c4eccdada9697 100644 (file)
@@ -133,7 +133,7 @@ struct videobuf_qtype_ops {
                                 enum v4l2_memory memory);
        int (*sync)             (struct videobuf_queue* q,
                                 struct videobuf_buffer *buf);
-       int (*copy_to_user)     (struct videobuf_queue *q,
+       int (*video_copy_to_user)(struct videobuf_queue *q,
                                 char __user *data,
                                 size_t count,
                                 int nonblocking);
index d143171896ae89d4d9fdff31744ad06e5698c663..ba615e4c1d7c324ee93e59c78c17f027c3fb3dd4 100644 (file)
@@ -59,7 +59,7 @@ extern void srp_target_free(struct srp_target *);
 extern struct iu_entry *srp_iu_get(struct srp_target *);
 extern void srp_iu_put(struct iu_entry *);
 
-extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64);
+extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64, u64);
 extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
                             srp_rdma_t, int, int);
 
index 53e170586c26c190a304c9a7c5f8100de1fd866a..65ab5145a09befcc23a78de1090676d7f8fdd42e 100644 (file)
@@ -33,20 +33,17 @@ struct scsi_cmnd {
        struct list_head list;  /* scsi_cmnd participates in queue lists */
        struct list_head eh_entry; /* entry for the host eh_cmd_q */
        int eh_eflags;          /* Used by error handlr */
-       void (*done) (struct scsi_cmnd *);      /* Mid-level done function */
 
        /*
         * A SCSI Command is assigned a nonzero serial_number before passed
         * to the driver's queue command function.  The serial_number is
         * cleared when scsi_done is entered indicating that the command
-        * has been completed.  It currently doesn't have much use other
-        * than printk's.  Some lldd's use this number for other purposes.
-        * It's almost certain that such usages are either incorrect or
-        * meaningless.  Please kill all usages other than printk's.  Also,
-        * as this number is always identical to ->pid, please convert
-        * printk's to use ->pid, so that we can kill this field.
+        * has been completed.  It is a bug for LLDDs to use this number
+        * for purposes other than printk (and even that is only useful
+        * for debugging).
         */
        unsigned long serial_number;
+
        /*
         * This is set to jiffies as it was when the command was first
         * allocated.  It is used to time how long the command has
@@ -116,7 +113,6 @@ struct scsi_cmnd {
        int result;             /* Status code from lower level driver */
 
        unsigned char tag;      /* SCSI-II queued command tag */
-       unsigned long pid;      /* Process ID, starts at 0. Unique per host. */
 };
 
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
@@ -124,7 +120,6 @@ extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
 extern void scsi_put_command(struct scsi_cmnd *);
 extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
                               struct device *);
-extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
 extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
 
index 5a43a4cd96c6f6ea9f11d9818fb4e4c5780046a5..e89844cc2cd359bf281574f45f942826b1af9056 100644 (file)
@@ -9,6 +9,8 @@ extern void __scsi_print_command(unsigned char *);
 extern void scsi_show_extd_sense(unsigned char, unsigned char);
 extern void scsi_show_sense_hdr(struct scsi_sense_hdr *);
 extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
+extern void scsi_cmd_print_sense_hdr(struct scsi_cmnd *, const char *,
+                                    struct scsi_sense_hdr *);
 extern void scsi_print_sense(char *, struct scsi_cmnd *);
 extern void __scsi_print_sense(const char *name,
                               const unsigned char *sense_buffer,
index 3465f31a21c4c5bb83980db6dcf6ab721ff0678e..1f5ca7f621165797ff559203e99b5a1deebe1624 100644 (file)
@@ -5,14 +5,17 @@
 
 struct module;
 struct scsi_cmnd;
+struct scsi_device;
+struct request;
+struct request_queue;
 
 
 struct scsi_driver {
        struct module           *owner;
        struct device_driver    gendrv;
 
-       int (*init_command)(struct scsi_cmnd *);
        void (*rescan)(struct device *);
+       int (*done)(struct scsi_cmnd *);
 };
 #define to_scsi_driver(drv) \
        container_of((drv), struct scsi_driver, gendrv)
@@ -25,4 +28,9 @@ extern int scsi_register_interface(struct class_interface *);
 #define scsi_unregister_interface(intf) \
        class_interface_unregister(intf)
 
+int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req);
+int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req);
+int scsi_prep_state_check(struct scsi_device *sdev, struct request *req);
+int scsi_prep_return(struct request_queue *q, struct request *req, int ret);
+
 #endif /* _SCSI_SCSI_DRIVER_H */
index c5c0f6762a013b0ebcd186e668e4a6f61a9f18cd..44224ba4dd9065cb89d93a10aa1c7daf95b2f6bd 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _SCSI_SCSI_EH_H
 #define _SCSI_SCSI_EH_H
 
-struct scsi_cmnd;
+#include <scsi/scsi_cmnd.h>
 struct scsi_device;
 struct Scsi_Host;
 
@@ -65,4 +65,25 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
 
 extern int scsi_reset_provider(struct scsi_device *, int);
 
+struct scsi_eh_save {
+       int result;
+       enum dma_data_direction data_direction;
+       unsigned char cmd_len;
+       unsigned char cmnd[MAX_COMMAND_SIZE];
+
+       void *buffer;
+       unsigned bufflen;
+       unsigned short use_sg;
+       int resid;
+
+       struct scatterlist sense_sgl;
+};
+
+extern void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
+               struct scsi_eh_save *ses, unsigned char *cmnd,
+               int cmnd_size, unsigned sense_bytes);
+
+extern void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
+               struct scsi_eh_save *ses);
+
 #endif /* _SCSI_SCSI_EH_H */
index 3b8a6a85c2f818e64435968136472fa7d2317bc1..7d210cd6c38d03a476b4f06fe563126d69db42c2 100644 (file)
@@ -32,6 +32,9 @@ struct blk_queue_tags;
 #define SG_NONE 0
 #define SG_ALL 0xff
 
+#define MODE_UNKNOWN 0x00
+#define MODE_INITIATOR 0x01
+#define MODE_TARGET 0x02
 
 #define DISABLE_CLUSTERING 0
 #define ENABLE_CLUSTERING 1
@@ -145,9 +148,6 @@ struct scsi_host_template {
        int (* transfer_response)(struct scsi_cmnd *,
                                  void (*done)(struct scsi_cmnd *));
 
-       /* Used as callback for the completion of task management request. */
-       int (* tsk_mgmt_response)(u64 mid, int result);
-
        /*
         * This is an error handling strategy routine.  You don't need to
         * define one of these if you don't want to - there is a default
@@ -407,6 +407,11 @@ struct scsi_host_template {
         */
        unsigned char present;
 
+       /*
+        * This specifies the mode that a LLD supports.
+        */
+       unsigned supported_mode:2;
+
        /*
         * true if this host adapter uses unchecked DMA onto an ISA bus.
         */
@@ -575,8 +580,9 @@ struct Scsi_Host {
         * Used to assign serial numbers to the cmds.
         * Protected by the host lock.
         */
-       unsigned long cmd_serial_number, cmd_pid; 
+       unsigned long cmd_serial_number;
        
+       unsigned active_mode:2;
        unsigned unchecked_isa_dma:1;
        unsigned use_clustering:1;
        unsigned use_blk_tcq:1;
index 4f4427937af277764cc74d119dc99f82f43cfa18..d0fefb96158f3dd52a007035113e8b80dc1bcf58 100644 (file)
@@ -11,9 +11,11 @@ struct scsi_lun;
 extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *);
 extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
 extern void scsi_tgt_free_queue(struct Scsi_Host *);
-extern int scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, u64);
-extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, int, u64, struct scsi_lun *,
-                                    void *);
+extern int scsi_tgt_queue_command(struct scsi_cmnd *, u64, struct scsi_lun *, u64);
+extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, u64, int, u64,
+                                    struct scsi_lun *, void *);
 extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
                                               enum dma_data_direction, gfp_t);
 extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *);
+extern int scsi_tgt_it_nexus_create(struct Scsi_Host *, u64, char *);
+extern int scsi_tgt_it_nexus_destroy(struct Scsi_Host *, u64);
index 4cf9dff29a2f69e792ef91395a120448dda8673c..f2ee7c238a4544d112e63c6c57a283dd7474c579 100644 (file)
 #define __SCSI_TARGET_IF_H
 
 /* user -> kernel */
-#define        TGT_UEVENT_CMD_RSP      0x0001
-#define        TGT_UEVENT_TSK_MGMT_RSP 0x0002
+#define        TGT_UEVENT_CMD_RSP              0x0001
+#define        TGT_UEVENT_IT_NEXUS_RSP         0x0002
+#define        TGT_UEVENT_TSK_MGMT_RSP         0x0003
 
 /* kernel -> user */
-#define        TGT_KEVENT_CMD_REQ      0x1001
-#define        TGT_KEVENT_CMD_DONE     0x1002
-#define        TGT_KEVENT_TSK_MGMT_REQ 0x1003
+#define        TGT_KEVENT_CMD_REQ              0x1001
+#define        TGT_KEVENT_CMD_DONE             0x1002
+#define        TGT_KEVENT_IT_NEXUS_REQ         0x1003
+#define        TGT_KEVENT_TSK_MGMT_REQ         0x1004
 
 struct tgt_event_hdr {
        uint16_t version;
@@ -46,6 +48,7 @@ struct tgt_event {
                struct {
                        int host_no;
                        int result;
+                       aligned_u64 itn_id;
                        aligned_u64 tag;
                        aligned_u64 uaddr;
                        aligned_u64 sense_uaddr;
@@ -55,15 +58,22 @@ struct tgt_event {
                } cmd_rsp;
                struct {
                        int host_no;
-                       aligned_u64 mid;
                        int result;
+                       aligned_u64 itn_id;
+                       aligned_u64 mid;
                } tsk_mgmt_rsp;
-
+               struct {
+                       __s32 host_no;
+                       __s32 result;
+                       aligned_u64 itn_id;
+                       __u32 function;
+               } it_nexus_rsp;
 
                /* kernel -> user */
                struct {
                        int host_no;
                        uint32_t data_len;
+                       aligned_u64 itn_id;
                        uint8_t scb[16];
                        uint8_t lun[8];
                        int attribute;
@@ -71,16 +81,25 @@ struct tgt_event {
                } cmd_req;
                struct {
                        int host_no;
-                       aligned_u64 tag;
                        int result;
+                       aligned_u64 itn_id;
+                       aligned_u64 tag;
                } cmd_done;
                struct {
                        int host_no;
                        int function;
+                       aligned_u64 itn_id;
                        aligned_u64 tag;
                        uint8_t lun[8];
                        aligned_u64 mid;
                } tsk_mgmt_req;
+               struct {
+                       __s32 host_no;
+                       __u32 function;
+                       aligned_u64 itn_id;
+                       __u32 max_cmds;
+                       __u8 initiator_id[16];
+               } it_nexus_req;
        } p;
 } __attribute__ ((aligned (sizeof(uint64_t))));
 
index 3c18baa65a729cd1578ab45b281ed1d5ba2d01dd..0dfef752f0e27c7c9009a2dbe378522322d453a4 100644 (file)
@@ -65,6 +65,18 @@ struct scsi_transport_template {
         * EH_NOT_HANDLED       Begin normal error recovery
         */
        enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+
+       /*
+        * Used as callback for the completion of i_t_nexus request
+        * for target drivers.
+        */
+       int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+
+       /*
+        * Used as callback for the completion of task management
+        * request for target drivers.
+        */
+       int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
 };
 
 #define transport_class_to_shost(tc) \
index a0d80bcaa93d489c909a4f67f3142dbdbd040ef4..e466d886e19283621c2e6af4f6087ce7eafa2d1e 100644 (file)
@@ -589,6 +589,10 @@ struct fc_function_template {
        int     (*vport_disable)(struct fc_vport *, bool);
        int     (*vport_delete)(struct fc_vport *);
 
+       /* target-mode drivers' functions */
+       int     (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
+       int     (* it_nexus_response)(struct Scsi_Host *, u64, int);
+
        /* allocation lengths for host-specific data */
        u32                             dd_fcrport_size;
        u32                             dd_fcvport_size;
@@ -632,6 +636,8 @@ struct fc_function_template {
        unsigned long   show_host_fabric_name:1;
        unsigned long   show_host_symbolic_name:1;
        unsigned long   show_host_system_hostname:1;
+
+       unsigned long   disable_target_scan:1;
 };
 
 
index 706c0cd36c14ffcfc69339ac8dc57544470d5928..7ff6199cbd55bef57c55b58b8c5a58f20a5d115a 100644 (file)
@@ -24,6 +24,8 @@
 #define SCSI_TRANSPORT_ISCSI_H
 
 #include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
 #include <scsi/iscsi_if.h>
 
 struct scsi_transport_template;
diff --git a/include/scsi/scsi_transport_srp.h b/include/scsi/scsi_transport_srp.h
new file mode 100644 (file)
index 0000000..9c60ca1
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SCSI_TRANSPORT_SRP_H
+#define SCSI_TRANSPORT_SRP_H
+
+#include <linux/transport_class.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+
+#define SRP_RPORT_ROLE_INITIATOR 0
+#define SRP_RPORT_ROLE_TARGET 1
+
+struct srp_rport_identifiers {
+       u8 port_id[16];
+       u8 roles;
+};
+
+struct srp_rport {
+       struct device dev;
+
+       u8 port_id[16];
+       u8 roles;
+};
+
+struct srp_function_template {
+       /* for target drivers */
+       int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
+       int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+};
+
+extern struct scsi_transport_template *
+srp_attach_transport(struct srp_function_template *);
+extern void srp_release_transport(struct scsi_transport_template *);
+
+extern struct srp_rport *srp_rport_add(struct Scsi_Host *,
+                                      struct srp_rport_identifiers *);
+extern void srp_rport_del(struct srp_rport *);
+
+extern void srp_remove_host(struct Scsi_Host *);
+
+#endif
index ce02ad1f518569cedefdb3f76fff5d8b055c0dba..f7513313ef0d5d5bdd85194dfb6771ac294cc22d 100644 (file)
@@ -47,20 +47,6 @@ struct scsi_disk {
 };
 #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
 
-static int  sd_revalidate_disk(struct gendisk *disk);
-static void sd_rw_intr(struct scsi_cmnd * SCpnt);
-static int  sd_probe(struct device *);
-static int  sd_remove(struct device *);
-static void sd_shutdown(struct device *dev);
-static int sd_suspend(struct device *dev, pm_message_t state);
-static int sd_resume(struct device *dev);
-static void sd_rescan(struct device *);
-static int  sd_init_command(struct scsi_cmnd *);
-static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
-static void scsi_disk_release(struct class_device *cdev);
-static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
-static void sd_print_result(struct scsi_disk *, int);
-
 #define sd_printk(prefix, sdsk, fmt, a...)                             \
         (sdsk)->disk ?                                                 \
        sdev_printk(prefix, (sdsk)->device, "[%s] " fmt,                \
index d54d0cadcc064c284c10cce88beaf9c55ccf0cdd..54f31a191b8813a1bac92190cd237023c30a684d 100644 (file)
@@ -281,6 +281,27 @@ config CPUSETS
 
          Say N if unsure.
 
+config FAIR_GROUP_SCHED
+       bool "Fair group CPU scheduler"
+       default y
+       depends on EXPERIMENTAL
+       help
+         This feature lets CPU scheduler recognize task groups and control CPU
+         bandwidth allocation to such task groups.
+
+choice
+       depends on FAIR_GROUP_SCHED
+       prompt "Basis for grouping tasks"
+       default FAIR_USER_SCHED
+
+config FAIR_USER_SCHED
+       bool "user id"
+       help
+         This option will choose userid as the basis for grouping
+         tasks, thus providing equal CPU bandwidth to each user.
+
+endchoice
+
 config SYSFS_DEPRECATED
        bool "Create deprecated sysfs files"
        default y
index 04f3ffb8d9d4adfd03b314db621f43c8c3ab11fe..0ae703c157ba3033a4e34c0ed012ca8812ba2e54 100644 (file)
@@ -1525,6 +1525,7 @@ add_names:
                        context->names[idx].ino = (unsigned long)-1;
        }
 }
+EXPORT_SYMBOL_GPL(__audit_inode_child);
 
 /**
  * auditsc_get_stamp - get local copies of audit_context values
index 81e697829633cb31725e589e68ab55642b6aa9e1..09e9574eeb26f0273054e1111224521e0a072c67 100644 (file)
@@ -119,7 +119,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
         * No locking available for sched_info (and too expensive to add one)
         * Mitigate by taking snapshot of values
         */
-       t1 = tsk->sched_info.pcnt;
+       t1 = tsk->sched_info.pcount;
        t2 = tsk->sched_info.run_delay;
        t3 = tsk->sched_info.cpu_time;
 
index 993369ee94d1ebb8d4c7675a821e90abf8a1737e..7f7959de4a87b22e013d001b05f0cba4dfe0cefa 100644 (file)
@@ -111,6 +111,7 @@ static void __exit_signal(struct task_struct *tsk)
                 */
                sig->utime = cputime_add(sig->utime, tsk->utime);
                sig->stime = cputime_add(sig->stime, tsk->stime);
+               sig->gtime = cputime_add(sig->gtime, tsk->gtime);
                sig->min_flt += tsk->min_flt;
                sig->maj_flt += tsk->maj_flt;
                sig->nvcsw += tsk->nvcsw;
@@ -1242,6 +1243,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
                        cputime_add(p->stime,
                        cputime_add(sig->stime,
                                    sig->cstime)));
+               psig->cgtime =
+                       cputime_add(psig->cgtime,
+                       cputime_add(p->gtime,
+                       cputime_add(sig->gtime,
+                                   sig->cgtime)));
                psig->cmin_flt +=
                        p->min_flt + sig->min_flt + sig->cmin_flt;
                psig->cmaj_flt +=
index 5e67f90a1694b46fc752b0a5b48fa3701bc15ec2..3fc3c1383912a8cf105ddbb218b00dfa88d76233 100644 (file)
@@ -877,6 +877,8 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
        sig->tty_old_pgrp = NULL;
 
        sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
+       sig->gtime = cputime_zero;
+       sig->cgtime = cputime_zero;
        sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
        sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
        sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
@@ -1045,6 +1047,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        p->utime = cputime_zero;
        p->stime = cputime_zero;
+       p->gtime = cputime_zero;
 
 #ifdef CONFIG_TASK_XACCT
        p->rchar = 0;           /* I/O counter: bytes read */
index d0e5c48e18c78c3fe1fea8a2d87d26fe4973ca2c..6046939d08047fc1f68db06b5366eada62c133d1 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kexec.h>
+#include <linux/sched.h>
 
 #define KERNEL_ATTR_RO(_name) \
 static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
@@ -116,6 +117,13 @@ static int __init ksysfs_init(void)
                                              &notes_attr);
        }
 
+       /*
+        * Create "/sys/kernel/uids" directory and corresponding root user's
+        * directory under it.
+        */
+       if (!error)
+               error = uids_kobject_init();
+
        return error;
 }
 
index 734da579ad134779685cbf0291fbc6e14e9cc133..a6f1ee9c92d9fb7900ae02e44debe938a293aedb 100644 (file)
@@ -1521,7 +1521,7 @@ cache_hit:
 }
 
 static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
-               struct held_lock *hlock, int chain_head)
+               struct held_lock *hlock, int chain_head, u64 chain_key)
 {
        /*
         * Trylock needs to maintain the stack of held locks, but it
@@ -1534,7 +1534,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
         * graph_lock for us)
         */
        if (!hlock->trylock && (hlock->check == 2) &&
-                       lookup_chain_cache(curr->curr_chain_key, hlock->class)) {
+                       lookup_chain_cache(chain_key, hlock->class)) {
                /*
                 * Check whether last held lock:
                 *
@@ -1576,7 +1576,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
 #else
 static inline int validate_chain(struct task_struct *curr,
                struct lockdep_map *lock, struct held_lock *hlock,
-               int chain_head)
+               int chain_head, u64 chain_key)
 {
        return 1;
 }
@@ -2450,11 +2450,11 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                chain_head = 1;
        }
        chain_key = iterate_chain_key(chain_key, id);
-       curr->curr_chain_key = chain_key;
 
-       if (!validate_chain(curr, lock, hlock, chain_head))
+       if (!validate_chain(curr, lock, hlock, chain_head, chain_key))
                return 0;
 
+       curr->curr_chain_key = chain_key;
        curr->lockdep_depth++;
        check_chain_key(curr);
 #ifdef CONFIG_DEBUG_LOCKDEP
@@ -3199,3 +3199,19 @@ void debug_show_held_locks(struct task_struct *task)
 }
 
 EXPORT_SYMBOL_GPL(debug_show_held_locks);
+
+void lockdep_sys_exit(void)
+{
+       struct task_struct *curr = current;
+
+       if (unlikely(curr->lockdep_depth)) {
+               if (!debug_locks_off())
+                       return;
+               printk("\n================================================\n");
+               printk(  "[ BUG: lock held when returning to user space! ]\n");
+               printk(  "------------------------------------------------\n");
+               printk("%s/%d is leaving the kernel with locks still held!\n",
+                               curr->comm, curr->pid);
+               lockdep_print_held_locks(curr);
+       }
+}
index c851b2dcc685cc91db6bf16838aaab556517878e..8a135bd163c2cc719b4635b1e511aa87039d6f46 100644 (file)
 
 static void *l_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct lock_class *class = v;
+       struct lock_class *class;
 
        (*pos)++;
 
-       if (class->lock_entry.next != &all_lock_classes)
-               class = list_entry(class->lock_entry.next, struct lock_class,
-                                 lock_entry);
-       else
-               class = NULL;
-       m->private = class;
+       if (v == SEQ_START_TOKEN)
+               class = m->private;
+       else {
+               class = v;
+
+               if (class->lock_entry.next != &all_lock_classes)
+                       class = list_entry(class->lock_entry.next,
+                                          struct lock_class, lock_entry);
+               else
+                       class = NULL;
+       }
 
        return class;
 }
 
 static void *l_start(struct seq_file *m, loff_t *pos)
 {
-       struct lock_class *class = m->private;
+       struct lock_class *class;
+       loff_t i = 0;
 
-       if (&class->lock_entry == all_lock_classes.next)
-               seq_printf(m, "all lock classes:\n");
+       if (*pos == 0)
+               return SEQ_START_TOKEN;
 
-       return class;
+       list_for_each_entry(class, &all_lock_classes, lock_entry) {
+               if (++i == *pos)
+               return class;
+       }
+       return NULL;
 }
 
 static void l_stop(struct seq_file *m, void *v)
@@ -101,10 +111,15 @@ static void print_name(struct seq_file *m, struct lock_class *class)
 static int l_show(struct seq_file *m, void *v)
 {
        unsigned long nr_forward_deps, nr_backward_deps;
-       struct lock_class *class = m->private;
+       struct lock_class *class = v;
        struct lock_list *entry;
        char c1, c2, c3, c4;
 
+       if (v == SEQ_START_TOKEN) {
+               seq_printf(m, "all lock classes:\n");
+               return 0;
+       }
+
        seq_printf(m, "%p", class->key);
 #ifdef CONFIG_DEBUG_LOCKDEP
        seq_printf(m, " OPS:%8ld", class->ops);
@@ -523,10 +538,11 @@ static void *ls_start(struct seq_file *m, loff_t *pos)
 {
        struct lock_stat_seq *data = m->private;
 
-       if (data->iter == data->stats)
-               seq_header(m);
+       if (*pos == 0)
+               return SEQ_START_TOKEN;
 
-       if (data->iter == data->iter_end)
+       data->iter = data->stats + *pos;
+       if (data->iter >= data->iter_end)
                data->iter = NULL;
 
        return data->iter;
@@ -538,8 +554,13 @@ static void *ls_next(struct seq_file *m, void *v, loff_t *pos)
 
        (*pos)++;
 
-       data->iter = v;
-       data->iter++;
+       if (v == SEQ_START_TOKEN)
+               data->iter = data->stats;
+       else {
+               data->iter = v;
+               data->iter++;
+       }
+
        if (data->iter == data->iter_end)
                data->iter = NULL;
 
@@ -552,9 +573,11 @@ static void ls_stop(struct seq_file *m, void *v)
 
 static int ls_show(struct seq_file *m, void *v)
 {
-       struct lock_stat_seq *data = m->private;
+       if (v == SEQ_START_TOKEN)
+               seq_header(m);
+       else
+               seq_stats(m, v);
 
-       seq_stats(m, data->iter);
        return 0;
 }
 
index 691b86564dd97fbe8f88e75a0f1cd6024cf6762b..d7fe50cc556fd79624196a175b74996d9b23cf41 100644 (file)
@@ -51,6 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 
 EXPORT_SYMBOL(__mutex_init);
 
+#ifndef CONFIG_DEBUG_LOCK_ALLOC
 /*
  * We split the mutex lock/unlock logic into separate fastpath and
  * slowpath functions, to reduce the register pressure on the fastpath.
@@ -92,6 +93,7 @@ void inline fastcall __sched mutex_lock(struct mutex *lock)
 }
 
 EXPORT_SYMBOL(mutex_lock);
+#endif
 
 static void fastcall noinline __sched
 __mutex_unlock_slowpath(atomic_t *lock_count);
@@ -122,7 +124,8 @@ EXPORT_SYMBOL(mutex_unlock);
  * Lock a mutex (possibly interruptible), slowpath:
  */
 static inline int __sched
-__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
+__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
+               unsigned long ip)
 {
        struct task_struct *task = current;
        struct mutex_waiter waiter;
@@ -132,7 +135,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
        spin_lock_mutex(&lock->wait_lock, flags);
 
        debug_mutex_lock_common(lock, &waiter);
-       mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
+       mutex_acquire(&lock->dep_map, subclass, 0, ip);
        debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
 
        /* add waiting tasks to the end of the waitqueue (FIFO): */
@@ -143,7 +146,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
        if (old_val == 1)
                goto done;
 
-       lock_contended(&lock->dep_map, _RET_IP_);
+       lock_contended(&lock->dep_map, ip);
 
        for (;;) {
                /*
@@ -166,7 +169,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
                if (unlikely(state == TASK_INTERRUPTIBLE &&
                                                signal_pending(task))) {
                        mutex_remove_waiter(lock, &waiter, task_thread_info(task));
-                       mutex_release(&lock->dep_map, 1, _RET_IP_);
+                       mutex_release(&lock->dep_map, 1, ip);
                        spin_unlock_mutex(&lock->wait_lock, flags);
 
                        debug_mutex_free_waiter(&waiter);
@@ -197,20 +200,12 @@ done:
        return 0;
 }
 
-static void fastcall noinline __sched
-__mutex_lock_slowpath(atomic_t *lock_count)
-{
-       struct mutex *lock = container_of(lock_count, struct mutex, count);
-
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0);
-}
-
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 void __sched
 mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_nested);
@@ -219,7 +214,7 @@ int __sched
 mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass);
+       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
@@ -271,6 +266,7 @@ __mutex_unlock_slowpath(atomic_t *lock_count)
        __mutex_unlock_common_slowpath(lock_count, 1);
 }
 
+#ifndef CONFIG_DEBUG_LOCK_ALLOC
 /*
  * Here come the less common (and hence less performance-critical) APIs:
  * mutex_lock_interruptible() and mutex_trylock().
@@ -298,13 +294,22 @@ int fastcall __sched mutex_lock_interruptible(struct mutex *lock)
 
 EXPORT_SYMBOL(mutex_lock_interruptible);
 
+static void fastcall noinline __sched
+__mutex_lock_slowpath(atomic_t *lock_count)
+{
+       struct mutex *lock = container_of(lock_count, struct mutex, count);
+
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, _RET_IP_);
+}
+
 static int fastcall noinline __sched
 __mutex_lock_interruptible_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0);
+       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, _RET_IP_);
 }
+#endif
 
 /*
  * Spinlock based trylock, we take the spinlock and check whether we
index 7a15afb73ed0352d9ee31f6d03334255c716e5a9..57efe0400bc2a133b7b1bb055e597345c567450f 100644 (file)
@@ -712,7 +712,7 @@ sys_timer_getoverrun(timer_t timer_id)
 {
        struct k_itimer *timr;
        int overrun;
-       long flags;
+       unsigned long flags;
 
        timr = lock_timer(timer_id, &flags);
        if (!timr)
@@ -784,7 +784,7 @@ sys_timer_settime(timer_t timer_id, int flags,
        struct k_itimer *timr;
        struct itimerspec new_spec, old_spec;
        int error = 0;
-       long flag;
+       unsigned long flag;
        struct itimerspec *rtn = old_setting ? &old_spec : NULL;
 
        if (!new_setting)
@@ -836,7 +836,7 @@ asmlinkage long
 sys_timer_delete(timer_t timer_id)
 {
        struct k_itimer *timer;
-       long flags;
+       unsigned long flags;
 
 retry_delete:
        timer = lock_timer(timer_id, &flags);
index 2c2dd8410dc4fd8b27d0e66dcd31daceb56ff027..130214f3d229009d461a26ea01aae9e36a153d3a 100644 (file)
 #include <linux/cpu.h>
 #include <linux/mutex.h>
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key rcu_lock_key;
+struct lockdep_map rcu_lock_map =
+       STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
+
+EXPORT_SYMBOL_GPL(rcu_lock_map);
+#endif
+
 /* Definition for rcupdate control block. */
 static struct rcu_ctrlblk rcu_ctrlblk = {
        .cur = -300,
index 6c10fa796ca040ef8da1f1e65acd58e4d7644faa..bba57adb95044ba215caa58ee7bdd514ccd71c1c 100644 (file)
@@ -96,7 +96,7 @@ unsigned long long __attribute__((weak)) sched_clock(void)
 /*
  * Some helpers for converting nanosecond timing to jiffy resolution
  */
-#define NS_TO_JIFFIES(TIME)    ((TIME) / (1000000000 / HZ))
+#define NS_TO_JIFFIES(TIME)    ((unsigned long)(TIME) / (1000000000 / HZ))
 #define JIFFIES_TO_NS(TIME)    ((TIME) * (1000000000 / HZ))
 
 #define NICE_0_LOAD            SCHED_LOAD_SCALE
@@ -105,11 +105,9 @@ unsigned long long __attribute__((weak)) sched_clock(void)
 /*
  * These are the 'tuning knobs' of the scheduler:
  *
- * Minimum timeslice is 5 msecs (or 1 jiffy, whichever is larger),
- * default timeslice is 100 msecs, maximum timeslice is 800 msecs.
+ * default timeslice is 100 msecs (used only for SCHED_RR tasks).
  * Timeslices get refilled after they expire.
  */
-#define MIN_TIMESLICE          max(5 * HZ / 1000, 1)
 #define DEF_TIMESLICE          (100 * HZ / 1000)
 
 #ifdef CONFIG_SMP
@@ -133,24 +131,6 @@ static inline void sg_inc_cpu_power(struct sched_group *sg, u32 val)
 }
 #endif
 
-#define SCALE_PRIO(x, prio) \
-       max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
-
-/*
- * static_prio_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
- * to time slice values: [800ms ... 100ms ... 5ms]
- */
-static unsigned int static_prio_timeslice(int static_prio)
-{
-       if (static_prio == NICE_TO_PRIO(19))
-               return 1;
-
-       if (static_prio < NICE_TO_PRIO(0))
-               return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio);
-       else
-               return SCALE_PRIO(DEF_TIMESLICE, static_prio);
-}
-
 static inline int rt_policy(int policy)
 {
        if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
@@ -171,31 +151,91 @@ struct rt_prio_array {
        struct list_head queue[MAX_RT_PRIO];
 };
 
-struct load_stat {
-       struct load_weight load;
-       u64 load_update_start, load_update_last;
-       unsigned long delta_fair, delta_exec, delta_stat;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+struct cfs_rq;
+
+/* task group related information */
+struct task_group {
+       /* schedulable entities of this group on each cpu */
+       struct sched_entity **se;
+       /* runqueue "owned" by this group on each cpu */
+       struct cfs_rq **cfs_rq;
+       unsigned long shares;
+       /* spinlock to serialize modification to shares */
+       spinlock_t lock;
+};
+
+/* Default task group's sched entity on each cpu */
+static DEFINE_PER_CPU(struct sched_entity, init_sched_entity);
+/* Default task group's cfs_rq on each cpu */
+static DEFINE_PER_CPU(struct cfs_rq, init_cfs_rq) ____cacheline_aligned_in_smp;
+
+static struct sched_entity *init_sched_entity_p[NR_CPUS];
+static struct cfs_rq *init_cfs_rq_p[NR_CPUS];
+
+/* Default task group.
+ *     Every task in system belong to this group at bootup.
+ */
+struct task_group init_task_group = {
+       .se     = init_sched_entity_p,
+       .cfs_rq = init_cfs_rq_p,
 };
 
+#ifdef CONFIG_FAIR_USER_SCHED
+# define INIT_TASK_GRP_LOAD    2*NICE_0_LOAD
+#else
+# define INIT_TASK_GRP_LOAD    NICE_0_LOAD
+#endif
+
+static int init_task_group_load = INIT_TASK_GRP_LOAD;
+
+/* return group to which a task belongs */
+static inline struct task_group *task_group(struct task_struct *p)
+{
+       struct task_group *tg;
+
+#ifdef CONFIG_FAIR_USER_SCHED
+       tg = p->user->tg;
+#else
+       tg  = &init_task_group;
+#endif
+
+       return tg;
+}
+
+/* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
+static inline void set_task_cfs_rq(struct task_struct *p)
+{
+       p->se.cfs_rq = task_group(p)->cfs_rq[task_cpu(p)];
+       p->se.parent = task_group(p)->se[task_cpu(p)];
+}
+
+#else
+
+static inline void set_task_cfs_rq(struct task_struct *p) { }
+
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
 /* CFS-related fields in a runqueue */
 struct cfs_rq {
        struct load_weight load;
        unsigned long nr_running;
 
-       s64 fair_clock;
        u64 exec_clock;
-       s64 wait_runtime;
-       u64 sleeper_bonus;
-       unsigned long wait_runtime_overruns, wait_runtime_underruns;
+       u64 min_vruntime;
 
        struct rb_root tasks_timeline;
        struct rb_node *rb_leftmost;
        struct rb_node *rb_load_balance_curr;
-#ifdef CONFIG_FAIR_GROUP_SCHED
        /* 'curr' points to currently running entity on this cfs_rq.
         * It is set to NULL otherwise (i.e when none are currently running).
         */
        struct sched_entity *curr;
+
+       unsigned long nr_spread_over;
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
        struct rq *rq;  /* cpu runqueue to which this cfs_rq is attached */
 
        /* leaf cfs_rqs are those that hold tasks (lowest schedulable entity in
@@ -206,6 +246,8 @@ struct cfs_rq {
         * list is used during load balance.
         */
        struct list_head leaf_cfs_rq_list; /* Better name : task_cfs_rq_list? */
+       struct task_group *tg;    /* group that "owns" this runqueue */
+       struct rcu_head rcu;
 #endif
 };
 
@@ -237,7 +279,7 @@ struct rq {
 #ifdef CONFIG_NO_HZ
        unsigned char in_nohz_recently;
 #endif
-       struct load_stat ls;    /* capture load from *all* tasks on this cpu */
+       struct load_weight load;        /* capture load from *all* tasks on this cpu */
        unsigned long nr_load_updates;
        u64 nr_switches;
 
@@ -289,16 +331,19 @@ struct rq {
        unsigned long yld_exp_empty;
        unsigned long yld_act_empty;
        unsigned long yld_both_empty;
-       unsigned long yld_cnt;
+       unsigned long yld_count;
 
        /* schedule() stats */
        unsigned long sched_switch;
-       unsigned long sched_cnt;
+       unsigned long sched_count;
        unsigned long sched_goidle;
 
        /* try_to_wake_up() stats */
-       unsigned long ttwu_cnt;
+       unsigned long ttwu_count;
        unsigned long ttwu_local;
+
+       /* BKL stats */
+       unsigned long bkl_count;
 #endif
        struct lock_class_key rq_lock_key;
 };
@@ -382,6 +427,37 @@ static void update_rq_clock(struct rq *rq)
 #define task_rq(p)             cpu_rq(task_cpu(p))
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 
+/*
+ * Tunables that become constants when CONFIG_SCHED_DEBUG is off:
+ */
+#ifdef CONFIG_SCHED_DEBUG
+# define const_debug __read_mostly
+#else
+# define const_debug static const
+#endif
+
+/*
+ * Debugging: various feature bits
+ */
+enum {
+       SCHED_FEAT_NEW_FAIR_SLEEPERS    = 1,
+       SCHED_FEAT_START_DEBIT          = 2,
+       SCHED_FEAT_TREE_AVG             = 4,
+       SCHED_FEAT_APPROX_AVG           = 8,
+       SCHED_FEAT_WAKEUP_PREEMPT       = 16,
+       SCHED_FEAT_PREEMPT_RESTRICT     = 32,
+};
+
+const_debug unsigned int sysctl_sched_features =
+               SCHED_FEAT_NEW_FAIR_SLEEPERS    *1 |
+               SCHED_FEAT_START_DEBIT          *1 |
+               SCHED_FEAT_TREE_AVG             *0 |
+               SCHED_FEAT_APPROX_AVG           *0 |
+               SCHED_FEAT_WAKEUP_PREEMPT       *1 |
+               SCHED_FEAT_PREEMPT_RESTRICT     *1;
+
+#define sched_feat(x) (sysctl_sched_features & SCHED_FEAT_##x)
+
 /*
  * For kernel-internal use: high-speed (but slightly incorrect) per-cpu
  * clock constructed from sched_clock():
@@ -400,18 +476,7 @@ unsigned long long cpu_clock(int cpu)
 
        return now;
 }
-
-#ifdef CONFIG_FAIR_GROUP_SCHED
-/* Change a task's ->cfs_rq if it moves across CPUs */
-static inline void set_task_cfs_rq(struct task_struct *p)
-{
-       p->se.cfs_rq = &task_rq(p)->cfs;
-}
-#else
-static inline void set_task_cfs_rq(struct task_struct *p)
-{
-}
-#endif
+EXPORT_SYMBOL_GPL(cpu_clock);
 
 #ifndef prepare_arch_switch
 # define prepare_arch_switch(next)     do { } while (0)
@@ -497,16 +562,13 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
 static inline struct rq *__task_rq_lock(struct task_struct *p)
        __acquires(rq->lock)
 {
-       struct rq *rq;
-
-repeat_lock_task:
-       rq = task_rq(p);
-       spin_lock(&rq->lock);
-       if (unlikely(rq != task_rq(p))) {
+       for (;;) {
+               struct rq *rq = task_rq(p);
+               spin_lock(&rq->lock);
+               if (likely(rq == task_rq(p)))
+                       return rq;
                spin_unlock(&rq->lock);
-               goto repeat_lock_task;
        }
-       return rq;
 }
 
 /*
@@ -519,18 +581,17 @@ static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
 {
        struct rq *rq;
 
-repeat_lock_task:
-       local_irq_save(*flags);
-       rq = task_rq(p);
-       spin_lock(&rq->lock);
-       if (unlikely(rq != task_rq(p))) {
+       for (;;) {
+               local_irq_save(*flags);
+               rq = task_rq(p);
+               spin_lock(&rq->lock);
+               if (likely(rq == task_rq(p)))
+                       return rq;
                spin_unlock_irqrestore(&rq->lock, *flags);
-               goto repeat_lock_task;
        }
-       return rq;
 }
 
-static inline void __task_rq_unlock(struct rq *rq)
+static void __task_rq_unlock(struct rq *rq)
        __releases(rq->lock)
 {
        spin_unlock(&rq->lock);
@@ -545,7 +606,7 @@ static inline void task_rq_unlock(struct rq *rq, unsigned long *flags)
 /*
  * this_rq_lock - lock this runqueue and disable interrupts.
  */
-static inline struct rq *this_rq_lock(void)
+static struct rq *this_rq_lock(void)
        __acquires(rq->lock)
 {
        struct rq *rq;
@@ -645,19 +706,6 @@ static inline void resched_task(struct task_struct *p)
 }
 #endif
 
-static u64 div64_likely32(u64 divident, unsigned long divisor)
-{
-#if BITS_PER_LONG == 32
-       if (likely(divident <= 0xffffffffULL))
-               return (u32)divident / divisor;
-       do_div(divident, divisor);
-
-       return divident;
-#else
-       return divident / divisor;
-#endif
-}
-
 #if BITS_PER_LONG == 32
 # define WMULT_CONST   (~0UL)
 #else
@@ -699,16 +747,14 @@ calc_delta_fair(unsigned long delta_exec, struct load_weight *lw)
        return calc_delta_mine(delta_exec, NICE_0_LOAD, lw);
 }
 
-static void update_load_add(struct load_weight *lw, unsigned long inc)
+static inline void update_load_add(struct load_weight *lw, unsigned long inc)
 {
        lw->weight += inc;
-       lw->inv_weight = 0;
 }
 
-static void update_load_sub(struct load_weight *lw, unsigned long dec)
+static inline void update_load_sub(struct load_weight *lw, unsigned long dec)
 {
        lw->weight -= dec;
-       lw->inv_weight = 0;
 }
 
 /*
@@ -784,29 +830,20 @@ static int balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
                      int *this_best_prio, struct rq_iterator *iterator);
 
 #include "sched_stats.h"
-#include "sched_rt.c"
-#include "sched_fair.c"
 #include "sched_idletask.c"
+#include "sched_fair.c"
+#include "sched_rt.c"
 #ifdef CONFIG_SCHED_DEBUG
 # include "sched_debug.c"
 #endif
 
 #define sched_class_highest (&rt_sched_class)
 
-static void __update_curr_load(struct rq *rq, struct load_stat *ls)
-{
-       if (rq->curr != rq->idle && ls->load.weight) {
-               ls->delta_exec += ls->delta_stat;
-               ls->delta_fair += calc_delta_fair(ls->delta_stat, &ls->load);
-               ls->delta_stat = 0;
-       }
-}
-
 /*
  * Update delta_exec, delta_fair fields for rq.
  *
  * delta_fair clock advances at a rate inversely proportional to
- * total load (rq->ls.load.weight) on the runqueue, while
+ * total load (rq->load.weight) on the runqueue, while
  * delta_exec advances at the same rate as wall-clock (provided
  * cpu is not idle).
  *
@@ -814,35 +851,17 @@ static void __update_curr_load(struct rq *rq, struct load_stat *ls)
  * runqueue over any given interval. This (smoothened) load is used
  * during load balance.
  *
- * This function is called /before/ updating rq->ls.load
+ * This function is called /before/ updating rq->load
  * and when switching tasks.
  */
-static void update_curr_load(struct rq *rq)
-{
-       struct load_stat *ls = &rq->ls;
-       u64 start;
-
-       start = ls->load_update_start;
-       ls->load_update_start = rq->clock;
-       ls->delta_stat += rq->clock - start;
-       /*
-        * Stagger updates to ls->delta_fair. Very frequent updates
-        * can be expensive.
-        */
-       if (ls->delta_stat >= sysctl_sched_stat_granularity)
-               __update_curr_load(rq, ls);
-}
-
 static inline void inc_load(struct rq *rq, const struct task_struct *p)
 {
-       update_curr_load(rq);
-       update_load_add(&rq->ls.load, p->se.load.weight);
+       update_load_add(&rq->load, p->se.load.weight);
 }
 
 static inline void dec_load(struct rq *rq, const struct task_struct *p)
 {
-       update_curr_load(rq);
-       update_load_sub(&rq->ls.load, p->se.load.weight);
+       update_load_sub(&rq->load, p->se.load.weight);
 }
 
 static void inc_nr_running(struct task_struct *p, struct rq *rq)
@@ -859,8 +878,6 @@ static void dec_nr_running(struct task_struct *p, struct rq *rq)
 
 static void set_load_weight(struct task_struct *p)
 {
-       p->se.wait_runtime = 0;
-
        if (task_has_rt_policy(p)) {
                p->se.load.weight = prio_to_weight[0] * 2;
                p->se.load.inv_weight = prio_to_wmult[0] >> 1;
@@ -951,20 +968,6 @@ static void activate_task(struct rq *rq, struct task_struct *p, int wakeup)
        inc_nr_running(p, rq);
 }
 
-/*
- * activate_idle_task - move idle task to the _front_ of runqueue.
- */
-static inline void activate_idle_task(struct task_struct *p, struct rq *rq)
-{
-       update_rq_clock(rq);
-
-       if (p->state == TASK_UNINTERRUPTIBLE)
-               rq->nr_uninterruptible--;
-
-       enqueue_task(rq, p, 0);
-       inc_nr_running(p, rq);
-}
-
 /*
  * deactivate_task - remove a task from the runqueue.
  */
@@ -989,32 +992,50 @@ inline int task_curr(const struct task_struct *p)
 /* Used instead of source_load when we know the type == 0 */
 unsigned long weighted_cpuload(const int cpu)
 {
-       return cpu_rq(cpu)->ls.load.weight;
+       return cpu_rq(cpu)->load.weight;
 }
 
 static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
 {
 #ifdef CONFIG_SMP
        task_thread_info(p)->cpu = cpu;
-       set_task_cfs_rq(p);
 #endif
+       set_task_cfs_rq(p);
 }
 
 #ifdef CONFIG_SMP
 
+/*
+ * Is this task likely cache-hot:
+ */
+static inline int
+task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
+{
+       s64 delta;
+
+       if (p->sched_class != &fair_sched_class)
+               return 0;
+
+       if (sysctl_sched_migration_cost == -1)
+               return 1;
+       if (sysctl_sched_migration_cost == 0)
+               return 0;
+
+       delta = now - p->se.exec_start;
+
+       return delta < (s64)sysctl_sched_migration_cost;
+}
+
+
 void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 {
        int old_cpu = task_cpu(p);
        struct rq *old_rq = cpu_rq(old_cpu), *new_rq = cpu_rq(new_cpu);
-       u64 clock_offset, fair_clock_offset;
+       struct cfs_rq *old_cfsrq = task_cfs_rq(p),
+                     *new_cfsrq = cpu_cfs_rq(old_cfsrq, new_cpu);
+       u64 clock_offset;
 
        clock_offset = old_rq->clock - new_rq->clock;
-       fair_clock_offset = old_rq->cfs.fair_clock - new_rq->cfs.fair_clock;
-
-       if (p->se.wait_start_fair)
-               p->se.wait_start_fair -= fair_clock_offset;
-       if (p->se.sleep_start_fair)
-               p->se.sleep_start_fair -= fair_clock_offset;
 
 #ifdef CONFIG_SCHEDSTATS
        if (p->se.wait_start)
@@ -1023,7 +1044,14 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
                p->se.sleep_start -= clock_offset;
        if (p->se.block_start)
                p->se.block_start -= clock_offset;
+       if (old_cpu != new_cpu) {
+               schedstat_inc(p, se.nr_migrations);
+               if (task_hot(p, old_rq->clock, NULL))
+                       schedstat_inc(p, se.nr_forced2_migrations);
+       }
 #endif
+       p->se.vruntime -= old_cfsrq->min_vruntime -
+                                        new_cfsrq->min_vruntime;
 
        __set_task_cpu(p, new_cpu);
 }
@@ -1078,69 +1106,71 @@ void wait_task_inactive(struct task_struct *p)
        int running, on_rq;
        struct rq *rq;
 
-repeat:
-       /*
-        * We do the initial early heuristics without holding
-        * any task-queue locks at all. We'll only try to get
-        * the runqueue lock when things look like they will
-        * work out!
-        */
-       rq = task_rq(p);
+       for (;;) {
+               /*
+                * We do the initial early heuristics without holding
+                * any task-queue locks at all. We'll only try to get
+                * the runqueue lock when things look like they will
+                * work out!
+                */
+               rq = task_rq(p);
 
-       /*
-        * If the task is actively running on another CPU
-        * still, just relax and busy-wait without holding
-        * any locks.
-        *
-        * NOTE! Since we don't hold any locks, it's not
-        * even sure that "rq" stays as the right runqueue!
-        * But we don't care, since "task_running()" will
-        * return false if the runqueue has changed and p
-        * is actually now running somewhere else!
-        */
-       while (task_running(rq, p))
-               cpu_relax();
+               /*
+                * If the task is actively running on another CPU
+                * still, just relax and busy-wait without holding
+                * any locks.
+                *
+                * NOTE! Since we don't hold any locks, it's not
+                * even sure that "rq" stays as the right runqueue!
+                * But we don't care, since "task_running()" will
+                * return false if the runqueue has changed and p
+                * is actually now running somewhere else!
+                */
+               while (task_running(rq, p))
+                       cpu_relax();
 
-       /*
-        * Ok, time to look more closely! We need the rq
-        * lock now, to be *sure*. If we're wrong, we'll
-        * just go back and repeat.
-        */
-       rq = task_rq_lock(p, &flags);
-       running = task_running(rq, p);
-       on_rq = p->se.on_rq;
-       task_rq_unlock(rq, &flags);
+               /*
+                * Ok, time to look more closely! We need the rq
+                * lock now, to be *sure*. If we're wrong, we'll
+                * just go back and repeat.
+                */
+               rq = task_rq_lock(p, &flags);
+               running = task_running(rq, p);
+               on_rq = p->se.on_rq;
+               task_rq_unlock(rq, &flags);
 
-       /*
-        * Was it really running after all now that we
-        * checked with the proper locks actually held?
-        *
-        * Oops. Go back and try again..
-        */
-       if (unlikely(running)) {
-               cpu_relax();
-               goto repeat;
-       }
+               /*
+                * Was it really running after all now that we
+                * checked with the proper locks actually held?
+                *
+                * Oops. Go back and try again..
+                */
+               if (unlikely(running)) {
+                       cpu_relax();
+                       continue;
+               }
 
-       /*
-        * It's not enough that it's not actively running,
-        * it must be off the runqueue _entirely_, and not
-        * preempted!
-        *
-        * So if it wa still runnable (but just not actively
-        * running right now), it's preempted, and we should
-        * yield - it could be a while.
-        */
-       if (unlikely(on_rq)) {
-               yield();
-               goto repeat;
-       }
+               /*
+                * It's not enough that it's not actively running,
+                * it must be off the runqueue _entirely_, and not
+                * preempted!
+                *
+                * So if it wa still runnable (but just not actively
+                * running right now), it's preempted, and we should
+                * yield - it could be a while.
+                */
+               if (unlikely(on_rq)) {
+                       schedule_timeout_uninterruptible(1);
+                       continue;
+               }
 
-       /*
-        * Ahh, all good. It wasn't running, and it wasn't
-        * runnable, which means that it will never become
-        * running in the future either. We're all done!
-        */
+               /*
+                * Ahh, all good. It wasn't running, and it wasn't
+                * runnable, which means that it will never become
+                * running in the future either. We're all done!
+                */
+               break;
+       }
 }
 
 /***
@@ -1174,7 +1204,7 @@ void kick_process(struct task_struct *p)
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
  */
-static inline unsigned long source_load(int cpu, int type)
+static unsigned long source_load(int cpu, int type)
 {
        struct rq *rq = cpu_rq(cpu);
        unsigned long total = weighted_cpuload(cpu);
@@ -1189,7 +1219,7 @@ static inline unsigned long source_load(int cpu, int type)
  * Return a high guess at the load of a migration-target cpu weighted
  * according to the scheduling class and "nice" value.
  */
-static inline unsigned long target_load(int cpu, int type)
+static unsigned long target_load(int cpu, int type)
 {
        struct rq *rq = cpu_rq(cpu);
        unsigned long total = weighted_cpuload(cpu);
@@ -1231,7 +1261,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
 
                /* Skip over this group if it has no CPUs allowed */
                if (!cpus_intersects(group->cpumask, p->cpus_allowed))
-                       goto nextgroup;
+                       continue;
 
                local_group = cpu_isset(this_cpu, group->cpumask);
 
@@ -1259,9 +1289,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
                        min_load = avg_load;
                        idlest = group;
                }
-nextgroup:
-               group = group->next;
-       } while (group != sd->groups);
+       } while (group = group->next, group != sd->groups);
 
        if (!idlest || 100*this_load < imbalance*min_load)
                return NULL;
@@ -1393,8 +1421,13 @@ static int wake_idle(int cpu, struct task_struct *p)
                if (sd->flags & SD_WAKE_IDLE) {
                        cpus_and(tmp, sd->span, p->cpus_allowed);
                        for_each_cpu_mask(i, tmp) {
-                               if (idle_cpu(i))
+                               if (idle_cpu(i)) {
+                                       if (i != task_cpu(p)) {
+                                               schedstat_inc(p,
+                                                       se.nr_wakeups_idle);
+                                       }
                                        return i;
+                               }
                        }
                } else {
                        break;
@@ -1425,7 +1458,7 @@ static inline int wake_idle(int cpu, struct task_struct *p)
  */
 static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
 {
-       int cpu, this_cpu, success = 0;
+       int cpu, orig_cpu, this_cpu, success = 0;
        unsigned long flags;
        long old_state;
        struct rq *rq;
@@ -1444,6 +1477,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
                goto out_running;
 
        cpu = task_cpu(p);
+       orig_cpu = cpu;
        this_cpu = smp_processor_id();
 
 #ifdef CONFIG_SMP
@@ -1452,7 +1486,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
 
        new_cpu = cpu;
 
-       schedstat_inc(rq, ttwu_cnt);
+       schedstat_inc(rq, ttwu_count);
        if (cpu == this_cpu) {
                schedstat_inc(rq, ttwu_local);
                goto out_set_cpu;
@@ -1487,6 +1521,13 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
                        unsigned long tl = this_load;
                        unsigned long tl_per_task;
 
+                       /*
+                        * Attract cache-cold tasks on sync wakeups:
+                        */
+                       if (sync && !task_hot(p, rq->clock, this_sd))
+                               goto out_set_cpu;
+
+                       schedstat_inc(p, se.nr_wakeups_affine_attempts);
                        tl_per_task = cpu_avg_load_per_task(this_cpu);
 
                        /*
@@ -1506,6 +1547,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
                                 * there is no bad imbalance.
                                 */
                                schedstat_inc(this_sd, ttwu_move_affine);
+                               schedstat_inc(p, se.nr_wakeups_affine);
                                goto out_set_cpu;
                        }
                }
@@ -1517,6 +1559,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
                if (this_sd->flags & SD_WAKE_BALANCE) {
                        if (imbalance*this_load <= 100*load) {
                                schedstat_inc(this_sd, ttwu_move_balance);
+                               schedstat_inc(p, se.nr_wakeups_passive);
                                goto out_set_cpu;
                        }
                }
@@ -1542,18 +1585,18 @@ out_set_cpu:
 
 out_activate:
 #endif /* CONFIG_SMP */
+       schedstat_inc(p, se.nr_wakeups);
+       if (sync)
+               schedstat_inc(p, se.nr_wakeups_sync);
+       if (orig_cpu != cpu)
+               schedstat_inc(p, se.nr_wakeups_migrate);
+       if (cpu == this_cpu)
+               schedstat_inc(p, se.nr_wakeups_local);
+       else
+               schedstat_inc(p, se.nr_wakeups_remote);
        update_rq_clock(rq);
        activate_task(rq, p, 1);
-       /*
-        * Sync wakeups (i.e. those types of wakeups where the waker
-        * has indicated that it will leave the CPU in short order)
-        * don't trigger a preemption, if the woken up task will run on
-        * this cpu. (in this case the 'I will reschedule' promise of
-        * the waker guarantees that the freshly woken up task is going
-        * to be considered on this CPU.)
-        */
-       if (!sync || cpu != this_cpu)
-               check_preempt_curr(rq, p);
+       check_preempt_curr(rq, p);
        success = 1;
 
 out_running:
@@ -1584,28 +1627,20 @@ int fastcall wake_up_state(struct task_struct *p, unsigned int state)
  */
 static void __sched_fork(struct task_struct *p)
 {
-       p->se.wait_start_fair           = 0;
        p->se.exec_start                = 0;
        p->se.sum_exec_runtime          = 0;
        p->se.prev_sum_exec_runtime     = 0;
-       p->se.delta_exec                = 0;
-       p->se.delta_fair_run            = 0;
-       p->se.delta_fair_sleep          = 0;
-       p->se.wait_runtime              = 0;
-       p->se.sleep_start_fair          = 0;
 
 #ifdef CONFIG_SCHEDSTATS
        p->se.wait_start                = 0;
-       p->se.sum_wait_runtime          = 0;
        p->se.sum_sleep_runtime         = 0;
        p->se.sleep_start               = 0;
        p->se.block_start               = 0;
        p->se.sleep_max                 = 0;
        p->se.block_max                 = 0;
        p->se.exec_max                  = 0;
+       p->se.slice_max                 = 0;
        p->se.wait_max                  = 0;
-       p->se.wait_runtime_overruns     = 0;
-       p->se.wait_runtime_underruns    = 0;
 #endif
 
        INIT_LIST_HEAD(&p->run_list);
@@ -1636,12 +1671,14 @@ void sched_fork(struct task_struct *p, int clone_flags)
 #ifdef CONFIG_SMP
        cpu = sched_balance_self(cpu, SD_BALANCE_FORK);
 #endif
-       __set_task_cpu(p, cpu);
+       set_task_cpu(p, cpu);
 
        /*
         * Make sure we do not leak PI boosting priority to the child:
         */
        p->prio = current->normal_prio;
+       if (!rt_prio(p->prio))
+               p->sched_class = &fair_sched_class;
 
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
        if (likely(sched_info_on()))
@@ -1657,12 +1694,6 @@ void sched_fork(struct task_struct *p, int clone_flags)
        put_cpu();
 }
 
-/*
- * After fork, child runs first. (default) If set to 0 then
- * parent will (try to) run first.
- */
-unsigned int __read_mostly sysctl_sched_child_runs_first = 1;
-
 /*
  * wake_up_new_task - wake up a newly created task for the first time.
  *
@@ -1674,24 +1705,14 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
 {
        unsigned long flags;
        struct rq *rq;
-       int this_cpu;
 
        rq = task_rq_lock(p, &flags);
        BUG_ON(p->state != TASK_RUNNING);
-       this_cpu = smp_processor_id(); /* parent's CPU */
        update_rq_clock(rq);
 
        p->prio = effective_prio(p);
 
-       if (rt_prio(p->prio))
-               p->sched_class = &rt_sched_class;
-       else
-               p->sched_class = &fair_sched_class;
-
-       if (!p->sched_class->task_new || !sysctl_sched_child_runs_first ||
-                       (clone_flags & CLONE_VM) || task_cpu(p) != this_cpu ||
-                       !current->se.on_rq) {
-
+       if (!p->sched_class->task_new || !current->se.on_rq || !rq->cfs.curr) {
                activate_task(rq, p, 0);
        } else {
                /*
@@ -1800,7 +1821,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
  * with the lock held can cause deadlocks; see schedule() for
  * details.)
  */
-static inline void finish_task_switch(struct rq *rq, struct task_struct *prev)
+static void finish_task_switch(struct rq *rq, struct task_struct *prev)
        __releases(rq->lock)
 {
        struct mm_struct *mm = rq->prev_mm;
@@ -1982,42 +2003,10 @@ unsigned long nr_active(void)
  */
 static void update_cpu_load(struct rq *this_rq)
 {
-       u64 fair_delta64, exec_delta64, idle_delta64, sample_interval64, tmp64;
-       unsigned long total_load = this_rq->ls.load.weight;
-       unsigned long this_load =  total_load;
-       struct load_stat *ls = &this_rq->ls;
+       unsigned long this_load = this_rq->load.weight;
        int i, scale;
 
        this_rq->nr_load_updates++;
-       if (unlikely(!(sysctl_sched_features & SCHED_FEAT_PRECISE_CPU_LOAD)))
-               goto do_avg;
-
-       /* Update delta_fair/delta_exec fields first */
-       update_curr_load(this_rq);
-
-       fair_delta64 = ls->delta_fair + 1;
-       ls->delta_fair = 0;
-
-       exec_delta64 = ls->delta_exec + 1;
-       ls->delta_exec = 0;
-
-       sample_interval64 = this_rq->clock - ls->load_update_last;
-       ls->load_update_last = this_rq->clock;
-
-       if ((s64)sample_interval64 < (s64)TICK_NSEC)
-               sample_interval64 = TICK_NSEC;
-
-       if (exec_delta64 > sample_interval64)
-               exec_delta64 = sample_interval64;
-
-       idle_delta64 = sample_interval64 - exec_delta64;
-
-       tmp64 = div64_64(SCHED_LOAD_SCALE * exec_delta64, fair_delta64);
-       tmp64 = div64_64(tmp64 * exec_delta64, sample_interval64);
-
-       this_load = (unsigned long)tmp64;
-
-do_avg:
 
        /* Update our load: */
        for (i = 0, scale = 1; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
@@ -2027,7 +2016,13 @@ do_avg:
 
                old_load = this_rq->cpu_load[i];
                new_load = this_load;
-
+               /*
+                * Round up the averaging division if load is increasing. This
+                * prevents us from getting stuck on 9 if the load is 10, for
+                * example.
+                */
+               if (new_load > old_load)
+                       new_load += scale-1;
                this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
        }
 }
@@ -2179,13 +2174,38 @@ int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
         * 2) cannot be migrated to this CPU due to cpus_allowed, or
         * 3) are cache-hot on their current CPU.
         */
-       if (!cpu_isset(this_cpu, p->cpus_allowed))
+       if (!cpu_isset(this_cpu, p->cpus_allowed)) {
+               schedstat_inc(p, se.nr_failed_migrations_affine);
                return 0;
+       }
        *all_pinned = 0;
 
-       if (task_running(rq, p))
+       if (task_running(rq, p)) {
+               schedstat_inc(p, se.nr_failed_migrations_running);
                return 0;
+       }
+
+       /*
+        * Aggressive migration if:
+        * 1) task is cache cold, or
+        * 2) too many balance attempts have failed.
+        */
+
+       if (!task_hot(p, rq->clock, sd) ||
+                       sd->nr_balance_failed > sd->cache_nice_tries) {
+#ifdef CONFIG_SCHEDSTATS
+               if (task_hot(p, rq->clock, sd)) {
+                       schedstat_inc(sd, lb_hot_gained[idle]);
+                       schedstat_inc(p, se.nr_forced_migrations);
+               }
+#endif
+               return 1;
+       }
 
+       if (task_hot(p, rq->clock, sd)) {
+               schedstat_inc(p, se.nr_failed_migrations_hot);
+               return 0;
+       }
        return 1;
 }
 
@@ -2264,7 +2284,7 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
                      struct sched_domain *sd, enum cpu_idle_type idle,
                      int *all_pinned)
 {
-       struct sched_class *class = sched_class_highest;
+       const struct sched_class *class = sched_class_highest;
        unsigned long total_load_moved = 0;
        int this_best_prio = this_rq->curr->prio;
 
@@ -2289,7 +2309,7 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
 static int move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest,
                         struct sched_domain *sd, enum cpu_idle_type idle)
 {
-       struct sched_class *class;
+       const struct sched_class *class;
        int this_best_prio = MAX_PRIO;
 
        for (class = sched_class_highest; class; class = class->next)
@@ -2653,7 +2673,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
            !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
                sd_idle = 1;
 
-       schedstat_inc(sd, lb_cnt[idle]);
+       schedstat_inc(sd, lb_count[idle]);
 
 redo:
        group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,
@@ -2806,7 +2826,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
            !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
                sd_idle = 1;
 
-       schedstat_inc(sd, lb_cnt[CPU_NEWLY_IDLE]);
+       schedstat_inc(sd, lb_count[CPU_NEWLY_IDLE]);
 redo:
        group = find_busiest_group(sd, this_cpu, &imbalance, CPU_NEWLY_IDLE,
                                   &sd_idle, &cpus, NULL);
@@ -2940,7 +2960,7 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu)
        }
 
        if (likely(sd)) {
-               schedstat_inc(sd, alb_cnt);
+               schedstat_inc(sd, alb_count);
 
                if (move_one_task(target_rq, target_cpu, busiest_rq,
                                  sd, CPU_IDLE))
@@ -3033,7 +3053,7 @@ static DEFINE_SPINLOCK(balancing);
  *
  * Balancing parameters are set up in arch_init_sched_domains.
  */
-static inline void rebalance_domains(int cpu, enum cpu_idle_type idle)
+static void rebalance_domains(int cpu, enum cpu_idle_type idle)
 {
        int balance = 1;
        struct rq *rq = cpu_rq(cpu);
@@ -3279,6 +3299,25 @@ void account_user_time(struct task_struct *p, cputime_t cputime)
                cpustat->user = cputime64_add(cpustat->user, tmp);
 }
 
+/*
+ * Account guest cpu time to a process.
+ * @p: the process that the cpu time gets accounted to
+ * @cputime: the cpu time spent in virtual machine since the last update
+ */
+void account_guest_time(struct task_struct *p, cputime_t cputime)
+{
+       cputime64_t tmp;
+       struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
+
+       tmp = cputime_to_cputime64(cputime);
+
+       p->utime = cputime_add(p->utime, cputime);
+       p->gtime = cputime_add(p->gtime, cputime);
+
+       cpustat->user = cputime64_add(cpustat->user, tmp);
+       cpustat->guest = cputime64_add(cpustat->guest, tmp);
+}
+
 /*
  * Account system cpu time to a process.
  * @p: the process that the cpu time gets accounted to
@@ -3292,6 +3331,12 @@ void account_system_time(struct task_struct *p, int hardirq_offset,
        struct rq *rq = this_rq();
        cputime64_t tmp;
 
+       if (p->flags & PF_VCPU) {
+               account_guest_time(p, cputime);
+               p->flags &= ~PF_VCPU;
+               return;
+       }
+
        p->stime = cputime_add(p->stime, cputime);
 
        /* Add system time to cpustat. */
@@ -3430,7 +3475,13 @@ static inline void schedule_debug(struct task_struct *prev)
 
        profile_hit(SCHED_PROFILING, __builtin_return_address(0));
 
-       schedstat_inc(this_rq(), sched_cnt);
+       schedstat_inc(this_rq(), sched_count);
+#ifdef CONFIG_SCHEDSTATS
+       if (unlikely(prev->lock_depth >= 0)) {
+               schedstat_inc(this_rq(), bkl_count);
+               schedstat_inc(prev, sched_info.bkl_count);
+       }
+#endif
 }
 
 /*
@@ -3439,7 +3490,7 @@ static inline void schedule_debug(struct task_struct *prev)
 static inline struct task_struct *
 pick_next_task(struct rq *rq, struct task_struct *prev)
 {
-       struct sched_class *class;
+       const struct sched_class *class;
        struct task_struct *p;
 
        /*
@@ -3488,9 +3539,13 @@ need_resched_nonpreemptible:
 
        schedule_debug(prev);
 
-       spin_lock_irq(&rq->lock);
-       clear_tsk_need_resched(prev);
+       /*
+        * Do the rq-clock update outside the rq lock:
+        */
+       local_irq_disable();
        __update_rq_clock(rq);
+       spin_lock(&rq->lock);
+       clear_tsk_need_resched(prev);
 
        if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
                if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
@@ -3550,27 +3605,30 @@ asmlinkage void __sched preempt_schedule(void)
        if (likely(ti->preempt_count || irqs_disabled()))
                return;
 
-need_resched:
-       add_preempt_count(PREEMPT_ACTIVE);
-       /*
-        * We keep the big kernel semaphore locked, but we
-        * clear ->lock_depth so that schedule() doesnt
-        * auto-release the semaphore:
-        */
+       do {
+               add_preempt_count(PREEMPT_ACTIVE);
+
+               /*
+                * We keep the big kernel semaphore locked, but we
+                * clear ->lock_depth so that schedule() doesnt
+                * auto-release the semaphore:
+                */
 #ifdef CONFIG_PREEMPT_BKL
-       saved_lock_depth = task->lock_depth;
-       task->lock_depth = -1;
+               saved_lock_depth = task->lock_depth;
+               task->lock_depth = -1;
 #endif
-       schedule();
+               schedule();
 #ifdef CONFIG_PREEMPT_BKL
-       task->lock_depth = saved_lock_depth;
+               task->lock_depth = saved_lock_depth;
 #endif
-       sub_preempt_count(PREEMPT_ACTIVE);
+               sub_preempt_count(PREEMPT_ACTIVE);
 
-       /* we could miss a preemption opportunity between schedule and now */
-       barrier();
-       if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
-               goto need_resched;
+               /*
+                * Check again in case we missed a preemption opportunity
+                * between schedule and now.
+                */
+               barrier();
+       } while (unlikely(test_thread_flag(TIF_NEED_RESCHED)));
 }
 EXPORT_SYMBOL(preempt_schedule);
 
@@ -3590,29 +3648,32 @@ asmlinkage void __sched preempt_schedule_irq(void)
        /* Catch callers which need to be fixed */
        BUG_ON(ti->preempt_count || !irqs_disabled());
 
-need_resched:
-       add_preempt_count(PREEMPT_ACTIVE);
-       /*
-        * We keep the big kernel semaphore locked, but we
-        * clear ->lock_depth so that schedule() doesnt
-        * auto-release the semaphore:
-        */
+       do {
+               add_preempt_count(PREEMPT_ACTIVE);
+
+               /*
+                * We keep the big kernel semaphore locked, but we
+                * clear ->lock_depth so that schedule() doesnt
+                * auto-release the semaphore:
+                */
 #ifdef CONFIG_PREEMPT_BKL
-       saved_lock_depth = task->lock_depth;
-       task->lock_depth = -1;
+               saved_lock_depth = task->lock_depth;
+               task->lock_depth = -1;
 #endif
-       local_irq_enable();
-       schedule();
-       local_irq_disable();
+               local_irq_enable();
+               schedule();
+               local_irq_disable();
 #ifdef CONFIG_PREEMPT_BKL
-       task->lock_depth = saved_lock_depth;
+               task->lock_depth = saved_lock_depth;
 #endif
-       sub_preempt_count(PREEMPT_ACTIVE);
+               sub_preempt_count(PREEMPT_ACTIVE);
 
-       /* we could miss a preemption opportunity between schedule and now */
-       barrier();
-       if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
-               goto need_resched;
+               /*
+                * Check again in case we missed a preemption opportunity
+                * between schedule and now.
+                */
+               barrier();
+       } while (unlikely(test_thread_flag(TIF_NEED_RESCHED)));
 }
 
 #endif /* CONFIG_PREEMPT */
@@ -3636,10 +3697,9 @@ EXPORT_SYMBOL(default_wake_function);
 static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
                             int nr_exclusive, int sync, void *key)
 {
-       struct list_head *tmp, *next;
+       wait_queue_t *curr, *next;
 
-       list_for_each_safe(tmp, next, &q->task_list) {
-               wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
+       list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
                unsigned flags = curr->flags;
 
                if (curr->func(curr, mode, sync, key) &&
@@ -3729,206 +3789,116 @@ void fastcall complete_all(struct completion *x)
 }
 EXPORT_SYMBOL(complete_all);
 
-void fastcall __sched wait_for_completion(struct completion *x)
+static inline long __sched
+do_wait_for_common(struct completion *x, long timeout, int state)
 {
-       might_sleep();
-
-       spin_lock_irq(&x->wait.lock);
        if (!x->done) {
                DECLARE_WAITQUEUE(wait, current);
 
                wait.flags |= WQ_FLAG_EXCLUSIVE;
                __add_wait_queue_tail(&x->wait, &wait);
                do {
-                       __set_current_state(TASK_UNINTERRUPTIBLE);
-                       spin_unlock_irq(&x->wait.lock);
-                       schedule();
-                       spin_lock_irq(&x->wait.lock);
-               } while (!x->done);
-               __remove_wait_queue(&x->wait, &wait);
-       }
-       x->done--;
-       spin_unlock_irq(&x->wait.lock);
-}
-EXPORT_SYMBOL(wait_for_completion);
-
-unsigned long fastcall __sched
-wait_for_completion_timeout(struct completion *x, unsigned long timeout)
-{
-       might_sleep();
-
-       spin_lock_irq(&x->wait.lock);
-       if (!x->done) {
-               DECLARE_WAITQUEUE(wait, current);
-
-               wait.flags |= WQ_FLAG_EXCLUSIVE;
-               __add_wait_queue_tail(&x->wait, &wait);
-               do {
-                       __set_current_state(TASK_UNINTERRUPTIBLE);
+                       if (state == TASK_INTERRUPTIBLE &&
+                           signal_pending(current)) {
+                               __remove_wait_queue(&x->wait, &wait);
+                               return -ERESTARTSYS;
+                       }
+                       __set_current_state(state);
                        spin_unlock_irq(&x->wait.lock);
                        timeout = schedule_timeout(timeout);
                        spin_lock_irq(&x->wait.lock);
                        if (!timeout) {
                                __remove_wait_queue(&x->wait, &wait);
-                               goto out;
+                               return timeout;
                        }
                } while (!x->done);
                __remove_wait_queue(&x->wait, &wait);
        }
        x->done--;
-out:
-       spin_unlock_irq(&x->wait.lock);
        return timeout;
 }
-EXPORT_SYMBOL(wait_for_completion_timeout);
 
-int fastcall __sched wait_for_completion_interruptible(struct completion *x)
+static long __sched
+wait_for_common(struct completion *x, long timeout, int state)
 {
-       int ret = 0;
-
        might_sleep();
 
        spin_lock_irq(&x->wait.lock);
-       if (!x->done) {
-               DECLARE_WAITQUEUE(wait, current);
-
-               wait.flags |= WQ_FLAG_EXCLUSIVE;
-               __add_wait_queue_tail(&x->wait, &wait);
-               do {
-                       if (signal_pending(current)) {
-                               ret = -ERESTARTSYS;
-                               __remove_wait_queue(&x->wait, &wait);
-                               goto out;
-                       }
-                       __set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_irq(&x->wait.lock);
-                       schedule();
-                       spin_lock_irq(&x->wait.lock);
-               } while (!x->done);
-               __remove_wait_queue(&x->wait, &wait);
-       }
-       x->done--;
-out:
+       timeout = do_wait_for_common(x, timeout, state);
        spin_unlock_irq(&x->wait.lock);
+       return timeout;
+}
 
-       return ret;
+void fastcall __sched wait_for_completion(struct completion *x)
+{
+       wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
 }
-EXPORT_SYMBOL(wait_for_completion_interruptible);
+EXPORT_SYMBOL(wait_for_completion);
 
 unsigned long fastcall __sched
-wait_for_completion_interruptible_timeout(struct completion *x,
-                                         unsigned long timeout)
+wait_for_completion_timeout(struct completion *x, unsigned long timeout)
 {
-       might_sleep();
-
-       spin_lock_irq(&x->wait.lock);
-       if (!x->done) {
-               DECLARE_WAITQUEUE(wait, current);
-
-               wait.flags |= WQ_FLAG_EXCLUSIVE;
-               __add_wait_queue_tail(&x->wait, &wait);
-               do {
-                       if (signal_pending(current)) {
-                               timeout = -ERESTARTSYS;
-                               __remove_wait_queue(&x->wait, &wait);
-                               goto out;
-                       }
-                       __set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_irq(&x->wait.lock);
-                       timeout = schedule_timeout(timeout);
-                       spin_lock_irq(&x->wait.lock);
-                       if (!timeout) {
-                               __remove_wait_queue(&x->wait, &wait);
-                               goto out;
-                       }
-               } while (!x->done);
-               __remove_wait_queue(&x->wait, &wait);
-       }
-       x->done--;
-out:
-       spin_unlock_irq(&x->wait.lock);
-       return timeout;
+       return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
 }
-EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
+EXPORT_SYMBOL(wait_for_completion_timeout);
 
-static inline void
-sleep_on_head(wait_queue_head_t *q, wait_queue_t *wait, unsigned long *flags)
+int __sched wait_for_completion_interruptible(struct completion *x)
 {
-       spin_lock_irqsave(&q->lock, *flags);
-       __add_wait_queue(q, wait);
-       spin_unlock(&q->lock);
+       return wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE);
 }
+EXPORT_SYMBOL(wait_for_completion_interruptible);
 
-static inline void
-sleep_on_tail(wait_queue_head_t *q, wait_queue_t *wait, unsigned long *flags)
+unsigned long fastcall __sched
+wait_for_completion_interruptible_timeout(struct completion *x,
+                                         unsigned long timeout)
 {
-       spin_lock_irq(&q->lock);
-       __remove_wait_queue(q, wait);
-       spin_unlock_irqrestore(&q->lock, *flags);
+       return wait_for_common(x, timeout, TASK_INTERRUPTIBLE);
 }
+EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
 
-void __sched interruptible_sleep_on(wait_queue_head_t *q)
+static long __sched
+sleep_on_common(wait_queue_head_t *q, int state, long timeout)
 {
        unsigned long flags;
        wait_queue_t wait;
 
        init_waitqueue_entry(&wait, current);
 
-       current->state = TASK_INTERRUPTIBLE;
+       __set_current_state(state);
 
-       sleep_on_head(q, &wait, &flags);
-       schedule();
-       sleep_on_tail(q, &wait, &flags);
+       spin_lock_irqsave(&q->lock, flags);
+       __add_wait_queue(q, &wait);
+       spin_unlock(&q->lock);
+       timeout = schedule_timeout(timeout);
+       spin_lock_irq(&q->lock);
+       __remove_wait_queue(q, &wait);
+       spin_unlock_irqrestore(&q->lock, flags);
+
+       return timeout;
+}
+
+void __sched interruptible_sleep_on(wait_queue_head_t *q)
+{
+       sleep_on_common(q, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
 }
 EXPORT_SYMBOL(interruptible_sleep_on);
 
 long __sched
 interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
-       unsigned long flags;
-       wait_queue_t wait;
-
-       init_waitqueue_entry(&wait, current);
-
-       current->state = TASK_INTERRUPTIBLE;
-
-       sleep_on_head(q, &wait, &flags);
-       timeout = schedule_timeout(timeout);
-       sleep_on_tail(q, &wait, &flags);
-
-       return timeout;
+       return sleep_on_common(q, TASK_INTERRUPTIBLE, timeout);
 }
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 
 void __sched sleep_on(wait_queue_head_t *q)
 {
-       unsigned long flags;
-       wait_queue_t wait;
-
-       init_waitqueue_entry(&wait, current);
-
-       current->state = TASK_UNINTERRUPTIBLE;
-
-       sleep_on_head(q, &wait, &flags);
-       schedule();
-       sleep_on_tail(q, &wait, &flags);
+       sleep_on_common(q, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
 }
 EXPORT_SYMBOL(sleep_on);
 
 long __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
-       unsigned long flags;
-       wait_queue_t wait;
-
-       init_waitqueue_entry(&wait, current);
-
-       current->state = TASK_UNINTERRUPTIBLE;
-
-       sleep_on_head(q, &wait, &flags);
-       timeout = schedule_timeout(timeout);
-       sleep_on_tail(q, &wait, &flags);
-
-       return timeout;
+       return sleep_on_common(q, TASK_UNINTERRUPTIBLE, timeout);
 }
 EXPORT_SYMBOL(sleep_on_timeout);
 
@@ -3947,7 +3917,7 @@ EXPORT_SYMBOL(sleep_on_timeout);
 void rt_mutex_setprio(struct task_struct *p, int prio)
 {
        unsigned long flags;
-       int oldprio, on_rq;
+       int oldprio, on_rq, running;
        struct rq *rq;
 
        BUG_ON(prio < 0 || prio > MAX_PRIO);
@@ -3957,8 +3927,12 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
 
        oldprio = p->prio;
        on_rq = p->se.on_rq;
-       if (on_rq)
+       running = task_running(rq, p);
+       if (on_rq) {
                dequeue_task(rq, p, 0);
+               if (running)
+                       p->sched_class->put_prev_task(rq, p);
+       }
 
        if (rt_prio(prio))
                p->sched_class = &rt_sched_class;
@@ -3968,13 +3942,15 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        p->prio = prio;
 
        if (on_rq) {
+               if (running)
+                       p->sched_class->set_curr_task(rq);
                enqueue_task(rq, p, 0);
                /*
                 * Reschedule if we are currently running on this runqueue and
                 * our priority decreased, or if we are not currently running on
                 * this runqueue and our priority is higher than the current's
                 */
-               if (task_running(rq, p)) {
+               if (running) {
                        if (p->prio > oldprio)
                                resched_task(rq->curr);
                } else {
@@ -4138,7 +4114,7 @@ struct task_struct *idle_task(int cpu)
  * find_process_by_pid - find a process with a matching PID value.
  * @pid: the pid in question.
  */
-static inline struct task_struct *find_process_by_pid(pid_t pid)
+static struct task_struct *find_process_by_pid(pid_t pid)
 {
        return pid ? find_task_by_pid(pid) : current;
 }
@@ -4180,7 +4156,7 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
 int sched_setscheduler(struct task_struct *p, int policy,
                       struct sched_param *param)
 {
-       int retval, oldprio, oldpolicy = -1, on_rq;
+       int retval, oldprio, oldpolicy = -1, on_rq, running;
        unsigned long flags;
        struct rq *rq;
 
@@ -4262,18 +4238,26 @@ recheck:
        }
        update_rq_clock(rq);
        on_rq = p->se.on_rq;
-       if (on_rq)
+       running = task_running(rq, p);
+       if (on_rq) {
                deactivate_task(rq, p, 0);
+               if (running)
+                       p->sched_class->put_prev_task(rq, p);
+       }
+
        oldprio = p->prio;
        __setscheduler(rq, p, policy, param->sched_priority);
+
        if (on_rq) {
+               if (running)
+                       p->sched_class->set_curr_task(rq);
                activate_task(rq, p, 0);
                /*
                 * Reschedule if we are currently running on this runqueue and
                 * our priority decreased, or if we are not currently running on
                 * this runqueue and our priority is higher than the current's
                 */
-               if (task_running(rq, p)) {
+               if (running) {
                        if (p->prio > oldprio)
                                resched_task(rq->curr);
                } else {
@@ -4344,10 +4328,10 @@ asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param)
 asmlinkage long sys_sched_getscheduler(pid_t pid)
 {
        struct task_struct *p;
-       int retval = -EINVAL;
+       int retval;
 
        if (pid < 0)
-               goto out_nounlock;
+               return -EINVAL;
 
        retval = -ESRCH;
        read_lock(&tasklist_lock);
@@ -4358,8 +4342,6 @@ asmlinkage long sys_sched_getscheduler(pid_t pid)
                        retval = p->policy;
        }
        read_unlock(&tasklist_lock);
-
-out_nounlock:
        return retval;
 }
 
@@ -4372,10 +4354,10 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param)
 {
        struct sched_param lp;
        struct task_struct *p;
-       int retval = -EINVAL;
+       int retval;
 
        if (!param || pid < 0)
-               goto out_nounlock;
+               return -EINVAL;
 
        read_lock(&tasklist_lock);
        p = find_process_by_pid(pid);
@@ -4395,7 +4377,6 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param)
         */
        retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0;
 
-out_nounlock:
        return retval;
 
 out_unlock:
@@ -4555,8 +4536,8 @@ asmlinkage long sys_sched_yield(void)
 {
        struct rq *rq = this_rq_lock();
 
-       schedstat_inc(rq, yld_cnt);
-       current->sched_class->yield_task(rq, current);
+       schedstat_inc(rq, yld_count);
+       current->sched_class->yield_task(rq);
 
        /*
         * Since we are going to call schedule() anyway, there's
@@ -4750,11 +4731,12 @@ asmlinkage
 long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval)
 {
        struct task_struct *p;
-       int retval = -EINVAL;
+       unsigned int time_slice;
+       int retval;
        struct timespec t;
 
        if (pid < 0)
-               goto out_nounlock;
+               return -EINVAL;
 
        retval = -ESRCH;
        read_lock(&tasklist_lock);
@@ -4766,12 +4748,24 @@ long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval)
        if (retval)
                goto out_unlock;
 
-       jiffies_to_timespec(p->policy == SCHED_FIFO ?
-                               0 : static_prio_timeslice(p->static_prio), &t);
+       if (p->policy == SCHED_FIFO)
+               time_slice = 0;
+       else if (p->policy == SCHED_RR)
+               time_slice = DEF_TIMESLICE;
+       else {
+               struct sched_entity *se = &p->se;
+               unsigned long flags;
+               struct rq *rq;
+
+               rq = task_rq_lock(p, &flags);
+               time_slice = NS_TO_JIFFIES(sched_slice(cfs_rq_of(se), se));
+               task_rq_unlock(rq, &flags);
+       }
        read_unlock(&tasklist_lock);
+       jiffies_to_timespec(time_slice, &t);
        retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
-out_nounlock:
        return retval;
+
 out_unlock:
        read_unlock(&tasklist_lock);
        return retval;
@@ -4900,32 +4894,6 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
  */
 cpumask_t nohz_cpu_mask = CPU_MASK_NONE;
 
-/*
- * Increase the granularity value when there are more CPUs,
- * because with more CPUs the 'effective latency' as visible
- * to users decreases. But the relationship is not linear,
- * so pick a second-best guess by going with the log2 of the
- * number of CPUs.
- *
- * This idea comes from the SD scheduler of Con Kolivas:
- */
-static inline void sched_init_granularity(void)
-{
-       unsigned int factor = 1 + ilog2(num_online_cpus());
-       const unsigned long limit = 100000000;
-
-       sysctl_sched_min_granularity *= factor;
-       if (sysctl_sched_min_granularity > limit)
-               sysctl_sched_min_granularity = limit;
-
-       sysctl_sched_latency *= factor;
-       if (sysctl_sched_latency > limit)
-               sysctl_sched_latency = limit;
-
-       sysctl_sched_runtime_limit = sysctl_sched_latency;
-       sysctl_sched_wakeup_granularity = sysctl_sched_min_granularity / 2;
-}
-
 #ifdef CONFIG_SMP
 /*
  * This is how migration works:
@@ -5103,35 +5071,34 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p)
        struct rq *rq;
        int dest_cpu;
 
-restart:
-       /* On same node? */
-       mask = node_to_cpumask(cpu_to_node(dead_cpu));
-       cpus_and(mask, mask, p->cpus_allowed);
-       dest_cpu = any_online_cpu(mask);
-
-       /* On any allowed CPU? */
-       if (dest_cpu == NR_CPUS)
-               dest_cpu = any_online_cpu(p->cpus_allowed);
-
-       /* No more Mr. Nice Guy. */
-       if (dest_cpu == NR_CPUS) {
-               rq = task_rq_lock(p, &flags);
-               cpus_setall(p->cpus_allowed);
-               dest_cpu = any_online_cpu(p->cpus_allowed);
-               task_rq_unlock(rq, &flags);
+       do {
+               /* On same node? */
+               mask = node_to_cpumask(cpu_to_node(dead_cpu));
+               cpus_and(mask, mask, p->cpus_allowed);
+               dest_cpu = any_online_cpu(mask);
+
+               /* On any allowed CPU? */
+               if (dest_cpu == NR_CPUS)
+                       dest_cpu = any_online_cpu(p->cpus_allowed);
+
+               /* No more Mr. Nice Guy. */
+               if (dest_cpu == NR_CPUS) {
+                       rq = task_rq_lock(p, &flags);
+                       cpus_setall(p->cpus_allowed);
+                       dest_cpu = any_online_cpu(p->cpus_allowed);
+                       task_rq_unlock(rq, &flags);
 
-               /*
-                * Don't tell them about moving exiting tasks or
-                * kernel threads (both mm NULL), since they never
-                * leave kernel.
-                */
-               if (p->mm && printk_ratelimit())
-                       printk(KERN_INFO "process %d (%s) no "
-                              "longer affine to cpu%d\n",
-                              p->pid, p->comm, dead_cpu);
-       }
-       if (!__migrate_task(p, dead_cpu, dest_cpu))
-               goto restart;
+                       /*
+                        * Don't tell them about moving exiting tasks or
+                        * kernel threads (both mm NULL), since they never
+                        * leave kernel.
+                        */
+                       if (p->mm && printk_ratelimit())
+                               printk(KERN_INFO "process %d (%s) no "
+                                      "longer affine to cpu%d\n",
+                                      p->pid, p->comm, dead_cpu);
+               }
+       } while (!__migrate_task(p, dead_cpu, dest_cpu));
 }
 
 /*
@@ -5172,6 +5139,20 @@ static void migrate_live_tasks(int src_cpu)
        write_unlock_irq(&tasklist_lock);
 }
 
+/*
+ * activate_idle_task - move idle task to the _front_ of runqueue.
+ */
+static void activate_idle_task(struct task_struct *p, struct rq *rq)
+{
+       update_rq_clock(rq);
+
+       if (p->state == TASK_UNINTERRUPTIBLE)
+               rq->nr_uninterruptible--;
+
+       enqueue_task(rq, p, 0);
+       inc_nr_running(p, rq);
+}
+
 /*
  * Schedules idle task to be the next runnable task on current CPU.
  * It does so by boosting its priority to highest possible and adding it to
@@ -5284,14 +5265,23 @@ static struct ctl_table sd_ctl_root[] = {
 static struct ctl_table *sd_alloc_ctl_entry(int n)
 {
        struct ctl_table *entry =
-               kmalloc(n * sizeof(struct ctl_table), GFP_KERNEL);
-
-       BUG_ON(!entry);
-       memset(entry, 0, n * sizeof(struct ctl_table));
+               kcalloc(n, sizeof(struct ctl_table), GFP_KERNEL);
 
        return entry;
 }
 
+static void sd_free_ctl_entry(struct ctl_table **tablep)
+{
+       struct ctl_table *entry = *tablep;
+
+       for (entry = *tablep; entry->procname; entry++)
+               if (entry->child)
+                       sd_free_ctl_entry(&entry->child);
+
+       kfree(*tablep);
+       *tablep = NULL;
+}
+
 static void
 set_table_entry(struct ctl_table *entry,
                const char *procname, void *data, int maxlen,
@@ -5307,7 +5297,10 @@ set_table_entry(struct ctl_table *entry,
 static struct ctl_table *
 sd_alloc_ctl_domain_table(struct sched_domain *sd)
 {
-       struct ctl_table *table = sd_alloc_ctl_entry(14);
+       struct ctl_table *table = sd_alloc_ctl_entry(12);
+
+       if (table == NULL)
+               return NULL;
 
        set_table_entry(&table[0], "min_interval", &sd->min_interval,
                sizeof(long), 0644, proc_doulongvec_minmax);
@@ -5327,11 +5320,12 @@ sd_alloc_ctl_domain_table(struct sched_domain *sd)
                sizeof(int), 0644, proc_dointvec_minmax);
        set_table_entry(&table[8], "imbalance_pct", &sd->imbalance_pct,
                sizeof(int), 0644, proc_dointvec_minmax);
-       set_table_entry(&table[10], "cache_nice_tries",
+       set_table_entry(&table[9], "cache_nice_tries",
                &sd->cache_nice_tries,
                sizeof(int), 0644, proc_dointvec_minmax);
-       set_table_entry(&table[12], "flags", &sd->flags,
+       set_table_entry(&table[10], "flags", &sd->flags,
                sizeof(int), 0644, proc_dointvec_minmax);
+       /* &table[11] is terminator */
 
        return table;
 }
@@ -5346,6 +5340,8 @@ static ctl_table *sd_alloc_ctl_cpu_table(int cpu)
        for_each_domain(cpu, sd)
                domain_num++;
        entry = table = sd_alloc_ctl_entry(domain_num + 1);
+       if (table == NULL)
+               return NULL;
 
        i = 0;
        for_each_domain(cpu, sd) {
@@ -5360,24 +5356,38 @@ static ctl_table *sd_alloc_ctl_cpu_table(int cpu)
 }
 
 static struct ctl_table_header *sd_sysctl_header;
-static void init_sched_domain_sysctl(void)
+static void register_sched_domain_sysctl(void)
 {
        int i, cpu_num = num_online_cpus();
        struct ctl_table *entry = sd_alloc_ctl_entry(cpu_num + 1);
        char buf[32];
 
+       if (entry == NULL)
+               return;
+
        sd_ctl_dir[0].child = entry;
 
-       for (i = 0; i < cpu_num; i++, entry++) {
+       for_each_online_cpu(i) {
                snprintf(buf, 32, "cpu%d", i);
                entry->procname = kstrdup(buf, GFP_KERNEL);
                entry->mode = 0555;
                entry->child = sd_alloc_ctl_cpu_table(i);
+               entry++;
        }
        sd_sysctl_header = register_sysctl_table(sd_ctl_root);
 }
+
+static void unregister_sched_domain_sysctl(void)
+{
+       unregister_sysctl_table(sd_sysctl_header);
+       sd_sysctl_header = NULL;
+       sd_free_ctl_entry(&sd_ctl_dir[0].child);
+}
 #else
-static void init_sched_domain_sysctl(void)
+static void register_sched_domain_sysctl(void)
+{
+}
+static void unregister_sched_domain_sysctl(void)
 {
 }
 #endif
@@ -5499,8 +5509,7 @@ int __init migration_init(void)
 int nr_cpu_ids __read_mostly = NR_CPUS;
 EXPORT_SYMBOL(nr_cpu_ids);
 
-#undef SCHED_DOMAIN_DEBUG
-#ifdef SCHED_DOMAIN_DEBUG
+#ifdef CONFIG_SCHED_DEBUG
 static void sched_domain_debug(struct sched_domain *sd, int cpu)
 {
        int level = 0;
@@ -5558,16 +5567,19 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
                                printk("\n");
                                printk(KERN_ERR "ERROR: domain->cpu_power not "
                                                "set\n");
+                               break;
                        }
 
                        if (!cpus_weight(group->cpumask)) {
                                printk("\n");
                                printk(KERN_ERR "ERROR: empty group\n");
+                               break;
                        }
 
                        if (cpus_intersects(groupmask, group->cpumask)) {
                                printk("\n");
                                printk(KERN_ERR "ERROR: repeated CPUs\n");
+                               break;
                        }
 
                        cpus_or(groupmask, groupmask, group->cpumask);
@@ -5701,7 +5713,7 @@ static int __init isolated_cpu_setup(char *str)
        return 1;
 }
 
-__setup ("isolcpus=", isolated_cpu_setup);
+__setup("isolcpus=", isolated_cpu_setup);
 
 /*
  * init_sched_build_groups takes the cpumask we wish to span, and a pointer
@@ -5930,24 +5942,23 @@ static void init_numa_sched_groups_power(struct sched_group *group_head)
 
        if (!sg)
                return;
-next_sg:
-       for_each_cpu_mask(j, sg->cpumask) {
-               struct sched_domain *sd;
+       do {
+               for_each_cpu_mask(j, sg->cpumask) {
+                       struct sched_domain *sd;
 
-               sd = &per_cpu(phys_domains, j);
-               if (j != first_cpu(sd->groups->cpumask)) {
-                       /*
-                        * Only add "power" once for each
-                        * physical package.
-                        */
-                       continue;
-               }
+                       sd = &per_cpu(phys_domains, j);
+                       if (j != first_cpu(sd->groups->cpumask)) {
+                               /*
+                                * Only add "power" once for each
+                                * physical package.
+                                */
+                               continue;
+                       }
 
-               sg_inc_cpu_power(sg, sd->groups->__cpu_power);
-       }
-       sg = sg->next;
-       if (sg != group_head)
-               goto next_sg;
+                       sg_inc_cpu_power(sg, sd->groups->__cpu_power);
+               }
+               sg = sg->next;
+       } while (sg != group_head);
 }
 #endif
 
@@ -6058,7 +6069,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
        /*
         * Allocate the per-node list of sched groups
         */
-       sched_group_nodes = kzalloc(sizeof(struct sched_group *)*MAX_NUMNODES,
+       sched_group_nodes = kcalloc(MAX_NUMNODES, sizeof(struct sched_group *),
                                           GFP_KERNEL);
        if (!sched_group_nodes) {
                printk(KERN_WARNING "Can not alloc sched group node list\n");
@@ -6311,6 +6322,8 @@ static int arch_init_sched_domains(const cpumask_t *cpu_map)
 
        err = build_sched_domains(&cpu_default_map);
 
+       register_sched_domain_sysctl();
+
        return err;
 }
 
@@ -6327,6 +6340,8 @@ static void detach_destroy_domains(const cpumask_t *cpu_map)
 {
        int i;
 
+       unregister_sched_domain_sysctl();
+
        for_each_cpu_mask(i, *cpu_map)
                cpu_attach_domain(NULL, i);
        synchronize_sched();
@@ -6357,6 +6372,8 @@ int partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
        if (!err && !cpus_empty(*partition2))
                err = build_sched_domains(partition2);
 
+       register_sched_domain_sysctl();
+
        return err;
 }
 
@@ -6488,17 +6505,13 @@ void __init sched_init_smp(void)
        /* XXX: Theoretical race here - CPU may be hotplugged now */
        hotcpu_notifier(update_sched_domains, 0);
 
-       init_sched_domain_sysctl();
-
        /* Move init over to a non-isolated CPU */
        if (set_cpus_allowed(current, non_isolated_cpus) < 0)
                BUG();
-       sched_init_granularity();
 }
 #else
 void __init sched_init_smp(void)
 {
-       sched_init_granularity();
 }
 #endif /* CONFIG_SMP */
 
@@ -6512,28 +6525,20 @@ int in_sched_functions(unsigned long addr)
                && addr < (unsigned long)__sched_text_end);
 }
 
-static inline void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
+static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
 {
        cfs_rq->tasks_timeline = RB_ROOT;
-       cfs_rq->fair_clock = 1;
 #ifdef CONFIG_FAIR_GROUP_SCHED
        cfs_rq->rq = rq;
 #endif
+       cfs_rq->min_vruntime = (u64)(-(1LL << 20));
 }
 
 void __init sched_init(void)
 {
-       u64 now = sched_clock();
        int highest_cpu = 0;
        int i, j;
 
-       /*
-        * Link up the scheduling class hierarchy:
-        */
-       rt_sched_class.next = &fair_sched_class;
-       fair_sched_class.next = &idle_sched_class;
-       idle_sched_class.next = NULL;
-
        for_each_possible_cpu(i) {
                struct rt_prio_array *array;
                struct rq *rq;
@@ -6546,10 +6551,28 @@ void __init sched_init(void)
                init_cfs_rq(&rq->cfs, rq);
 #ifdef CONFIG_FAIR_GROUP_SCHED
                INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
-               list_add(&rq->cfs.leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+               {
+                       struct cfs_rq *cfs_rq = &per_cpu(init_cfs_rq, i);
+                       struct sched_entity *se =
+                                        &per_cpu(init_sched_entity, i);
+
+                       init_cfs_rq_p[i] = cfs_rq;
+                       init_cfs_rq(cfs_rq, rq);
+                       cfs_rq->tg = &init_task_group;
+                       list_add(&cfs_rq->leaf_cfs_rq_list,
+                                                        &rq->leaf_cfs_rq_list);
+
+                       init_sched_entity_p[i] = se;
+                       se->cfs_rq = &rq->cfs;
+                       se->my_q = cfs_rq;
+                       se->load.weight = init_task_group_load;
+                       se->load.inv_weight =
+                                div64_64(1ULL<<32, init_task_group_load);
+                       se->parent = NULL;
+               }
+               init_task_group.shares = init_task_group_load;
+               spin_lock_init(&init_task_group.lock);
 #endif
-               rq->ls.load_update_last = now;
-               rq->ls.load_update_start = now;
 
                for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
                        rq->cpu_load[j] = 0;
@@ -6634,26 +6657,40 @@ EXPORT_SYMBOL(__might_sleep);
 #endif
 
 #ifdef CONFIG_MAGIC_SYSRQ
+static void normalize_task(struct rq *rq, struct task_struct *p)
+{
+       int on_rq;
+       update_rq_clock(rq);
+       on_rq = p->se.on_rq;
+       if (on_rq)
+               deactivate_task(rq, p, 0);
+       __setscheduler(rq, p, SCHED_NORMAL, 0);
+       if (on_rq) {
+               activate_task(rq, p, 0);
+               resched_task(rq->curr);
+       }
+}
+
 void normalize_rt_tasks(void)
 {
        struct task_struct *g, *p;
        unsigned long flags;
        struct rq *rq;
-       int on_rq;
 
        read_lock_irq(&tasklist_lock);
        do_each_thread(g, p) {
-               p->se.fair_key                  = 0;
-               p->se.wait_runtime              = 0;
+               /*
+                * Only normalize user tasks:
+                */
+               if (!p->mm)
+                       continue;
+
                p->se.exec_start                = 0;
-               p->se.wait_start_fair           = 0;
-               p->se.sleep_start_fair          = 0;
 #ifdef CONFIG_SCHEDSTATS
                p->se.wait_start                = 0;
                p->se.sleep_start               = 0;
                p->se.block_start               = 0;
 #endif
-               task_rq(p)->cfs.fair_clock      = 0;
                task_rq(p)->clock               = 0;
 
                if (!rt_task(p)) {
@@ -6668,26 +6705,9 @@ void normalize_rt_tasks(void)
 
                spin_lock_irqsave(&p->pi_lock, flags);
                rq = __task_rq_lock(p);
-#ifdef CONFIG_SMP
-               /*
-                * Do not touch the migration thread:
-                */
-               if (p == rq->migration_thread)
-                       goto out_unlock;
-#endif
 
-               update_rq_clock(rq);
-               on_rq = p->se.on_rq;
-               if (on_rq)
-                       deactivate_task(rq, p, 0);
-               __setscheduler(rq, p, SCHED_NORMAL, 0);
-               if (on_rq) {
-                       activate_task(rq, p, 0);
-                       resched_task(rq->curr);
-               }
-#ifdef CONFIG_SMP
- out_unlock:
-#endif
+               normalize_task(rq, p);
+
                __task_rq_unlock(rq);
                spin_unlock_irqrestore(&p->pi_lock, flags);
        } while_each_thread(g, p);
@@ -6740,3 +6760,201 @@ void set_curr_task(int cpu, struct task_struct *p)
 }
 
 #endif
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+/* allocate runqueue etc for a new task group */
+struct task_group *sched_create_group(void)
+{
+       struct task_group *tg;
+       struct cfs_rq *cfs_rq;
+       struct sched_entity *se;
+       struct rq *rq;
+       int i;
+
+       tg = kzalloc(sizeof(*tg), GFP_KERNEL);
+       if (!tg)
+               return ERR_PTR(-ENOMEM);
+
+       tg->cfs_rq = kzalloc(sizeof(cfs_rq) * NR_CPUS, GFP_KERNEL);
+       if (!tg->cfs_rq)
+               goto err;
+       tg->se = kzalloc(sizeof(se) * NR_CPUS, GFP_KERNEL);
+       if (!tg->se)
+               goto err;
+
+       for_each_possible_cpu(i) {
+               rq = cpu_rq(i);
+
+               cfs_rq = kmalloc_node(sizeof(struct cfs_rq), GFP_KERNEL,
+                                                        cpu_to_node(i));
+               if (!cfs_rq)
+                       goto err;
+
+               se = kmalloc_node(sizeof(struct sched_entity), GFP_KERNEL,
+                                                       cpu_to_node(i));
+               if (!se)
+                       goto err;
+
+               memset(cfs_rq, 0, sizeof(struct cfs_rq));
+               memset(se, 0, sizeof(struct sched_entity));
+
+               tg->cfs_rq[i] = cfs_rq;
+               init_cfs_rq(cfs_rq, rq);
+               cfs_rq->tg = tg;
+
+               tg->se[i] = se;
+               se->cfs_rq = &rq->cfs;
+               se->my_q = cfs_rq;
+               se->load.weight = NICE_0_LOAD;
+               se->load.inv_weight = div64_64(1ULL<<32, NICE_0_LOAD);
+               se->parent = NULL;
+       }
+
+       for_each_possible_cpu(i) {
+               rq = cpu_rq(i);
+               cfs_rq = tg->cfs_rq[i];
+               list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+       }
+
+       tg->shares = NICE_0_LOAD;
+       spin_lock_init(&tg->lock);
+
+       return tg;
+
+err:
+       for_each_possible_cpu(i) {
+               if (tg->cfs_rq)
+                       kfree(tg->cfs_rq[i]);
+               if (tg->se)
+                       kfree(tg->se[i]);
+       }
+       kfree(tg->cfs_rq);
+       kfree(tg->se);
+       kfree(tg);
+
+       return ERR_PTR(-ENOMEM);
+}
+
+/* rcu callback to free various structures associated with a task group */
+static void free_sched_group(struct rcu_head *rhp)
+{
+       struct cfs_rq *cfs_rq = container_of(rhp, struct cfs_rq, rcu);
+       struct task_group *tg = cfs_rq->tg;
+       struct sched_entity *se;
+       int i;
+
+       /* now it should be safe to free those cfs_rqs */
+       for_each_possible_cpu(i) {
+               cfs_rq = tg->cfs_rq[i];
+               kfree(cfs_rq);
+
+               se = tg->se[i];
+               kfree(se);
+       }
+
+       kfree(tg->cfs_rq);
+       kfree(tg->se);
+       kfree(tg);
+}
+
+/* Destroy runqueue etc associated with a task group */
+void sched_destroy_group(struct task_group *tg)
+{
+       struct cfs_rq *cfs_rq;
+       int i;
+
+       for_each_possible_cpu(i) {
+               cfs_rq = tg->cfs_rq[i];
+               list_del_rcu(&cfs_rq->leaf_cfs_rq_list);
+       }
+
+       cfs_rq = tg->cfs_rq[0];
+
+       /* wait for possible concurrent references to cfs_rqs complete */
+       call_rcu(&cfs_rq->rcu, free_sched_group);
+}
+
+/* change task's runqueue when it moves between groups.
+ *     The caller of this function should have put the task in its new group
+ *     by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
+ *     reflect its new group.
+ */
+void sched_move_task(struct task_struct *tsk)
+{
+       int on_rq, running;
+       unsigned long flags;
+       struct rq *rq;
+
+       rq = task_rq_lock(tsk, &flags);
+
+       if (tsk->sched_class != &fair_sched_class)
+               goto done;
+
+       update_rq_clock(rq);
+
+       running = task_running(rq, tsk);
+       on_rq = tsk->se.on_rq;
+
+       if (on_rq) {
+               dequeue_task(rq, tsk, 0);
+               if (unlikely(running))
+                       tsk->sched_class->put_prev_task(rq, tsk);
+       }
+
+       set_task_cfs_rq(tsk);
+
+       if (on_rq) {
+               if (unlikely(running))
+                       tsk->sched_class->set_curr_task(rq);
+               enqueue_task(rq, tsk, 0);
+       }
+
+done:
+       task_rq_unlock(rq, &flags);
+}
+
+static void set_se_shares(struct sched_entity *se, unsigned long shares)
+{
+       struct cfs_rq *cfs_rq = se->cfs_rq;
+       struct rq *rq = cfs_rq->rq;
+       int on_rq;
+
+       spin_lock_irq(&rq->lock);
+
+       on_rq = se->on_rq;
+       if (on_rq)
+               dequeue_entity(cfs_rq, se, 0);
+
+       se->load.weight = shares;
+       se->load.inv_weight = div64_64((1ULL<<32), shares);
+
+       if (on_rq)
+               enqueue_entity(cfs_rq, se, 0);
+
+       spin_unlock_irq(&rq->lock);
+}
+
+int sched_group_set_shares(struct task_group *tg, unsigned long shares)
+{
+       int i;
+
+       spin_lock(&tg->lock);
+       if (tg->shares == shares)
+               goto done;
+
+       tg->shares = shares;
+       for_each_possible_cpu(i)
+               set_se_shares(tg->se[i], shares);
+
+done:
+       spin_unlock(&tg->lock);
+       return 0;
+}
+
+unsigned long sched_group_shares(struct task_group *tg)
+{
+       return tg->shares;
+}
+
+#endif /* CONFIG_FAIR_GROUP_SCHED */
index c3ee38bd3426d91449640d0d5329c7ead4ad038e..a5e517ec07c3dfa5e7b688b40355a9e4a67f13bc 100644 (file)
                printk(x);                      \
  } while (0)
 
+/*
+ * Ease the printing of nsec fields:
+ */
+static long long nsec_high(long long nsec)
+{
+       if (nsec < 0) {
+               nsec = -nsec;
+               do_div(nsec, 1000000);
+               return -nsec;
+       }
+       do_div(nsec, 1000000);
+
+       return nsec;
+}
+
+static unsigned long nsec_low(long long nsec)
+{
+       if (nsec < 0)
+               nsec = -nsec;
+
+       return do_div(nsec, 1000000);
+}
+
+#define SPLIT_NS(x) nsec_high(x), nsec_low(x)
+
 static void
 print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
 {
@@ -36,23 +61,19 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
        else
                SEQ_printf(m, " ");
 
-       SEQ_printf(m, "%15s %5d %15Ld %13Ld %13Ld %9Ld %5d ",
+       SEQ_printf(m, "%15s %5d %9Ld.%06ld %9Ld %5d ",
                p->comm, p->pid,
-               (long long)p->se.fair_key,
-               (long long)(p->se.fair_key - rq->cfs.fair_clock),
-               (long long)p->se.wait_runtime,
+               SPLIT_NS(p->se.vruntime),
                (long long)(p->nvcsw + p->nivcsw),
                p->prio);
 #ifdef CONFIG_SCHEDSTATS
-       SEQ_printf(m, "%15Ld %15Ld %15Ld %15Ld %15Ld\n",
-               (long long)p->se.sum_exec_runtime,
-               (long long)p->se.sum_wait_runtime,
-               (long long)p->se.sum_sleep_runtime,
-               (long long)p->se.wait_runtime_overruns,
-               (long long)p->se.wait_runtime_underruns);
+       SEQ_printf(m, "%9Ld.%06ld %9Ld.%06ld %9Ld.%06ld\n",
+               SPLIT_NS(p->se.vruntime),
+               SPLIT_NS(p->se.sum_exec_runtime),
+               SPLIT_NS(p->se.sum_sleep_runtime));
 #else
-       SEQ_printf(m, "%15Ld %15Ld %15Ld %15Ld %15Ld\n",
-               0LL, 0LL, 0LL, 0LL, 0LL);
+       SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld\n",
+               0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
 #endif
 }
 
@@ -62,14 +83,10 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
 
        SEQ_printf(m,
        "\nrunnable tasks:\n"
-       "            task   PID        tree-key         delta       waiting"
-       "  switches  prio"
-       "        sum-exec        sum-wait       sum-sleep"
-       "    wait-overrun   wait-underrun\n"
-       "------------------------------------------------------------------"
-       "----------------"
-       "------------------------------------------------"
-       "--------------------------------\n");
+       "            task   PID         tree-key  switches  prio"
+       "     exec-runtime         sum-exec        sum-sleep\n"
+       "------------------------------------------------------"
+       "----------------------------------------------------\n");
 
        read_lock_irq(&tasklist_lock);
 
@@ -83,45 +100,48 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
        read_unlock_irq(&tasklist_lock);
 }
 
-static void
-print_cfs_rq_runtime_sum(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
+void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 {
-       s64 wait_runtime_rq_sum = 0;
-       struct task_struct *p;
-       struct rb_node *curr;
-       unsigned long flags;
+       s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1,
+               spread, rq0_min_vruntime, spread0;
        struct rq *rq = &per_cpu(runqueues, cpu);
+       struct sched_entity *last;
+       unsigned long flags;
 
-       spin_lock_irqsave(&rq->lock, flags);
-       curr = first_fair(cfs_rq);
-       while (curr) {
-               p = rb_entry(curr, struct task_struct, se.run_node);
-               wait_runtime_rq_sum += p->se.wait_runtime;
-
-               curr = rb_next(curr);
-       }
-       spin_unlock_irqrestore(&rq->lock, flags);
-
-       SEQ_printf(m, "  .%-30s: %Ld\n", "wait_runtime_rq_sum",
-               (long long)wait_runtime_rq_sum);
-}
-
-void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
-{
        SEQ_printf(m, "\ncfs_rq\n");
 
-#define P(x) \
-       SEQ_printf(m, "  .%-30s: %Ld\n", #x, (long long)(cfs_rq->x))
-
-       P(fair_clock);
-       P(exec_clock);
-       P(wait_runtime);
-       P(wait_runtime_overruns);
-       P(wait_runtime_underruns);
-       P(sleeper_bonus);
-#undef P
+       SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "exec_clock",
+                       SPLIT_NS(cfs_rq->exec_clock));
 
-       print_cfs_rq_runtime_sum(m, cpu, cfs_rq);
+       spin_lock_irqsave(&rq->lock, flags);
+       if (cfs_rq->rb_leftmost)
+               MIN_vruntime = (__pick_next_entity(cfs_rq))->vruntime;
+       last = __pick_last_entity(cfs_rq);
+       if (last)
+               max_vruntime = last->vruntime;
+       min_vruntime = rq->cfs.min_vruntime;
+       rq0_min_vruntime = per_cpu(runqueues, 0).cfs.min_vruntime;
+       spin_unlock_irqrestore(&rq->lock, flags);
+       SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "MIN_vruntime",
+                       SPLIT_NS(MIN_vruntime));
+       SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "min_vruntime",
+                       SPLIT_NS(min_vruntime));
+       SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "max_vruntime",
+                       SPLIT_NS(max_vruntime));
+       spread = max_vruntime - MIN_vruntime;
+       SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "spread",
+                       SPLIT_NS(spread));
+       spread0 = min_vruntime - rq0_min_vruntime;
+       SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "spread0",
+                       SPLIT_NS(spread0));
+       SEQ_printf(m, "  .%-30s: %ld\n", "nr_running", cfs_rq->nr_running);
+       SEQ_printf(m, "  .%-30s: %ld\n", "load", cfs_rq->load.weight);
+#ifdef CONFIG_SCHEDSTATS
+       SEQ_printf(m, "  .%-30s: %ld\n", "bkl_count",
+                       rq->bkl_count);
+#endif
+       SEQ_printf(m, "  .%-30s: %ld\n", "nr_spread_over",
+                       cfs_rq->nr_spread_over);
 }
 
 static void print_cpu(struct seq_file *m, int cpu)
@@ -141,31 +161,32 @@ static void print_cpu(struct seq_file *m, int cpu)
 
 #define P(x) \
        SEQ_printf(m, "  .%-30s: %Ld\n", #x, (long long)(rq->x))
+#define PN(x) \
+       SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rq->x))
 
        P(nr_running);
        SEQ_printf(m, "  .%-30s: %lu\n", "load",
-                  rq->ls.load.weight);
-       P(ls.delta_fair);
-       P(ls.delta_exec);
+                  rq->load.weight);
        P(nr_switches);
        P(nr_load_updates);
        P(nr_uninterruptible);
        SEQ_printf(m, "  .%-30s: %lu\n", "jiffies", jiffies);
-       P(next_balance);
+       PN(next_balance);
        P(curr->pid);
-       P(clock);
-       P(idle_clock);
-       P(prev_clock_raw);
+       PN(clock);
+       PN(idle_clock);
+       PN(prev_clock_raw);
        P(clock_warps);
        P(clock_overflows);
        P(clock_deep_idle_events);
-       P(clock_max_delta);
+       PN(clock_max_delta);
        P(cpu_load[0]);
        P(cpu_load[1]);
        P(cpu_load[2]);
        P(cpu_load[3]);
        P(cpu_load[4]);
 #undef P
+#undef PN
 
        print_cfs_stats(m, cpu);
 
@@ -177,12 +198,25 @@ static int sched_debug_show(struct seq_file *m, void *v)
        u64 now = ktime_to_ns(ktime_get());
        int cpu;
 
-       SEQ_printf(m, "Sched Debug Version: v0.05-v20, %s %.*s\n",
+       SEQ_printf(m, "Sched Debug Version: v0.06-v22, %s %.*s\n",
                init_utsname()->release,
                (int)strcspn(init_utsname()->version, " "),
                init_utsname()->version);
 
-       SEQ_printf(m, "now at %Lu nsecs\n", (unsigned long long)now);
+       SEQ_printf(m, "now at %Lu.%06ld msecs\n", SPLIT_NS(now));
+
+#define P(x) \
+       SEQ_printf(m, "  .%-40s: %Ld\n", #x, (long long)(x))
+#define PN(x) \
+       SEQ_printf(m, "  .%-40s: %Ld.%06ld\n", #x, SPLIT_NS(x))
+       PN(sysctl_sched_latency);
+       PN(sysctl_sched_nr_latency);
+       PN(sysctl_sched_wakeup_granularity);
+       PN(sysctl_sched_batch_wakeup_granularity);
+       PN(sysctl_sched_child_runs_first);
+       P(sysctl_sched_features);
+#undef PN
+#undef P
 
        for_each_online_cpu(cpu)
                print_cpu(m, cpu);
@@ -202,7 +236,7 @@ static int sched_debug_open(struct inode *inode, struct file *filp)
        return single_open(filp, sched_debug_show, NULL);
 }
 
-static struct file_operations sched_debug_fops = {
+static const struct file_operations sched_debug_fops = {
        .open           = sched_debug_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -226,6 +260,7 @@ __initcall(init_sched_debug_procfs);
 
 void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 {
+       unsigned long nr_switches;
        unsigned long flags;
        int num_threads = 1;
 
@@ -237,41 +272,89 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
        rcu_read_unlock();
 
        SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
-       SEQ_printf(m, "----------------------------------------------\n");
+       SEQ_printf(m,
+               "---------------------------------------------------------\n");
+#define __P(F) \
+       SEQ_printf(m, "%-35s:%21Ld\n", #F, (long long)F)
 #define P(F) \
-       SEQ_printf(m, "%-25s:%20Ld\n", #F, (long long)p->F)
+       SEQ_printf(m, "%-35s:%21Ld\n", #F, (long long)p->F)
+#define __PN(F) \
+       SEQ_printf(m, "%-35s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F))
+#define PN(F) \
+       SEQ_printf(m, "%-35s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F))
 
-       P(se.wait_runtime);
-       P(se.wait_start_fair);
-       P(se.exec_start);
-       P(se.sleep_start_fair);
-       P(se.sum_exec_runtime);
+       PN(se.exec_start);
+       PN(se.vruntime);
+       PN(se.sum_exec_runtime);
+
+       nr_switches = p->nvcsw + p->nivcsw;
 
 #ifdef CONFIG_SCHEDSTATS
-       P(se.wait_start);
-       P(se.sleep_start);
-       P(se.block_start);
-       P(se.sleep_max);
-       P(se.block_max);
-       P(se.exec_max);
-       P(se.wait_max);
-       P(se.wait_runtime_overruns);
-       P(se.wait_runtime_underruns);
-       P(se.sum_wait_runtime);
+       PN(se.wait_start);
+       PN(se.sleep_start);
+       PN(se.block_start);
+       PN(se.sleep_max);
+       PN(se.block_max);
+       PN(se.exec_max);
+       PN(se.slice_max);
+       PN(se.wait_max);
+       P(sched_info.bkl_count);
+       P(se.nr_migrations);
+       P(se.nr_migrations_cold);
+       P(se.nr_failed_migrations_affine);
+       P(se.nr_failed_migrations_running);
+       P(se.nr_failed_migrations_hot);
+       P(se.nr_forced_migrations);
+       P(se.nr_forced2_migrations);
+       P(se.nr_wakeups);
+       P(se.nr_wakeups_sync);
+       P(se.nr_wakeups_migrate);
+       P(se.nr_wakeups_local);
+       P(se.nr_wakeups_remote);
+       P(se.nr_wakeups_affine);
+       P(se.nr_wakeups_affine_attempts);
+       P(se.nr_wakeups_passive);
+       P(se.nr_wakeups_idle);
+
+       {
+               u64 avg_atom, avg_per_cpu;
+
+               avg_atom = p->se.sum_exec_runtime;
+               if (nr_switches)
+                       do_div(avg_atom, nr_switches);
+               else
+                       avg_atom = -1LL;
+
+               avg_per_cpu = p->se.sum_exec_runtime;
+               if (p->se.nr_migrations)
+                       avg_per_cpu = div64_64(avg_per_cpu, p->se.nr_migrations);
+               else
+                       avg_per_cpu = -1LL;
+
+               __PN(avg_atom);
+               __PN(avg_per_cpu);
+       }
 #endif
-       SEQ_printf(m, "%-25s:%20Ld\n",
-                  "nr_switches", (long long)(p->nvcsw + p->nivcsw));
+       __P(nr_switches);
+       SEQ_printf(m, "%-35s:%21Ld\n",
+                  "nr_voluntary_switches", (long long)p->nvcsw);
+       SEQ_printf(m, "%-35s:%21Ld\n",
+                  "nr_involuntary_switches", (long long)p->nivcsw);
+
        P(se.load.weight);
        P(policy);
        P(prio);
+#undef PN
+#undef __PN
 #undef P
+#undef __P
 
        {
                u64 t0, t1;
 
                t0 = sched_clock();
                t1 = sched_clock();
-               SEQ_printf(m, "%-25s:%20Ld\n",
+               SEQ_printf(m, "%-35s:%21Ld\n",
                           "clock-delta", (long long)(t1-t0));
        }
 }
@@ -279,9 +362,32 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 void proc_sched_set_task(struct task_struct *p)
 {
 #ifdef CONFIG_SCHEDSTATS
-       p->se.sleep_max = p->se.block_max = p->se.exec_max = p->se.wait_max = 0;
-       p->se.wait_runtime_overruns = p->se.wait_runtime_underruns = 0;
+       p->se.wait_max                          = 0;
+       p->se.sleep_max                         = 0;
+       p->se.sum_sleep_runtime                 = 0;
+       p->se.block_max                         = 0;
+       p->se.exec_max                          = 0;
+       p->se.slice_max                         = 0;
+       p->se.nr_migrations                     = 0;
+       p->se.nr_migrations_cold                = 0;
+       p->se.nr_failed_migrations_affine       = 0;
+       p->se.nr_failed_migrations_running      = 0;
+       p->se.nr_failed_migrations_hot          = 0;
+       p->se.nr_forced_migrations              = 0;
+       p->se.nr_forced2_migrations             = 0;
+       p->se.nr_wakeups                        = 0;
+       p->se.nr_wakeups_sync                   = 0;
+       p->se.nr_wakeups_migrate                = 0;
+       p->se.nr_wakeups_local                  = 0;
+       p->se.nr_wakeups_remote                 = 0;
+       p->se.nr_wakeups_affine                 = 0;
+       p->se.nr_wakeups_affine_attempts        = 0;
+       p->se.nr_wakeups_passive                = 0;
+       p->se.nr_wakeups_idle                   = 0;
+       p->sched_info.bkl_count                 = 0;
 #endif
-       p->se.sum_exec_runtime = 0;
-       p->se.prev_sum_exec_runtime     = 0;
+       p->se.sum_exec_runtime                  = 0;
+       p->se.prev_sum_exec_runtime             = 0;
+       p->nvcsw                                = 0;
+       p->nivcsw                               = 0;
 }
index 67c67a87146ebaa64514c4bdf8b0ae5de0d4cf47..a17b785d7000cd876045cae3e9c1fdba1f39ce9e 100644 (file)
  * (default: 20ms, units: nanoseconds)
  *
  * NOTE: this latency value is not the same as the concept of
- * 'timeslice length' - timeslices in CFS are of variable length.
- * (to see the precise effective timeslice length of your workload,
- *  run vmstat and monitor the context-switches field)
+ * 'timeslice length' - timeslices in CFS are of variable length
+ * and have no persistent notion like in traditional, time-slice
+ * based scheduling concepts.
  *
- * On SMP systems the value of this is multiplied by the log2 of the
- * number of CPUs. (i.e. factor 2x on 2-way systems, 3x on 4-way
- * systems, 4x on 8-way systems, 5x on 16-way systems, etc.)
- * Targeted preemption latency for CPU-bound tasks:
+ * (to see the precise effective timeslice length of your workload,
+ *  run vmstat and monitor the context-switches (cs) field)
  */
-unsigned int sysctl_sched_latency __read_mostly = 20000000ULL;
+const_debug unsigned int sysctl_sched_latency = 20000000ULL;
+
+/*
+ * After fork, child runs first. (default) If set to 0 then
+ * parent will (try to) run first.
+ */
+const_debug unsigned int sysctl_sched_child_runs_first = 1;
 
 /*
  * Minimal preemption granularity for CPU-bound tasks:
  * (default: 2 msec, units: nanoseconds)
  */
-unsigned int sysctl_sched_min_granularity __read_mostly = 2000000ULL;
+const_debug unsigned int sysctl_sched_nr_latency = 20;
 
 /*
  * sys_sched_yield() compat mode
@@ -52,52 +56,25 @@ unsigned int __read_mostly sysctl_sched_compat_yield;
 
 /*
  * SCHED_BATCH wake-up granularity.
- * (default: 25 msec, units: nanoseconds)
+ * (default: 10 msec, units: nanoseconds)
  *
  * This option delays the preemption effects of decoupled workloads
  * and reduces their over-scheduling. Synchronous workloads will still
  * have immediate wakeup/sleep latencies.
  */
-unsigned int sysctl_sched_batch_wakeup_granularity __read_mostly = 25000000UL;
+const_debug unsigned int sysctl_sched_batch_wakeup_granularity = 10000000UL;
 
 /*
  * SCHED_OTHER wake-up granularity.
- * (default: 1 msec, units: nanoseconds)
+ * (default: 10 msec, units: nanoseconds)
  *
  * This option delays the preemption effects of decoupled workloads
  * and reduces their over-scheduling. Synchronous workloads will still
  * have immediate wakeup/sleep latencies.
  */
-unsigned int sysctl_sched_wakeup_granularity __read_mostly = 1000000UL;
-
-unsigned int sysctl_sched_stat_granularity __read_mostly;
-
-/*
- * Initialized in sched_init_granularity() [to 5 times the base granularity]:
- */
-unsigned int sysctl_sched_runtime_limit __read_mostly;
-
-/*
- * Debugging: various feature bits
- */
-enum {
-       SCHED_FEAT_FAIR_SLEEPERS        = 1,
-       SCHED_FEAT_SLEEPER_AVG          = 2,
-       SCHED_FEAT_SLEEPER_LOAD_AVG     = 4,
-       SCHED_FEAT_PRECISE_CPU_LOAD     = 8,
-       SCHED_FEAT_START_DEBIT          = 16,
-       SCHED_FEAT_SKIP_INITIAL         = 32,
-};
+const_debug unsigned int sysctl_sched_wakeup_granularity = 10000000UL;
 
-unsigned int sysctl_sched_features __read_mostly =
-               SCHED_FEAT_FAIR_SLEEPERS        *1 |
-               SCHED_FEAT_SLEEPER_AVG          *0 |
-               SCHED_FEAT_SLEEPER_LOAD_AVG     *1 |
-               SCHED_FEAT_PRECISE_CPU_LOAD     *1 |
-               SCHED_FEAT_START_DEBIT          *1 |
-               SCHED_FEAT_SKIP_INITIAL         *0;
-
-extern struct sched_class fair_sched_class;
+const_debug unsigned int sysctl_sched_migration_cost = 500000UL;
 
 /**************************************************************
  * CFS operations on generic schedulable entities:
@@ -111,21 +88,9 @@ static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
        return cfs_rq->rq;
 }
 
-/* currently running entity (if any) on this cfs_rq */
-static inline struct sched_entity *cfs_rq_curr(struct cfs_rq *cfs_rq)
-{
-       return cfs_rq->curr;
-}
-
 /* An entity is a task if it doesn't "own" a runqueue */
 #define entity_is_task(se)     (!se->my_q)
 
-static inline void
-set_cfs_rq_curr(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-       cfs_rq->curr = se;
-}
-
 #else  /* CONFIG_FAIR_GROUP_SCHED */
 
 static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
@@ -133,21 +98,8 @@ static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
        return container_of(cfs_rq, struct rq, cfs);
 }
 
-static inline struct sched_entity *cfs_rq_curr(struct cfs_rq *cfs_rq)
-{
-       struct rq *rq = rq_of(cfs_rq);
-
-       if (unlikely(rq->curr->sched_class != &fair_sched_class))
-               return NULL;
-
-       return &rq->curr->se;
-}
-
 #define entity_is_task(se)     1
 
-static inline void
-set_cfs_rq_curr(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
-
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 static inline struct task_struct *task_of(struct sched_entity *se)
@@ -160,16 +112,38 @@ static inline struct task_struct *task_of(struct sched_entity *se)
  * Scheduling class tree data structure manipulation methods:
  */
 
+static inline u64 max_vruntime(u64 min_vruntime, u64 vruntime)
+{
+       s64 delta = (s64)(vruntime - min_vruntime);
+       if (delta > 0)
+               min_vruntime = vruntime;
+
+       return min_vruntime;
+}
+
+static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime)
+{
+       s64 delta = (s64)(vruntime - min_vruntime);
+       if (delta < 0)
+               min_vruntime = vruntime;
+
+       return min_vruntime;
+}
+
+static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       return se->vruntime - cfs_rq->min_vruntime;
+}
+
 /*
  * Enqueue an entity into the rb-tree:
  */
-static inline void
-__enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
        struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
        struct rb_node *parent = NULL;
        struct sched_entity *entry;
-       s64 key = se->fair_key;
+       s64 key = entity_key(cfs_rq, se);
        int leftmost = 1;
 
        /*
@@ -182,7 +156,7 @@ __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
                 * We dont care about collisions. Nodes with
                 * the same key stay together.
                 */
-               if (key - entry->fair_key < 0) {
+               if (key < entity_key(cfs_rq, entry)) {
                        link = &parent->rb_left;
                } else {
                        link = &parent->rb_right;
@@ -199,24 +173,14 @@ __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 
        rb_link_node(&se->run_node, parent, link);
        rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
-       update_load_add(&cfs_rq->load, se->load.weight);
-       cfs_rq->nr_running++;
-       se->on_rq = 1;
-
-       schedstat_add(cfs_rq, wait_runtime, se->wait_runtime);
 }
 
-static inline void
-__dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
        if (cfs_rq->rb_leftmost == &se->run_node)
                cfs_rq->rb_leftmost = rb_next(&se->run_node);
-       rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
-       update_load_sub(&cfs_rq->load, se->load.weight);
-       cfs_rq->nr_running--;
-       se->on_rq = 0;
 
-       schedstat_add(cfs_rq, wait_runtime, -se->wait_runtime);
+       rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
 }
 
 static inline struct rb_node *first_fair(struct cfs_rq *cfs_rq)
@@ -229,118 +193,86 @@ static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
        return rb_entry(first_fair(cfs_rq), struct sched_entity, run_node);
 }
 
+static inline struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
+{
+       struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
+       struct sched_entity *se = NULL;
+       struct rb_node *parent;
+
+       while (*link) {
+               parent = *link;
+               se = rb_entry(parent, struct sched_entity, run_node);
+               link = &parent->rb_right;
+       }
+
+       return se;
+}
+
 /**************************************************************
  * Scheduling class statistics methods:
  */
 
+
 /*
- * Calculate the preemption granularity needed to schedule every
- * runnable task once per sysctl_sched_latency amount of time.
- * (down to a sensible low limit on granularity)
- *
- * For example, if there are 2 tasks running and latency is 10 msecs,
- * we switch tasks every 5 msecs. If we have 3 tasks running, we have
- * to switch tasks every 3.33 msecs to get a 10 msecs observed latency
- * for each task. We do finer and finer scheduling up to until we
- * reach the minimum granularity value.
- *
- * To achieve this we use the following dynamic-granularity rule:
+ * The idea is to set a period in which each task runs once.
  *
- *    gran = lat/nr - lat/nr/nr
+ * When there are too many tasks (sysctl_sched_nr_latency) we have to stretch
+ * this period because otherwise the slices get too small.
  *
- * This comes out of the following equations:
- *
- *    kA1 + gran = kB1
- *    kB2 + gran = kA2
- *    kA2 = kA1
- *    kB2 = kB1 - d + d/nr
- *    lat = d * nr
- *
- * Where 'k' is key, 'A' is task A (waiting), 'B' is task B (running),
- * '1' is start of time, '2' is end of time, 'd' is delay between
- * 1 and 2 (during which task B was running), 'nr' is number of tasks
- * running, 'lat' is the the period of each task. ('lat' is the
- * sched_latency that we aim for.)
+ * p = (nr <= nl) ? l : l*nr/nl
  */
-static long
-sched_granularity(struct cfs_rq *cfs_rq)
+static u64 __sched_period(unsigned long nr_running)
 {
-       unsigned int gran = sysctl_sched_latency;
-       unsigned int nr = cfs_rq->nr_running;
+       u64 period = sysctl_sched_latency;
+       unsigned long nr_latency = sysctl_sched_nr_latency;
 
-       if (nr > 1) {
-               gran = gran/nr - gran/nr/nr;
-               gran = max(gran, sysctl_sched_min_granularity);
+       if (unlikely(nr_running > nr_latency)) {
+               period *= nr_running;
+               do_div(period, nr_latency);
        }
 
-       return gran;
+       return period;
 }
 
 /*
- * We rescale the rescheduling granularity of tasks according to their
- * nice level, but only linearly, not exponentially:
+ * We calculate the wall-time slice from the period by taking a part
+ * proportional to the weight.
+ *
+ * s = p*w/rw
  */
-static long
-niced_granularity(struct sched_entity *curr, unsigned long granularity)
+static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       u64 tmp;
+       u64 slice = __sched_period(cfs_rq->nr_running);
 
-       if (likely(curr->load.weight == NICE_0_LOAD))
-               return granularity;
-       /*
-        * Positive nice levels get the same granularity as nice-0:
-        */
-       if (likely(curr->load.weight < NICE_0_LOAD)) {
-               tmp = curr->load.weight * (u64)granularity;
-               return (long) (tmp >> NICE_0_SHIFT);
-       }
-       /*
-        * Negative nice level tasks get linearly finer
-        * granularity:
-        */
-       tmp = curr->load.inv_weight * (u64)granularity;
+       slice *= se->load.weight;
+       do_div(slice, cfs_rq->load.weight);
 
-       /*
-        * It will always fit into 'long':
-        */
-       return (long) (tmp >> (WMULT_SHIFT-NICE_0_SHIFT));
+       return slice;
 }
 
-static inline void
-limit_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se)
+/*
+ * We calculate the vruntime slice.
+ *
+ * vs = s/w = p/rw
+ */
+static u64 __sched_vslice(unsigned long rq_weight, unsigned long nr_running)
 {
-       long limit = sysctl_sched_runtime_limit;
+       u64 vslice = __sched_period(nr_running);
 
-       /*
-        * Niced tasks have the same history dynamic range as
-        * non-niced tasks:
-        */
-       if (unlikely(se->wait_runtime > limit)) {
-               se->wait_runtime = limit;
-               schedstat_inc(se, wait_runtime_overruns);
-               schedstat_inc(cfs_rq, wait_runtime_overruns);
-       }
-       if (unlikely(se->wait_runtime < -limit)) {
-               se->wait_runtime = -limit;
-               schedstat_inc(se, wait_runtime_underruns);
-               schedstat_inc(cfs_rq, wait_runtime_underruns);
-       }
+       do_div(vslice, rq_weight);
+
+       return vslice;
 }
 
-static inline void
-__add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
+static u64 sched_vslice(struct cfs_rq *cfs_rq)
 {
-       se->wait_runtime += delta;
-       schedstat_add(se, sum_wait_runtime, delta);
-       limit_wait_runtime(cfs_rq, se);
+       return __sched_vslice(cfs_rq->load.weight, cfs_rq->nr_running);
 }
 
-static void
-add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
+static u64 sched_vslice_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       schedstat_add(cfs_rq, wait_runtime, -se->wait_runtime);
-       __add_wait_runtime(cfs_rq, se, delta);
-       schedstat_add(cfs_rq, wait_runtime, se->wait_runtime);
+       return __sched_vslice(cfs_rq->load.weight + se->load.weight,
+                       cfs_rq->nr_running + 1);
 }
 
 /*
@@ -348,46 +280,41 @@ add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
  * are not in our scheduling class.
  */
 static inline void
-__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr)
+__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
+             unsigned long delta_exec)
 {
-       unsigned long delta, delta_exec, delta_fair, delta_mine;
-       struct load_weight *lw = &cfs_rq->load;
-       unsigned long load = lw->weight;
+       unsigned long delta_exec_weighted;
+       u64 vruntime;
 
-       delta_exec = curr->delta_exec;
        schedstat_set(curr->exec_max, max((u64)delta_exec, curr->exec_max));
 
        curr->sum_exec_runtime += delta_exec;
-       cfs_rq->exec_clock += delta_exec;
-
-       if (unlikely(!load))
-               return;
-
-       delta_fair = calc_delta_fair(delta_exec, lw);
-       delta_mine = calc_delta_mine(delta_exec, curr->load.weight, lw);
-
-       if (cfs_rq->sleeper_bonus > sysctl_sched_min_granularity) {
-               delta = min((u64)delta_mine, cfs_rq->sleeper_bonus);
-               delta = min(delta, (unsigned long)(
-                       (long)sysctl_sched_runtime_limit - curr->wait_runtime));
-               cfs_rq->sleeper_bonus -= delta;
-               delta_mine -= delta;
+       schedstat_add(cfs_rq, exec_clock, delta_exec);
+       delta_exec_weighted = delta_exec;
+       if (unlikely(curr->load.weight != NICE_0_LOAD)) {
+               delta_exec_weighted = calc_delta_fair(delta_exec_weighted,
+                                                       &curr->load);
        }
+       curr->vruntime += delta_exec_weighted;
 
-       cfs_rq->fair_clock += delta_fair;
        /*
-        * We executed delta_exec amount of time on the CPU,
-        * but we were only entitled to delta_mine amount of
-        * time during that period (if nr_running == 1 then
-        * the two values are equal)
-        * [Note: delta_mine - delta_exec is negative]:
+        * maintain cfs_rq->min_vruntime to be a monotonic increasing
+        * value tracking the leftmost vruntime in the tree.
         */
-       add_wait_runtime(cfs_rq, curr, delta_mine - delta_exec);
+       if (first_fair(cfs_rq)) {
+               vruntime = min_vruntime(curr->vruntime,
+                               __pick_next_entity(cfs_rq)->vruntime);
+       } else
+               vruntime = curr->vruntime;
+
+       cfs_rq->min_vruntime =
+               max_vruntime(cfs_rq->min_vruntime, vruntime);
 }
 
 static void update_curr(struct cfs_rq *cfs_rq)
 {
-       struct sched_entity *curr = cfs_rq_curr(cfs_rq);
+       struct sched_entity *curr = cfs_rq->curr;
+       u64 now = rq_of(cfs_rq)->clock;
        unsigned long delta_exec;
 
        if (unlikely(!curr))
@@ -398,135 +325,47 @@ static void update_curr(struct cfs_rq *cfs_rq)
         * since the last time we changed load (this cannot
         * overflow on 32 bits):
         */
-       delta_exec = (unsigned long)(rq_of(cfs_rq)->clock - curr->exec_start);
+       delta_exec = (unsigned long)(now - curr->exec_start);
 
-       curr->delta_exec += delta_exec;
-
-       if (unlikely(curr->delta_exec > sysctl_sched_stat_granularity)) {
-               __update_curr(cfs_rq, curr);
-               curr->delta_exec = 0;
-       }
-       curr->exec_start = rq_of(cfs_rq)->clock;
+       __update_curr(cfs_rq, curr, delta_exec);
+       curr->exec_start = now;
 }
 
 static inline void
 update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       se->wait_start_fair = cfs_rq->fair_clock;
        schedstat_set(se->wait_start, rq_of(cfs_rq)->clock);
 }
 
-/*
- * We calculate fair deltas here, so protect against the random effects
- * of a multiplication overflow by capping it to the runtime limit:
- */
-#if BITS_PER_LONG == 32
-static inline unsigned long
-calc_weighted(unsigned long delta, unsigned long weight, int shift)
-{
-       u64 tmp = (u64)delta * weight >> shift;
-
-       if (unlikely(tmp > sysctl_sched_runtime_limit*2))
-               return sysctl_sched_runtime_limit*2;
-       return tmp;
-}
-#else
-static inline unsigned long
-calc_weighted(unsigned long delta, unsigned long weight, int shift)
-{
-       return delta * weight >> shift;
-}
-#endif
-
 /*
  * Task is being enqueued - update stats:
  */
 static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       s64 key;
-
        /*
         * Are we enqueueing a waiting task? (for current tasks
         * a dequeue/enqueue event is a NOP)
         */
-       if (se != cfs_rq_curr(cfs_rq))
+       if (se != cfs_rq->curr)
                update_stats_wait_start(cfs_rq, se);
-       /*
-        * Update the key:
-        */
-       key = cfs_rq->fair_clock;
-
-       /*
-        * Optimize the common nice 0 case:
-        */
-       if (likely(se->load.weight == NICE_0_LOAD)) {
-               key -= se->wait_runtime;
-       } else {
-               u64 tmp;
-
-               if (se->wait_runtime < 0) {
-                       tmp = -se->wait_runtime;
-                       key += (tmp * se->load.inv_weight) >>
-                                       (WMULT_SHIFT - NICE_0_SHIFT);
-               } else {
-                       tmp = se->wait_runtime;
-                       key -= (tmp * se->load.inv_weight) >>
-                                       (WMULT_SHIFT - NICE_0_SHIFT);
-               }
-       }
-
-       se->fair_key = key;
-}
-
-/*
- * Note: must be called with a freshly updated rq->fair_clock.
- */
-static inline void
-__update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-       unsigned long delta_fair = se->delta_fair_run;
-
-       schedstat_set(se->wait_max, max(se->wait_max,
-                       rq_of(cfs_rq)->clock - se->wait_start));
-
-       if (unlikely(se->load.weight != NICE_0_LOAD))
-               delta_fair = calc_weighted(delta_fair, se->load.weight,
-                                                       NICE_0_SHIFT);
-
-       add_wait_runtime(cfs_rq, se, delta_fair);
 }
 
 static void
 update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       unsigned long delta_fair;
-
-       if (unlikely(!se->wait_start_fair))
-               return;
-
-       delta_fair = (unsigned long)min((u64)(2*sysctl_sched_runtime_limit),
-                       (u64)(cfs_rq->fair_clock - se->wait_start_fair));
-
-       se->delta_fair_run += delta_fair;
-       if (unlikely(abs(se->delta_fair_run) >=
-                               sysctl_sched_stat_granularity)) {
-               __update_stats_wait_end(cfs_rq, se);
-               se->delta_fair_run = 0;
-       }
-
-       se->wait_start_fair = 0;
+       schedstat_set(se->wait_max, max(se->wait_max,
+                       rq_of(cfs_rq)->clock - se->wait_start));
        schedstat_set(se->wait_start, 0);
 }
 
 static inline void
 update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       update_curr(cfs_rq);
        /*
         * Mark the end of the wait period if dequeueing a
         * waiting task:
         */
-       if (se != cfs_rq_curr(cfs_rq))
+       if (se != cfs_rq->curr)
                update_stats_wait_end(cfs_rq, se);
 }
 
@@ -542,79 +381,28 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
        se->exec_start = rq_of(cfs_rq)->clock;
 }
 
-/*
- * We are descheduling a task - update its stats:
- */
-static inline void
-update_stats_curr_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-       se->exec_start = 0;
-}
-
 /**************************************************
  * Scheduling class queueing methods:
  */
 
-static void __enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static void
+account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       unsigned long load = cfs_rq->load.weight, delta_fair;
-       long prev_runtime;
-
-       /*
-        * Do not boost sleepers if there's too much bonus 'in flight'
-        * already:
-        */
-       if (unlikely(cfs_rq->sleeper_bonus > sysctl_sched_runtime_limit))
-               return;
-
-       if (sysctl_sched_features & SCHED_FEAT_SLEEPER_LOAD_AVG)
-               load = rq_of(cfs_rq)->cpu_load[2];
-
-       delta_fair = se->delta_fair_sleep;
-
-       /*
-        * Fix up delta_fair with the effect of us running
-        * during the whole sleep period:
-        */
-       if (sysctl_sched_features & SCHED_FEAT_SLEEPER_AVG)
-               delta_fair = div64_likely32((u64)delta_fair * load,
-                                               load + se->load.weight);
-
-       if (unlikely(se->load.weight != NICE_0_LOAD))
-               delta_fair = calc_weighted(delta_fair, se->load.weight,
-                                                       NICE_0_SHIFT);
-
-       prev_runtime = se->wait_runtime;
-       __add_wait_runtime(cfs_rq, se, delta_fair);
-       delta_fair = se->wait_runtime - prev_runtime;
+       update_load_add(&cfs_rq->load, se->load.weight);
+       cfs_rq->nr_running++;
+       se->on_rq = 1;
+}
 
-       /*
-        * Track the amount of bonus we've given to sleepers:
-        */
-       cfs_rq->sleeper_bonus += delta_fair;
+static void
+account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       update_load_sub(&cfs_rq->load, se->load.weight);
+       cfs_rq->nr_running--;
+       se->on_rq = 0;
 }
 
 static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       struct task_struct *tsk = task_of(se);
-       unsigned long delta_fair;
-
-       if ((entity_is_task(se) && tsk->policy == SCHED_BATCH) ||
-                        !(sysctl_sched_features & SCHED_FEAT_FAIR_SLEEPERS))
-               return;
-
-       delta_fair = (unsigned long)min((u64)(2*sysctl_sched_runtime_limit),
-               (u64)(cfs_rq->fair_clock - se->sleep_start_fair));
-
-       se->delta_fair_sleep += delta_fair;
-       if (unlikely(abs(se->delta_fair_sleep) >=
-                               sysctl_sched_stat_granularity)) {
-               __enqueue_sleeper(cfs_rq, se);
-               se->delta_fair_sleep = 0;
-       }
-
-       se->sleep_start_fair = 0;
-
 #ifdef CONFIG_SCHEDSTATS
        if (se->sleep_start) {
                u64 delta = rq_of(cfs_rq)->clock - se->sleep_start;
@@ -646,6 +434,8 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
                 * time that the task spent sleeping:
                 */
                if (unlikely(prof_on == SLEEP_PROFILING)) {
+                       struct task_struct *tsk = task_of(se);
+
                        profile_hits(SLEEP_PROFILING, (void *)get_wchan(tsk),
                                     delta >> 20);
                }
@@ -653,27 +443,81 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
 #endif
 }
 
+static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+#ifdef CONFIG_SCHED_DEBUG
+       s64 d = se->vruntime - cfs_rq->min_vruntime;
+
+       if (d < 0)
+               d = -d;
+
+       if (d > 3*sysctl_sched_latency)
+               schedstat_inc(cfs_rq, nr_spread_over);
+#endif
+}
+
+static void
+place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
+{
+       u64 vruntime;
+
+       vruntime = cfs_rq->min_vruntime;
+
+       if (sched_feat(TREE_AVG)) {
+               struct sched_entity *last = __pick_last_entity(cfs_rq);
+               if (last) {
+                       vruntime += last->vruntime;
+                       vruntime >>= 1;
+               }
+       } else if (sched_feat(APPROX_AVG) && cfs_rq->nr_running)
+               vruntime += sched_vslice(cfs_rq)/2;
+
+       if (initial && sched_feat(START_DEBIT))
+               vruntime += sched_vslice_add(cfs_rq, se);
+
+       if (!initial) {
+               if (sched_feat(NEW_FAIR_SLEEPERS) && entity_is_task(se) &&
+                               task_of(se)->policy != SCHED_BATCH)
+                       vruntime -= sysctl_sched_latency;
+
+               vruntime = max_t(s64, vruntime, se->vruntime);
+       }
+
+       se->vruntime = vruntime;
+
+}
+
 static void
 enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int wakeup)
 {
        /*
-        * Update the fair clock.
+        * Update run-time statistics of the 'current'.
         */
        update_curr(cfs_rq);
 
-       if (wakeup)
+       if (wakeup) {
+               place_entity(cfs_rq, se, 0);
                enqueue_sleeper(cfs_rq, se);
+       }
 
        update_stats_enqueue(cfs_rq, se);
-       __enqueue_entity(cfs_rq, se);
+       check_spread(cfs_rq, se);
+       if (se != cfs_rq->curr)
+               __enqueue_entity(cfs_rq, se);
+       account_entity_enqueue(cfs_rq, se);
 }
 
 static void
 dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep)
 {
+       /*
+        * Update run-time statistics of the 'current'.
+        */
+       update_curr(cfs_rq);
+
        update_stats_dequeue(cfs_rq, se);
        if (sleep) {
-               se->sleep_start_fair = cfs_rq->fair_clock;
+               se->peer_preempt = 0;
 #ifdef CONFIG_SCHEDSTATS
                if (entity_is_task(se)) {
                        struct task_struct *tsk = task_of(se);
@@ -685,68 +529,66 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep)
                }
 #endif
        }
-       __dequeue_entity(cfs_rq, se);
+
+       if (se != cfs_rq->curr)
+               __dequeue_entity(cfs_rq, se);
+       account_entity_dequeue(cfs_rq, se);
 }
 
 /*
  * Preempt the current task with a newly woken task if needed:
  */
 static void
-__check_preempt_curr_fair(struct cfs_rq *cfs_rq, struct sched_entity *se,
-                         struct sched_entity *curr, unsigned long granularity)
+check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
 {
-       s64 __delta = curr->fair_key - se->fair_key;
        unsigned long ideal_runtime, delta_exec;
 
-       /*
-        * ideal_runtime is compared against sum_exec_runtime, which is
-        * walltime, hence do not scale.
-        */
-       ideal_runtime = max(sysctl_sched_latency / cfs_rq->nr_running,
-                       (unsigned long)sysctl_sched_min_granularity);
-
-       /*
-        * If we executed more than what the latency constraint suggests,
-        * reduce the rescheduling granularity. This way the total latency
-        * of how much a task is not scheduled converges to
-        * sysctl_sched_latency:
-        */
+       ideal_runtime = sched_slice(cfs_rq, curr);
        delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
-       if (delta_exec > ideal_runtime)
-               granularity = 0;
-
-       /*
-        * Take scheduling granularity into account - do not
-        * preempt the current task unless the best task has
-        * a larger than sched_granularity fairness advantage:
-        *
-        * scale granularity as key space is in fair_clock.
-        */
-       if (__delta > niced_granularity(curr, granularity))
+       if (delta_exec > ideal_runtime ||
+                       (sched_feat(PREEMPT_RESTRICT) && curr->peer_preempt))
                resched_task(rq_of(cfs_rq)->curr);
+       curr->peer_preempt = 0;
 }
 
-static inline void
+static void
 set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
+       /* 'current' is not kept within the tree. */
+       if (se->on_rq) {
+               /*
+                * Any task has to be enqueued before it get to execute on
+                * a CPU. So account for the time it spent waiting on the
+                * runqueue.
+                */
+               update_stats_wait_end(cfs_rq, se);
+               __dequeue_entity(cfs_rq, se);
+       }
+
+       update_stats_curr_start(cfs_rq, se);
+       cfs_rq->curr = se;
+#ifdef CONFIG_SCHEDSTATS
        /*
-        * Any task has to be enqueued before it get to execute on
-        * a CPU. So account for the time it spent waiting on the
-        * runqueue. (note, here we rely on pick_next_task() having
-        * done a put_prev_task_fair() shortly before this, which
-        * updated rq->fair_clock - used by update_stats_wait_end())
+        * Track our maximum slice length, if the CPU's load is at
+        * least twice that of our own weight (i.e. dont track it
+        * when there are only lesser-weight tasks around):
         */
-       update_stats_wait_end(cfs_rq, se);
-       update_stats_curr_start(cfs_rq, se);
-       set_cfs_rq_curr(cfs_rq, se);
+       if (rq_of(cfs_rq)->load.weight >= 2*se->load.weight) {
+               se->slice_max = max(se->slice_max,
+                       se->sum_exec_runtime - se->prev_sum_exec_runtime);
+       }
+#endif
        se->prev_sum_exec_runtime = se->sum_exec_runtime;
 }
 
 static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
 {
-       struct sched_entity *se = __pick_next_entity(cfs_rq);
+       struct sched_entity *se = NULL;
 
-       set_next_entity(cfs_rq, se);
+       if (first_fair(cfs_rq)) {
+               se = __pick_next_entity(cfs_rq);
+               set_next_entity(cfs_rq, se);
+       }
 
        return se;
 }
@@ -760,33 +602,24 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
        if (prev->on_rq)
                update_curr(cfs_rq);
 
-       update_stats_curr_end(cfs_rq, prev);
-
-       if (prev->on_rq)
+       check_spread(cfs_rq, prev);
+       if (prev->on_rq) {
                update_stats_wait_start(cfs_rq, prev);
-       set_cfs_rq_curr(cfs_rq, NULL);
+               /* Put 'current' back into the tree. */
+               __enqueue_entity(cfs_rq, prev);
+       }
+       cfs_rq->curr = NULL;
 }
 
 static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
 {
-       struct sched_entity *next;
-
        /*
-        * Dequeue and enqueue the task to update its
-        * position within the tree:
+        * Update run-time statistics of the 'current'.
         */
-       dequeue_entity(cfs_rq, curr, 0);
-       enqueue_entity(cfs_rq, curr, 0);
-
-       /*
-        * Reschedule if another task tops the current one.
-        */
-       next = __pick_next_entity(cfs_rq);
-       if (next == curr)
-               return;
+       update_curr(cfs_rq);
 
-       __check_preempt_curr_fair(cfs_rq, next, curr,
-                       sched_granularity(cfs_rq));
+       if (cfs_rq->nr_running > 1 || !sched_feat(WAKEUP_PREEMPT))
+               check_preempt_tick(cfs_rq, curr);
 }
 
 /**************************************************
@@ -821,23 +654,28 @@ static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
  */
 static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
 {
-       /* A later patch will take group into account */
-       return &cpu_rq(this_cpu)->cfs;
+       return cfs_rq->tg->cfs_rq[this_cpu];
 }
 
 /* Iterate thr' all leaf cfs_rq's on a runqueue */
 #define for_each_leaf_cfs_rq(rq, cfs_rq) \
        list_for_each_entry(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
 
-/* Do the two (enqueued) tasks belong to the same group ? */
-static inline int is_same_group(struct task_struct *curr, struct task_struct *p)
+/* Do the two (enqueued) entities belong to the same group ? */
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
 {
-       if (curr->se.cfs_rq == p->se.cfs_rq)
+       if (se->cfs_rq == pse->cfs_rq)
                return 1;
 
        return 0;
 }
 
+static inline struct sched_entity *parent_entity(struct sched_entity *se)
+{
+       return se->parent;
+}
+
 #else  /* CONFIG_FAIR_GROUP_SCHED */
 
 #define for_each_sched_entity(se) \
@@ -870,11 +708,17 @@ static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
 #define for_each_leaf_cfs_rq(rq, cfs_rq) \
                for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
 
-static inline int is_same_group(struct task_struct *curr, struct task_struct *p)
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
 {
        return 1;
 }
 
+static inline struct sched_entity *parent_entity(struct sched_entity *se)
+{
+       return NULL;
+}
+
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 /*
@@ -892,6 +736,7 @@ static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup)
                        break;
                cfs_rq = cfs_rq_of(se);
                enqueue_entity(cfs_rq, se, wakeup);
+               wakeup = 1;
        }
 }
 
@@ -911,6 +756,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep)
                /* Don't dequeue parent if it has other entities besides us */
                if (cfs_rq->load.weight)
                        break;
+               sleep = 1;
        }
 }
 
@@ -919,12 +765,10 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep)
  *
  * If compat_yield is turned on then we requeue to the end of the tree.
  */
-static void yield_task_fair(struct rq *rq, struct task_struct *p)
+static void yield_task_fair(struct rq *rq)
 {
-       struct cfs_rq *cfs_rq = task_cfs_rq(p);
-       struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
-       struct sched_entity *rightmost, *se = &p->se;
-       struct rb_node *parent;
+       struct cfs_rq *cfs_rq = task_cfs_rq(rq->curr);
+       struct sched_entity *rightmost, *se = &rq->curr->se;
 
        /*
         * Are we the only task in the tree?
@@ -935,52 +779,39 @@ static void yield_task_fair(struct rq *rq, struct task_struct *p)
        if (likely(!sysctl_sched_compat_yield)) {
                __update_rq_clock(rq);
                /*
-                * Dequeue and enqueue the task to update its
-                * position within the tree:
+                * Update run-time statistics of the 'current'.
                 */
-               dequeue_entity(cfs_rq, &p->se, 0);
-               enqueue_entity(cfs_rq, &p->se, 0);
+               update_curr(cfs_rq);
 
                return;
        }
        /*
         * Find the rightmost entry in the rbtree:
         */
-       do {
-               parent = *link;
-               link = &parent->rb_right;
-       } while (*link);
-
-       rightmost = rb_entry(parent, struct sched_entity, run_node);
+       rightmost = __pick_last_entity(cfs_rq);
        /*
         * Already in the rightmost position?
         */
-       if (unlikely(rightmost == se))
+       if (unlikely(rightmost->vruntime < se->vruntime))
                return;
 
        /*
         * Minimally necessary key value to be last in the tree:
+        * Upon rescheduling, sched_class::put_prev_task() will place
+        * 'current' within the tree based on its new key value.
         */
-       se->fair_key = rightmost->fair_key + 1;
-
-       if (cfs_rq->rb_leftmost == &se->run_node)
-               cfs_rq->rb_leftmost = rb_next(&se->run_node);
-       /*
-        * Relink the task to the rightmost position:
-        */
-       rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
-       rb_link_node(&se->run_node, parent, link);
-       rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
+       se->vruntime = rightmost->vruntime + 1;
 }
 
 /*
  * Preempt the current task with a newly woken task if needed:
  */
-static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p)
+static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
 {
        struct task_struct *curr = rq->curr;
        struct cfs_rq *cfs_rq = task_cfs_rq(curr);
-       unsigned long gran;
+       struct sched_entity *se = &curr->se, *pse = &p->se;
+       s64 delta, gran;
 
        if (unlikely(rt_prio(p->prio))) {
                update_rq_clock(rq);
@@ -988,16 +819,31 @@ static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p)
                resched_task(curr);
                return;
        }
-
-       gran = sysctl_sched_wakeup_granularity;
        /*
-        * Batch tasks prefer throughput over latency:
+        * Batch tasks do not preempt (their preemption is driven by
+        * the tick):
         */
        if (unlikely(p->policy == SCHED_BATCH))
-               gran = sysctl_sched_batch_wakeup_granularity;
+               return;
+
+       if (sched_feat(WAKEUP_PREEMPT)) {
+               while (!is_same_group(se, pse)) {
+                       se = parent_entity(se);
+                       pse = parent_entity(pse);
+               }
 
-       if (is_same_group(curr, p))
-               __check_preempt_curr_fair(cfs_rq, &p->se, &curr->se, gran);
+               delta = se->vruntime - pse->vruntime;
+               gran = sysctl_sched_wakeup_granularity;
+               if (unlikely(se->load.weight != NICE_0_LOAD))
+                       gran = calc_delta_fair(gran, &se->load);
+
+               if (delta > gran) {
+                       int now = !sched_feat(PREEMPT_RESTRICT);
+
+                       if (now || p->prio < curr->prio || !se->peer_preempt++)
+                               resched_task(curr);
+               }
+       }
 }
 
 static struct task_struct *pick_next_task_fair(struct rq *rq)
@@ -1041,7 +887,7 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
  * achieve that by always pre-iterating before returning
  * the current task:
  */
-static inline struct task_struct *
+static struct task_struct *
 __load_balance_iterator(struct cfs_rq *cfs_rq, struct rb_node *curr)
 {
        struct task_struct *p;
@@ -1078,7 +924,10 @@ static int cfs_rq_best_prio(struct cfs_rq *cfs_rq)
        if (!cfs_rq->nr_running)
                return MAX_PRIO;
 
-       curr = __pick_next_entity(cfs_rq);
+       curr = cfs_rq->curr;
+       if (!curr)
+               curr = __pick_next_entity(cfs_rq);
+
        p = task_of(curr);
 
        return p->prio;
@@ -1153,6 +1002,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr)
        }
 }
 
+#define swap(a,b) do { typeof(a) tmp = (a); (a) = (b); (b) = tmp; } while (0)
+
 /*
  * Share the fairness runtime between parent and child, thus the
  * total amount of pressure for CPU stays equal - new tasks
@@ -1163,37 +1014,32 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr)
 static void task_new_fair(struct rq *rq, struct task_struct *p)
 {
        struct cfs_rq *cfs_rq = task_cfs_rq(p);
-       struct sched_entity *se = &p->se, *curr = cfs_rq_curr(cfs_rq);
+       struct sched_entity *se = &p->se, *curr = cfs_rq->curr;
+       int this_cpu = smp_processor_id();
 
        sched_info_queued(p);
 
        update_curr(cfs_rq);
-       update_stats_enqueue(cfs_rq, se);
-       /*
-        * Child runs first: we let it run before the parent
-        * until it reschedules once. We set up the key so that
-        * it will preempt the parent:
-        */
-       se->fair_key = curr->fair_key -
-               niced_granularity(curr, sched_granularity(cfs_rq)) - 1;
-       /*
-        * The first wait is dominated by the child-runs-first logic,
-        * so do not credit it with that waiting time yet:
-        */
-       if (sysctl_sched_features & SCHED_FEAT_SKIP_INITIAL)
-               se->wait_start_fair = 0;
+       place_entity(cfs_rq, se, 1);
 
-       /*
-        * The statistical average of wait_runtime is about
-        * -granularity/2, so initialize the task with that:
-        */
-       if (sysctl_sched_features & SCHED_FEAT_START_DEBIT)
-               se->wait_runtime = -(sched_granularity(cfs_rq) / 2);
+       if (sysctl_sched_child_runs_first && this_cpu == task_cpu(p) &&
+                       curr->vruntime < se->vruntime) {
+               /*
+                * Upon rescheduling, sched_class::put_prev_task() will place
+                * 'current' within the tree based on its new key value.
+                */
+               swap(curr->vruntime, se->vruntime);
+       }
 
+       update_stats_enqueue(cfs_rq, se);
+       check_spread(cfs_rq, se);
+       check_spread(cfs_rq, curr);
        __enqueue_entity(cfs_rq, se);
+       account_entity_enqueue(cfs_rq, se);
+       se->peer_preempt = 0;
+       resched_task(rq->curr);
 }
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
 /* Account for a task changing its policy or group.
  *
  * This routine is mostly called to set cfs_rq->curr field when a task
@@ -1206,21 +1052,17 @@ static void set_curr_task_fair(struct rq *rq)
        for_each_sched_entity(se)
                set_next_entity(cfs_rq_of(se), se);
 }
-#else
-static void set_curr_task_fair(struct rq *rq)
-{
-}
-#endif
 
 /*
  * All the scheduling class methods:
  */
-struct sched_class fair_sched_class __read_mostly = {
+static const struct sched_class fair_sched_class = {
+       .next                   = &idle_sched_class,
        .enqueue_task           = enqueue_task_fair,
        .dequeue_task           = dequeue_task_fair,
        .yield_task             = yield_task_fair,
 
-       .check_preempt_curr     = check_preempt_curr_fair,
+       .check_preempt_curr     = check_preempt_wakeup,
 
        .pick_next_task         = pick_next_task_fair,
        .put_prev_task          = put_prev_task_fair,
@@ -1237,6 +1079,9 @@ static void print_cfs_stats(struct seq_file *m, int cpu)
 {
        struct cfs_rq *cfs_rq;
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       print_cfs_rq(m, cpu, &cpu_rq(cpu)->cfs);
+#endif
        for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
                print_cfs_rq(m, cpu, cfs_rq);
 }
index 3503fb2d9f96caa0ee690ddbfaa722a573997ec0..6e2ead41516ee5bb7631b31e77ecd84f3922eb6a 100644 (file)
@@ -50,10 +50,15 @@ static void task_tick_idle(struct rq *rq, struct task_struct *curr)
 {
 }
 
+static void set_curr_task_idle(struct rq *rq)
+{
+}
+
 /*
  * Simple, special scheduling class for the per-CPU idle tasks:
  */
-static struct sched_class idle_sched_class __read_mostly = {
+const struct sched_class idle_sched_class = {
+       /* .next is NULL */
        /* no enqueue/yield_task for idle tasks */
 
        /* dequeue is not valid, we print a debug message there: */
@@ -66,6 +71,7 @@ static struct sched_class idle_sched_class __read_mostly = {
 
        .load_balance           = load_balance_idle,
 
+       .set_curr_task          = set_curr_task_idle,
        .task_tick              = task_tick_idle,
        /* no .task_new for idle tasks */
 };
index 4b87476a02d0fec53239c896c8f2b210964b8f92..d0097a0634e54f3dfcce71da006359c6d22d5b01 100644 (file)
@@ -7,7 +7,7 @@
  * Update the current task's runtime statistics. Skip current tasks that
  * are not in our scheduling class.
  */
-static inline void update_curr_rt(struct rq *rq)
+static void update_curr_rt(struct rq *rq)
 {
        struct task_struct *curr = rq->curr;
        u64 delta_exec;
@@ -59,9 +59,9 @@ static void requeue_task_rt(struct rq *rq, struct task_struct *p)
 }
 
 static void
-yield_task_rt(struct rq *rq, struct task_struct *p)
+yield_task_rt(struct rq *rq)
 {
-       requeue_task_rt(rq, p);
+       requeue_task_rt(rq, rq->curr);
 }
 
 /*
@@ -206,7 +206,7 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p)
        if (--p->time_slice)
                return;
 
-       p->time_slice = static_prio_timeslice(p->static_prio);
+       p->time_slice = DEF_TIMESLICE;
 
        /*
         * Requeue to the end of queue if we are not the only element
@@ -218,7 +218,15 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p)
        }
 }
 
-static struct sched_class rt_sched_class __read_mostly = {
+static void set_curr_task_rt(struct rq *rq)
+{
+       struct task_struct *p = rq->curr;
+
+       p->se.exec_start = rq->clock;
+}
+
+const struct sched_class rt_sched_class = {
+       .next                   = &fair_sched_class,
        .enqueue_task           = enqueue_task_rt,
        .dequeue_task           = dequeue_task_rt,
        .yield_task             = yield_task_rt,
@@ -230,5 +238,6 @@ static struct sched_class rt_sched_class __read_mostly = {
 
        .load_balance           = load_balance_rt,
 
+       .set_curr_task          = set_curr_task_rt,
        .task_tick              = task_tick_rt,
 };
index c20a94dda61e71c0014fc8945ba6349657e90f9a..1c084842c3e75517b7cbbdcb2f665b0dfe8f56dd 100644 (file)
@@ -16,18 +16,18 @@ static int show_schedstat(struct seq_file *seq, void *v)
                struct rq *rq = cpu_rq(cpu);
 #ifdef CONFIG_SMP
                struct sched_domain *sd;
-               int dcnt = 0;
+               int dcount = 0;
 #endif
 
                /* runqueue-specific stats */
                seq_printf(seq,
                    "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %llu %llu %lu",
                    cpu, rq->yld_both_empty,
-                   rq->yld_act_empty, rq->yld_exp_empty, rq->yld_cnt,
-                   rq->sched_switch, rq->sched_cnt, rq->sched_goidle,
-                   rq->ttwu_cnt, rq->ttwu_local,
+                   rq->yld_act_empty, rq->yld_exp_empty, rq->yld_count,
+                   rq->sched_switch, rq->sched_count, rq->sched_goidle,
+                   rq->ttwu_count, rq->ttwu_local,
                    rq->rq_sched_info.cpu_time,
-                   rq->rq_sched_info.run_delay, rq->rq_sched_info.pcnt);
+                   rq->rq_sched_info.run_delay, rq->rq_sched_info.pcount);
 
                seq_printf(seq, "\n");
 
@@ -39,12 +39,12 @@ static int show_schedstat(struct seq_file *seq, void *v)
                        char mask_str[NR_CPUS];
 
                        cpumask_scnprintf(mask_str, NR_CPUS, sd->span);
-                       seq_printf(seq, "domain%d %s", dcnt++, mask_str);
+                       seq_printf(seq, "domain%d %s", dcount++, mask_str);
                        for (itype = CPU_IDLE; itype < CPU_MAX_IDLE_TYPES;
                                        itype++) {
                                seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu "
                                                "%lu",
-                                   sd->lb_cnt[itype],
+                                   sd->lb_count[itype],
                                    sd->lb_balanced[itype],
                                    sd->lb_failed[itype],
                                    sd->lb_imbalance[itype],
@@ -55,9 +55,9 @@ static int show_schedstat(struct seq_file *seq, void *v)
                        }
                        seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu"
                            " %lu %lu %lu\n",
-                           sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
-                           sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
-                           sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
+                           sd->alb_count, sd->alb_failed, sd->alb_pushed,
+                           sd->sbe_count, sd->sbe_balanced, sd->sbe_pushed,
+                           sd->sbf_count, sd->sbf_balanced, sd->sbf_pushed,
                            sd->ttwu_wake_remote, sd->ttwu_move_affine,
                            sd->ttwu_move_balance);
                }
@@ -101,7 +101,7 @@ rq_sched_info_arrive(struct rq *rq, unsigned long long delta)
 {
        if (rq) {
                rq->rq_sched_info.run_delay += delta;
-               rq->rq_sched_info.pcnt++;
+               rq->rq_sched_info.pcount++;
        }
 }
 
@@ -129,7 +129,7 @@ rq_sched_info_depart(struct rq *rq, unsigned long long delta)
 # define schedstat_set(var, val)       do { } while (0)
 #endif
 
-#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
+#ifdef CONFIG_SCHEDSTATS
 /*
  * Called when a process is dequeued from the active array and given
  * the cpu.  We should note that with the exception of interactive
@@ -164,7 +164,7 @@ static void sched_info_arrive(struct task_struct *t)
        sched_info_dequeued(t);
        t->sched_info.run_delay += delta;
        t->sched_info.last_arrival = now;
-       t->sched_info.pcnt++;
+       t->sched_info.pcount++;
 
        rq_sched_info_arrive(task_rq(t), delta);
 }
@@ -233,5 +233,5 @@ sched_info_switch(struct task_struct *prev, struct task_struct *next)
 #else
 #define sched_info_queued(t)           do { } while (0)
 #define sched_info_switch(t, next)     do { } while (0)
-#endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */
+#endif /* CONFIG_SCHEDSTATS */
 
index c7314f95264763d10d5b0417aa29cf41ed26fd36..ec14aa8ac51fc83b820330af559077e1cc2cf797 100644 (file)
@@ -222,14 +222,11 @@ static ctl_table kern_table[] = {
 #ifdef CONFIG_SCHED_DEBUG
        {
                .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "sched_min_granularity_ns",
-               .data           = &sysctl_sched_min_granularity,
+               .procname       = "sched_nr_latency",
+               .data           = &sysctl_sched_nr_latency,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
-               .extra1         = &min_sched_granularity_ns,
-               .extra2         = &max_sched_granularity_ns,
+               .proc_handler   = &proc_dointvec,
        },
        {
                .ctl_name       = CTL_UNNUMBERED,
@@ -266,38 +263,24 @@ static ctl_table kern_table[] = {
        },
        {
                .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "sched_stat_granularity_ns",
-               .data           = &sysctl_sched_stat_granularity,
-               .maxlen         = sizeof(unsigned int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
-               .extra1         = &min_wakeup_granularity_ns,
-               .extra2         = &max_wakeup_granularity_ns,
-       },
-       {
-               .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "sched_runtime_limit_ns",
-               .data           = &sysctl_sched_runtime_limit,
+               .procname       = "sched_child_runs_first",
+               .data           = &sysctl_sched_child_runs_first,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
-               .extra1         = &min_sched_granularity_ns,
-               .extra2         = &max_sched_granularity_ns,
+               .proc_handler   = &proc_dointvec,
        },
        {
                .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "sched_child_runs_first",
-               .data           = &sysctl_sched_child_runs_first,
+               .procname       = "sched_features",
+               .data           = &sysctl_sched_features,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
        {
                .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "sched_features",
-               .data           = &sysctl_sched_features,
+               .procname       = "sched_migration_cost",
+               .data           = &sysctl_sched_migration_cost,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
@@ -1053,7 +1036,7 @@ static ctl_table vm_table[] = {
                .strategy       = &sysctl_string,
        },
 #endif
-#if defined(CONFIG_X86_32) || \
+#if (defined(CONFIG_X86_32) && !defined(CONFIG_UML))|| \
    (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
        {
                .ctl_name       = VM_VDSO_ENABLED,
index 298bc7c6f09f292487046a2969004ca38a0ce7d2..fc3fc79b3d593c7e4c5e170431a6204228f2e697 100644 (file)
@@ -217,26 +217,43 @@ static void tick_do_broadcast_on_off(void *why)
        bc = tick_broadcast_device.evtdev;
 
        /*
-        * Is the device in broadcast mode forever or is it not
-        * affected by the powerstate ?
+        * Is the device not affected by the powerstate ?
         */
-       if (!dev || !tick_device_is_functional(dev) ||
-           !(dev->features & CLOCK_EVT_FEAT_C3STOP))
+       if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
                goto out;
 
-       if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_ON) {
+       /*
+        * Defect device ?
+        */
+       if (!tick_device_is_functional(dev)) {
+               /*
+                * AMD C1E wreckage fixup:
+                *
+                * Device was registered functional in the first
+                * place. Now the secondary CPU detected the C1E
+                * misfeature and notifies us to fix it up
+                */
+               if (*reason != CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
+                       goto out;
+       }
+
+       switch (*reason) {
+       case CLOCK_EVT_NOTIFY_BROADCAST_ON:
+       case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
                if (!cpu_isset(cpu, tick_broadcast_mask)) {
                        cpu_set(cpu, tick_broadcast_mask);
                        if (td->mode == TICKDEV_MODE_PERIODIC)
                                clockevents_set_mode(dev,
                                                     CLOCK_EVT_MODE_SHUTDOWN);
                }
-       } else {
+               break;
+       case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
                if (cpu_isset(cpu, tick_broadcast_mask)) {
                        cpu_clear(cpu, tick_broadcast_mask);
                        if (td->mode == TICKDEV_MODE_PERIODIC)
                                tick_setup_periodic(dev, 0);
                }
+               break;
        }
 
        if (cpus_empty(tick_broadcast_mask))
index 3f3ae39078306264182734d35df7271b1c74dc48..1bea399a9ef009293958a8b37ac90dd5869fac40 100644 (file)
@@ -345,6 +345,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
 
        case CLOCK_EVT_NOTIFY_BROADCAST_ON:
        case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
+       case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
                tick_broadcast_on_off(reason, dev);
                break;
 
index 9ca2848fc35676fa8ebac52f20c33f7f056d09ff..f0e561e6d085a8f1a899c85d51c555aa18570d79 100644 (file)
@@ -50,12 +50,16 @@ struct user_struct root_user = {
        .uid_keyring    = &root_user_keyring,
        .session_keyring = &root_session_keyring,
 #endif
+#ifdef CONFIG_FAIR_USER_SCHED
+       .tg             = &init_task_group,
+#endif
 };
 
 /*
  * These routines must be called with the uidhash spinlock held!
  */
-static inline void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
+static inline void uid_hash_insert(struct user_struct *up,
+                                               struct hlist_head *hashent)
 {
        hlist_add_head(&up->uidhash_node, hashent);
 }
@@ -65,13 +69,14 @@ static inline void uid_hash_remove(struct user_struct *up)
        hlist_del_init(&up->uidhash_node);
 }
 
-static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+static inline struct user_struct *uid_hash_find(uid_t uid,
+                                               struct hlist_head *hashent)
 {
        struct user_struct *user;
        struct hlist_node *h;
 
        hlist_for_each_entry(user, h, hashent, uidhash_node) {
-               if(user->uid == uid) {
+               if (user->uid == uid) {
                        atomic_inc(&user->__count);
                        return user;
                }
@@ -80,6 +85,203 @@ static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *ha
        return NULL;
 }
 
+#ifdef CONFIG_FAIR_USER_SCHED
+
+static struct kobject uids_kobject; /* represents /sys/kernel/uids directory */
+static DEFINE_MUTEX(uids_mutex);
+
+static void sched_destroy_user(struct user_struct *up)
+{
+       sched_destroy_group(up->tg);
+}
+
+static int sched_create_user(struct user_struct *up)
+{
+       int rc = 0;
+
+       up->tg = sched_create_group();
+       if (IS_ERR(up->tg))
+               rc = -ENOMEM;
+
+       return rc;
+}
+
+static void sched_switch_user(struct task_struct *p)
+{
+       sched_move_task(p);
+}
+
+static inline void uids_mutex_lock(void)
+{
+       mutex_lock(&uids_mutex);
+}
+
+static inline void uids_mutex_unlock(void)
+{
+       mutex_unlock(&uids_mutex);
+}
+
+/* return cpu shares held by the user */
+ssize_t cpu_shares_show(struct kset *kset, char *buffer)
+{
+       struct user_struct *up = container_of(kset, struct user_struct, kset);
+
+       return sprintf(buffer, "%lu\n", sched_group_shares(up->tg));
+}
+
+/* modify cpu shares held by the user */
+ssize_t cpu_shares_store(struct kset *kset, const char *buffer, size_t size)
+{
+       struct user_struct *up = container_of(kset, struct user_struct, kset);
+       unsigned long shares;
+       int rc;
+
+       sscanf(buffer, "%lu", &shares);
+
+       rc = sched_group_set_shares(up->tg, shares);
+
+       return (rc ? rc : size);
+}
+
+static void user_attr_init(struct subsys_attribute *sa, char *name, int mode)
+{
+       sa->attr.name = name;
+       sa->attr.mode = mode;
+       sa->show = cpu_shares_show;
+       sa->store = cpu_shares_store;
+}
+
+/* Create "/sys/kernel/uids/<uid>" directory and
+ *  "/sys/kernel/uids/<uid>/cpu_share" file for this user.
+ */
+static int user_kobject_create(struct user_struct *up)
+{
+       struct kset *kset = &up->kset;
+       struct kobject *kobj = &kset->kobj;
+       int error;
+
+       memset(kset, 0, sizeof(struct kset));
+       kobj->parent = &uids_kobject;   /* create under /sys/kernel/uids dir */
+       kobject_set_name(kobj, "%d", up->uid);
+       kset_init(kset);
+       user_attr_init(&up->user_attr, "cpu_share", 0644);
+
+       error = kobject_add(kobj);
+       if (error)
+               goto done;
+
+       error = sysfs_create_file(kobj, &up->user_attr.attr);
+       if (error)
+               kobject_del(kobj);
+
+       kobject_uevent(kobj, KOBJ_ADD);
+
+done:
+       return error;
+}
+
+/* create these in sysfs filesystem:
+ *     "/sys/kernel/uids" directory
+ *     "/sys/kernel/uids/0" directory (for root user)
+ *     "/sys/kernel/uids/0/cpu_share" file (for root user)
+ */
+int __init uids_kobject_init(void)
+{
+       int error;
+
+       /* create under /sys/kernel dir */
+       uids_kobject.parent = &kernel_subsys.kobj;
+       uids_kobject.kset = &kernel_subsys;
+       kobject_set_name(&uids_kobject, "uids");
+       kobject_init(&uids_kobject);
+
+       error = kobject_add(&uids_kobject);
+       if (!error)
+               error = user_kobject_create(&root_user);
+
+       return error;
+}
+
+/* work function to remove sysfs directory for a user and free up
+ * corresponding structures.
+ */
+static void remove_user_sysfs_dir(struct work_struct *w)
+{
+       struct user_struct *up = container_of(w, struct user_struct, work);
+       struct kobject *kobj = &up->kset.kobj;
+       unsigned long flags;
+       int remove_user = 0;
+
+       /* Make uid_hash_remove() + sysfs_remove_file() + kobject_del()
+        * atomic.
+        */
+       uids_mutex_lock();
+
+       local_irq_save(flags);
+
+       if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
+               uid_hash_remove(up);
+               remove_user = 1;
+               spin_unlock_irqrestore(&uidhash_lock, flags);
+       } else {
+               local_irq_restore(flags);
+       }
+
+       if (!remove_user)
+               goto done;
+
+       sysfs_remove_file(kobj, &up->user_attr.attr);
+       kobject_uevent(kobj, KOBJ_REMOVE);
+       kobject_del(kobj);
+
+       sched_destroy_user(up);
+       key_put(up->uid_keyring);
+       key_put(up->session_keyring);
+       kmem_cache_free(uid_cachep, up);
+
+done:
+       uids_mutex_unlock();
+}
+
+/* IRQs are disabled and uidhash_lock is held upon function entry.
+ * IRQ state (as stored in flags) is restored and uidhash_lock released
+ * upon function exit.
+ */
+static inline void free_user(struct user_struct *up, unsigned long flags)
+{
+       /* restore back the count */
+       atomic_inc(&up->__count);
+       spin_unlock_irqrestore(&uidhash_lock, flags);
+
+       INIT_WORK(&up->work, remove_user_sysfs_dir);
+       schedule_work(&up->work);
+}
+
+#else  /* CONFIG_FAIR_USER_SCHED */
+
+static void sched_destroy_user(struct user_struct *up) { }
+static int sched_create_user(struct user_struct *up) { return 0; }
+static void sched_switch_user(struct task_struct *p) { }
+static inline int user_kobject_create(struct user_struct *up) { return 0; }
+static inline void uids_mutex_lock(void) { }
+static inline void uids_mutex_unlock(void) { }
+
+/* IRQs are disabled and uidhash_lock is held upon function entry.
+ * IRQ state (as stored in flags) is restored and uidhash_lock released
+ * upon function exit.
+ */
+static inline void free_user(struct user_struct *up, unsigned long flags)
+{
+       uid_hash_remove(up);
+       spin_unlock_irqrestore(&uidhash_lock, flags);
+       sched_destroy_user(up);
+       key_put(up->uid_keyring);
+       key_put(up->session_keyring);
+       kmem_cache_free(uid_cachep, up);
+}
+
+#endif /* CONFIG_FAIR_USER_SCHED */
+
 /*
  * Locate the user_struct for the passed UID.  If found, take a ref on it.  The
  * caller must undo that ref with free_uid().
@@ -106,15 +308,10 @@ void free_uid(struct user_struct *up)
                return;
 
        local_irq_save(flags);
-       if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
-               uid_hash_remove(up);
-               spin_unlock_irqrestore(&uidhash_lock, flags);
-               key_put(up->uid_keyring);
-               key_put(up->session_keyring);
-               kmem_cache_free(uid_cachep, up);
-       } else {
+       if (atomic_dec_and_lock(&up->__count, &uidhash_lock))
+               free_user(up, flags);
+       else
                local_irq_restore(flags);
-       }
 }
 
 struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
@@ -122,6 +319,11 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
        struct hlist_head *hashent = uidhashentry(ns, uid);
        struct user_struct *up;
 
+       /* Make uid_hash_find() + user_kobject_create() + uid_hash_insert()
+        * atomic.
+        */
+       uids_mutex_lock();
+
        spin_lock_irq(&uidhash_lock);
        up = uid_hash_find(uid, hashent);
        spin_unlock_irq(&uidhash_lock);
@@ -150,6 +352,22 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
                        return NULL;
                }
 
+               if (sched_create_user(new) < 0) {
+                       key_put(new->uid_keyring);
+                       key_put(new->session_keyring);
+                       kmem_cache_free(uid_cachep, new);
+                       return NULL;
+               }
+
+               if (user_kobject_create(new)) {
+                       sched_destroy_user(new);
+                       key_put(new->uid_keyring);
+                       key_put(new->session_keyring);
+                       kmem_cache_free(uid_cachep, new);
+                       uids_mutex_unlock();
+                       return NULL;
+               }
+
                /*
                 * Before adding this, check whether we raced
                 * on adding the same user already..
@@ -157,6 +375,11 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
                spin_lock_irq(&uidhash_lock);
                up = uid_hash_find(uid, hashent);
                if (up) {
+                       /* This case is not possible when CONFIG_FAIR_USER_SCHED
+                        * is defined, since we serialize alloc_uid() using
+                        * uids_mutex. Hence no need to call
+                        * sched_destroy_user() or remove_user_sysfs_dir().
+                        */
                        key_put(new->uid_keyring);
                        key_put(new->session_keyring);
                        kmem_cache_free(uid_cachep, new);
@@ -167,6 +390,9 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
                spin_unlock_irq(&uidhash_lock);
 
        }
+
+       uids_mutex_unlock();
+
        return up;
 }
 
@@ -184,6 +410,7 @@ void switch_uid(struct user_struct *new_user)
        atomic_dec(&old_user->processes);
        switch_uid_keyring(new_user);
        current->user = new_user;
+       sched_switch_user(current);
 
        /*
         * We need to synchronize with __sigqueue_alloc()
index d0f1acdbfa3a6451299867f38143dce6104faf11..09cbe2b69edb22ddc18c2feea74ff35b315e5018 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -120,7 +120,7 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
        int n, m, sh;
        struct idr_layer *p, *new;
        int l, id, oid;
-       long bm;
+       unsigned long bm;
 
        id = *starting_id;
  restart:
index e2fdbce1874b4ff7a481621b6c5a3285d8d75260..07f22d4a431f5ce63303632749453e9459ece1ee 100644 (file)
@@ -972,7 +972,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
         * array. Return various errors if the user did something wrong.
         */
        for (i = 0; i < nr_pages; i++) {
-               const void *p;
+               const void __user *p;
 
                err = -EFAULT;
                if (get_user(p, pages + i))
index 1e169a541ce76b617601a462571af418627ac68a..99b7bda37d10b3d797f1000f45ed0f51f55c4d9b 100644 (file)
@@ -557,6 +557,7 @@ __setup("netdev=", netdev_boot_setup);
 
 /**
  *     __dev_get_by_name       - find a device by its name
+ *     @net: the applicable net namespace
  *     @name: name to find
  *
  *     Find an interface by name. Must be called under RTNL semaphore
@@ -581,6 +582,7 @@ struct net_device *__dev_get_by_name(struct net *net, const char *name)
 
 /**
  *     dev_get_by_name         - find a device by its name
+ *     @net: the applicable net namespace
  *     @name: name to find
  *
  *     Find an interface by name. This can be called from any
@@ -604,6 +606,7 @@ struct net_device *dev_get_by_name(struct net *net, const char *name)
 
 /**
  *     __dev_get_by_index - find a device by its ifindex
+ *     @net: the applicable net namespace
  *     @ifindex: index of device
  *
  *     Search for an interface by index. Returns %NULL if the device
@@ -629,6 +632,7 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex)
 
 /**
  *     dev_get_by_index - find a device by its ifindex
+ *     @net: the applicable net namespace
  *     @ifindex: index of device
  *
  *     Search for an interface by index. Returns NULL if the device
@@ -651,6 +655,7 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
 
 /**
  *     dev_getbyhwaddr - find a device by its hardware address
+ *     @net: the applicable net namespace
  *     @type: media type of device
  *     @ha: hardware address
  *
@@ -709,6 +714,7 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
 
 /**
  *     dev_get_by_flags - find any device with given flags
+ *     @net: the applicable net namespace
  *     @if_flags: IFF_* values
  *     @mask: bitmask of bits in if_flags to check
  *
@@ -948,6 +954,7 @@ void netdev_state_change(struct net_device *dev)
 
 /**
  *     dev_load        - load a network module
+ *     @net: the applicable net namespace
  *     @name: name of interface
  *
  *     If a network interface is not present and the process has suitable
@@ -1185,7 +1192,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
 /**
  *     call_netdevice_notifiers - call all network notifier blocks
  *      @val: value passed unmodified to notifier function
- *      @v:   pointer passed unmodified to notifier function
+ *      @dev: net_device pointer passed unmodified to notifier function
  *
  *     Call all network notifier blocks.  Parameters and return value
  *     are as for raw_notifier_call_chain().
@@ -2097,7 +2104,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
 
 /**
  * __napi_schedule - schedule for receive
- * @napi: entry to schedule
+ * @n: entry to schedule
  *
  * The entry's receive function will be scheduled to run
  */
@@ -3259,6 +3266,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
 
 /**
  *     dev_ioctl       -       network device ioctl
+ *     @net: the applicable net namespace
  *     @cmd: command to issue
  *     @arg: pointer to a struct ifreq in user space
  *
@@ -3436,6 +3444,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 
 /**
  *     dev_new_index   -       allocate an ifindex
+ *     @net: the applicable net namespace
  *
  *     Returns a suitable unique value for a new device interface
  *     number.  The caller must hold the rtnl semaphore or the
index 4ed9b507c1e78d519488088e0285785ad1460f9b..d45ecdccc6a153ec1ffccb1430e6085a3dd42f7d 100644 (file)
@@ -869,6 +869,7 @@ static inline void sock_lock_init(struct sock *sk)
 
 /**
  *     sk_alloc - All socket objects are allocated here
+ *     @net: the applicable net namespace
  *     @family: protocol family
  *     @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
  *     @prot: struct proto associated with this new sock instance
index 4545b64e28151f76e2a7f301f87bc0c322a1829b..ac3b1d3dba2e0e81d2d032076aa429d14e6cf27f 100644 (file)
@@ -77,7 +77,7 @@ static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph,
 
        /* check tcp options (only timestamp allowed) */
        if (tcph->doff == TCPH_LEN_W_TIMESTAMP) {
-               u32 *topt = (u32 *)(tcph + 1);
+               __be32 *topt = (__be32 *)(tcph + 1);
 
                if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
                                   | (TCPOPT_TIMESTAMP << 8)
@@ -103,14 +103,14 @@ static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc)
 {
        struct iphdr *iph = lro_desc->iph;
        struct tcphdr *tcph = lro_desc->tcph;
-       u32 *p;
+       __be32 *p;
        __wsum tcp_hdr_csum;
 
        tcph->ack_seq = lro_desc->tcp_ack;
        tcph->window = lro_desc->tcp_window;
 
        if (lro_desc->tcp_saw_tstamp) {
-               p = (u32 *)(tcph + 1);
+               p = (__be32 *)(tcph + 1);
                *(p+2) = lro_desc->tcp_rcv_tsecr;
        }
 
@@ -150,7 +150,7 @@ static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
                          u16 vlan_tag, struct vlan_group *vgrp)
 {
        int nr_frags;
-       u32 *ptr;
+       __be32 *ptr;
        u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
 
        nr_frags = skb_shinfo(skb)->nr_frags;
@@ -159,14 +159,14 @@ static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
        lro_desc->iph = iph;
        lro_desc->tcph = tcph;
        lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len;
-       lro_desc->tcp_ack = ntohl(tcph->ack_seq);
+       lro_desc->tcp_ack = tcph->ack_seq;
        lro_desc->tcp_window = tcph->window;
 
        lro_desc->pkt_aggr_cnt = 1;
        lro_desc->ip_tot_len = ntohs(iph->tot_len);
 
        if (tcph->doff == 8) {
-               ptr = (u32 *)(tcph+1);
+               ptr = (__be32 *)(tcph+1);
                lro_desc->tcp_saw_tstamp = 1;
                lro_desc->tcp_rcv_tsval = *(ptr+1);
                lro_desc->tcp_rcv_tsecr = *(ptr+2);
@@ -190,7 +190,7 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
                           struct tcphdr *tcph, int tcp_data_len)
 {
        struct sk_buff *parent = lro_desc->parent;
-       u32 *topt;
+       __be32 *topt;
 
        lro_desc->pkt_aggr_cnt++;
        lro_desc->ip_tot_len += tcp_data_len;
@@ -200,7 +200,7 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
 
        /* don't update tcp_rcv_tsval, would not work with PAWS */
        if (lro_desc->tcp_saw_tstamp) {
-               topt = (u32 *) (tcph + 1);
+               topt = (__be32 *) (tcph + 1);
                lro_desc->tcp_rcv_tsecr = *(topt + 2);
        }
 
index 9c6a4b5f6264639724c52717d0e84c75129ed747..bd6f42a15a4b9d85336396ef680d7bec78912986 100644 (file)
@@ -5058,6 +5058,7 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
 static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct sctp_authchunks __user *p = (void __user *)optval;
        struct sctp_authchunks val;
        struct sctp_association *asoc;
        struct sctp_chunks_param *ch;
@@ -5066,10 +5067,10 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
        if (len <= sizeof(struct sctp_authchunks))
                return -EINVAL;
 
-       if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+       if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
                return -EFAULT;
 
-       to = val.gauth_chunks;
+       to = p->gauth_chunks;
        asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
        if (!asoc)
                return -EINVAL;
@@ -5092,6 +5093,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
 static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct sctp_authchunks __user *p = (void __user *)optval;
        struct sctp_authchunks val;
        struct sctp_association *asoc;
        struct sctp_chunks_param *ch;
@@ -5100,10 +5102,10 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
        if (len <= sizeof(struct sctp_authchunks))
                return -EINVAL;
 
-       if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+       if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
                return -EFAULT;
 
-       to = val.gauth_chunks;
+       to = p->gauth_chunks;
        asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
        if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP))
                return -EINVAL;
index 8ebfc4db7f5199274cd0cea30a4c5fa6ec066d47..5c69a725e530b825b9cef83cbbd495b309c184b0 100644 (file)
@@ -5,6 +5,7 @@
 
 obj-$(CONFIG_SUNRPC) += sunrpc.o
 obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
+obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/
 
 sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
            auth.o auth_null.o auth_unix.o \
index 42b3220bed399093ce7008a3b1183109c65e49ee..8bd074df27d36ece4d015dea8b4c5c9144fe95b2 100644 (file)
@@ -42,7 +42,7 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize)
 {
        u8 *ptr;
        u8 pad;
-       int len = buf->len;
+       size_t len = buf->len;
 
        if (len <= buf->head[0].iov_len) {
                pad = *(u8 *)(buf->head[0].iov_base + len - 1);
@@ -53,9 +53,9 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize)
        } else
                len -= buf->head[0].iov_len;
        if (len <= buf->page_len) {
-               int last = (buf->page_base + len - 1)
+               unsigned int last = (buf->page_base + len - 1)
                                        >>PAGE_CACHE_SHIFT;
-               int offset = (buf->page_base + len - 1)
+               unsigned int offset = (buf->page_base + len - 1)
                                        & (PAGE_CACHE_SIZE - 1);
                ptr = kmap_atomic(buf->pages[last], KM_USER0);
                pad = *(ptr + offset);
index 7da7050f06c39cfcc79f1383256ebbc66ba7e07b..73940df6c460c210d15e9f3c42c3a7b52a2694c7 100644 (file)
@@ -631,7 +631,8 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
        return 0;
 }
 
-/* Verify the checksum on the header and return SVC_OK on success.
+/*
+ * Verify the checksum on the header and return SVC_OK on success.
  * Otherwise, return SVC_DROP (in the case of a bad sequence number)
  * or return SVC_DENIED and indicate error in authp.
  */
@@ -960,6 +961,78 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
        return rc;
 }
 
+/*
+ * Having read the cred already and found we're in the context
+ * initiation case, read the verifier and initiate (or check the results
+ * of) upcalls to userspace for help with context initiation.  If
+ * the upcall results are available, write the verifier and result.
+ * Otherwise, drop the request pending an answer to the upcall.
+ */
+static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
+                       struct rpc_gss_wire_cred *gc, __be32 *authp)
+{
+       struct kvec *argv = &rqstp->rq_arg.head[0];
+       struct kvec *resv = &rqstp->rq_res.head[0];
+       struct xdr_netobj tmpobj;
+       struct rsi *rsip, rsikey;
+
+       /* Read the verifier; should be NULL: */
+       *authp = rpc_autherr_badverf;
+       if (argv->iov_len < 2 * 4)
+               return SVC_DENIED;
+       if (svc_getnl(argv) != RPC_AUTH_NULL)
+               return SVC_DENIED;
+       if (svc_getnl(argv) != 0)
+               return SVC_DENIED;
+
+       /* Martial context handle and token for upcall: */
+       *authp = rpc_autherr_badcred;
+       if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
+               return SVC_DENIED;
+       memset(&rsikey, 0, sizeof(rsikey));
+       if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
+               return SVC_DROP;
+       *authp = rpc_autherr_badverf;
+       if (svc_safe_getnetobj(argv, &tmpobj)) {
+               kfree(rsikey.in_handle.data);
+               return SVC_DENIED;
+       }
+       if (dup_netobj(&rsikey.in_token, &tmpobj)) {
+               kfree(rsikey.in_handle.data);
+               return SVC_DROP;
+       }
+
+       /* Perform upcall, or find upcall result: */
+       rsip = rsi_lookup(&rsikey);
+       rsi_free(&rsikey);
+       if (!rsip)
+               return SVC_DROP;
+       switch (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
+       case -EAGAIN:
+       case -ETIMEDOUT:
+       case -ENOENT:
+               /* No upcall result: */
+               return SVC_DROP;
+       case 0:
+               /* Got an answer to the upcall; use it: */
+               if (gss_write_init_verf(rqstp, rsip))
+                       return SVC_DROP;
+               if (resv->iov_len + 4 > PAGE_SIZE)
+                       return SVC_DROP;
+               svc_putnl(resv, RPC_SUCCESS);
+               if (svc_safe_putnetobj(resv, &rsip->out_handle))
+                       return SVC_DROP;
+               if (resv->iov_len + 3 * 4 > PAGE_SIZE)
+                       return SVC_DROP;
+               svc_putnl(resv, rsip->major_status);
+               svc_putnl(resv, rsip->minor_status);
+               svc_putnl(resv, GSS_SEQ_WIN);
+               if (svc_safe_putnetobj(resv, &rsip->out_token))
+                       return SVC_DROP;
+       }
+       return SVC_COMPLETE;
+}
+
 /*
  * Accept an rpcsec packet.
  * If context establishment, punt to user space
@@ -974,11 +1047,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        struct kvec     *argv = &rqstp->rq_arg.head[0];
        struct kvec     *resv = &rqstp->rq_res.head[0];
        u32             crlen;
-       struct xdr_netobj tmpobj;
        struct gss_svc_data *svcdata = rqstp->rq_auth_data;
        struct rpc_gss_wire_cred *gc;
        struct rsc      *rsci = NULL;
-       struct rsi      *rsip, rsikey;
        __be32          *rpcstart;
        __be32          *reject_stat = resv->iov_base + resv->iov_len;
        int             ret;
@@ -1023,30 +1094,14 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
                goto auth_err;
 
-       /*
-        * We've successfully parsed the credential. Let's check out the
-        * verifier.  An AUTH_NULL verifier is allowed (and required) for
-        * INIT and CONTINUE_INIT requests. AUTH_RPCSEC_GSS is required for
-        * PROC_DATA and PROC_DESTROY.
-        *
-        * AUTH_NULL verifier is 0 (AUTH_NULL), 0 (length).
-        * AUTH_RPCSEC_GSS verifier is:
-        *   6 (AUTH_RPCSEC_GSS), length, checksum.
-        * checksum is calculated over rpcheader from xid up to here.
-        */
        *authp = rpc_autherr_badverf;
        switch (gc->gc_proc) {
        case RPC_GSS_PROC_INIT:
        case RPC_GSS_PROC_CONTINUE_INIT:
-               if (argv->iov_len < 2 * 4)
-                       goto auth_err;
-               if (svc_getnl(argv) != RPC_AUTH_NULL)
-                       goto auth_err;
-               if (svc_getnl(argv) != 0)
-                       goto auth_err;
-               break;
+               return svcauth_gss_handle_init(rqstp, gc, authp);
        case RPC_GSS_PROC_DATA:
        case RPC_GSS_PROC_DESTROY:
+               /* Look up the context, and check the verifier: */
                *authp = rpcsec_gsserr_credproblem;
                rsci = gss_svc_searchbyctx(&gc->gc_ctx);
                if (!rsci)
@@ -1067,51 +1122,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
 
        /* now act upon the command: */
        switch (gc->gc_proc) {
-       case RPC_GSS_PROC_INIT:
-       case RPC_GSS_PROC_CONTINUE_INIT:
-               *authp = rpc_autherr_badcred;
-               if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
-                       goto auth_err;
-               memset(&rsikey, 0, sizeof(rsikey));
-               if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
-                       goto drop;
-               *authp = rpc_autherr_badverf;
-               if (svc_safe_getnetobj(argv, &tmpobj)) {
-                       kfree(rsikey.in_handle.data);
-                       goto auth_err;
-               }
-               if (dup_netobj(&rsikey.in_token, &tmpobj)) {
-                       kfree(rsikey.in_handle.data);
-                       goto drop;
-               }
-
-               rsip = rsi_lookup(&rsikey);
-               rsi_free(&rsikey);
-               if (!rsip) {
-                       goto drop;
-               }
-               switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
-               case -EAGAIN:
-               case -ETIMEDOUT:
-               case -ENOENT:
-                       goto drop;
-               case 0:
-                       if (gss_write_init_verf(rqstp, rsip))
-                               goto drop;
-                       if (resv->iov_len + 4 > PAGE_SIZE)
-                               goto drop;
-                       svc_putnl(resv, RPC_SUCCESS);
-                       if (svc_safe_putnetobj(resv, &rsip->out_handle))
-                               goto drop;
-                       if (resv->iov_len + 3 * 4 > PAGE_SIZE)
-                               goto drop;
-                       svc_putnl(resv, rsip->major_status);
-                       svc_putnl(resv, rsip->minor_status);
-                       svc_putnl(resv, GSS_SEQ_WIN);
-                       if (svc_safe_putnetobj(resv, &rsip->out_token))
-                               goto drop;
-               }
-               goto complete;
        case RPC_GSS_PROC_DESTROY:
                if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
                        goto auth_err;
@@ -1158,7 +1168,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
                goto out;
        }
 auth_err:
-       /* Restore write pointer to original value: */
+       /* Restore write pointer to its original value: */
        xdr_ressize_check(rqstp, reject_stat);
        ret = SVC_DENIED;
        goto out;
index 52429b1ffcc1d8d33bf7cf116bab5bfa0ceb052c..76be83ee4b04a59f90f99a3afc69ce8889a7ff39 100644 (file)
@@ -127,7 +127,14 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
        struct rpc_clnt         *clnt = NULL;
        struct rpc_auth         *auth;
        int err;
-       int len;
+       size_t len;
+
+       /* sanity check the name before trying to print it */
+       err = -EINVAL;
+       len = strlen(servname);
+       if (len > RPC_MAXNETNAMELEN)
+               goto out_no_rpciod;
+       len++;
 
        dprintk("RPC:       creating %s client for %s (xprt %p)\n",
                        program->name, servname, xprt);
@@ -148,7 +155,6 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
        clnt->cl_parent = clnt;
 
        clnt->cl_server = clnt->cl_inline_name;
-       len = strlen(servname) + 1;
        if (len > sizeof(clnt->cl_inline_name)) {
                char *buf = kmalloc(len, GFP_KERNEL);
                if (buf != 0)
@@ -234,8 +240,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 {
        struct rpc_xprt *xprt;
        struct rpc_clnt *clnt;
-       struct rpc_xprtsock_create xprtargs = {
-               .proto = args->protocol,
+       struct xprt_create xprtargs = {
+               .ident = args->protocol,
                .srcaddr = args->saddress,
                .dstaddr = args->address,
                .addrlen = args->addrsize,
@@ -253,7 +259,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
         */
        if (args->servername == NULL) {
                struct sockaddr_in *addr =
-                                       (struct sockaddr_in *) &args->address;
+                                       (struct sockaddr_in *) args->address;
                snprintf(servername, sizeof(servername), NIPQUAD_FMT,
                        NIPQUAD(addr->sin_addr.s_addr));
                args->servername = servername;
@@ -269,9 +275,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
        if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
                xprt->resvport = 0;
 
-       dprintk("RPC:       creating %s client for %s (xprt %p)\n",
-                       args->program->name, args->servername, xprt);
-
        clnt = rpc_new_client(xprt, args->servername, args->program,
                                args->version, args->authflavor);
        if (IS_ERR(clnt))
@@ -439,7 +442,7 @@ rpc_release_client(struct rpc_clnt *clnt)
  */
 struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
                                      struct rpc_program *program,
-                                     int vers)
+                                     u32 vers)
 {
        struct rpc_clnt *clnt;
        struct rpc_version *version;
@@ -843,8 +846,7 @@ call_allocate(struct rpc_task *task)
        dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
 
        if (RPC_IS_ASYNC(task) || !signalled()) {
-               xprt_release(task);
-               task->tk_action = call_reserve;
+               task->tk_action = call_allocate;
                rpc_delay(task, HZ>>4);
                return;
        }
@@ -871,6 +873,7 @@ rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
        buf->head[0].iov_len = len;
        buf->tail[0].iov_len = 0;
        buf->page_len = 0;
+       buf->flags = 0;
        buf->len = 0;
        buf->buflen = len;
 }
@@ -937,7 +940,7 @@ call_bind(struct rpc_task *task)
 static void
 call_bind_status(struct rpc_task *task)
 {
-       int status = -EACCES;
+       int status = -EIO;
 
        if (task->tk_status >= 0) {
                dprint_status(task);
@@ -947,9 +950,20 @@ call_bind_status(struct rpc_task *task)
        }
 
        switch (task->tk_status) {
+       case -EAGAIN:
+               dprintk("RPC: %5u rpcbind waiting for another request "
+                               "to finish\n", task->tk_pid);
+               /* avoid busy-waiting here -- could be a network outage. */
+               rpc_delay(task, 5*HZ);
+               goto retry_timeout;
        case -EACCES:
                dprintk("RPC: %5u remote rpcbind: RPC program/version "
                                "unavailable\n", task->tk_pid);
+               /* fail immediately if this is an RPC ping */
+               if (task->tk_msg.rpc_proc->p_proc == 0) {
+                       status = -EOPNOTSUPP;
+                       break;
+               }
                rpc_delay(task, 3*HZ);
                goto retry_timeout;
        case -ETIMEDOUT:
@@ -957,6 +971,7 @@ call_bind_status(struct rpc_task *task)
                                task->tk_pid);
                goto retry_timeout;
        case -EPFNOSUPPORT:
+               /* server doesn't support any rpcbind version we know of */
                dprintk("RPC: %5u remote rpcbind service unavailable\n",
                                task->tk_pid);
                break;
@@ -969,7 +984,6 @@ call_bind_status(struct rpc_task *task)
        default:
                dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
                                task->tk_pid, -task->tk_status);
-               status = -EIO;
        }
 
        rpc_exit(task, status);
@@ -1257,7 +1271,6 @@ call_refresh(struct rpc_task *task)
 {
        dprint_status(task);
 
-       xprt_release(task);     /* Must do to obtain new XID */
        task->tk_action = call_refreshresult;
        task->tk_status = 0;
        task->tk_client->cl_stats->rpcauthrefresh++;
@@ -1375,6 +1388,8 @@ call_verify(struct rpc_task *task)
                        dprintk("RPC: %5u %s: retry stale creds\n",
                                        task->tk_pid, __FUNCTION__);
                        rpcauth_invalcred(task);
+                       /* Ensure we obtain a new XID! */
+                       xprt_release(task);
                        task->tk_action = call_refresh;
                        goto out_retry;
                case RPC_AUTH_BADCRED:
@@ -1523,13 +1538,18 @@ void rpc_show_tasks(void)
                spin_lock(&clnt->cl_lock);
                list_for_each_entry(t, &clnt->cl_tasks, tk_task) {
                        const char *rpc_waitq = "none";
+                       int proc;
+
+                       if (t->tk_msg.rpc_proc)
+                               proc = t->tk_msg.rpc_proc->p_proc;
+                       else
+                               proc = -1;
 
                        if (RPC_IS_QUEUED(t))
                                rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
 
                        printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
-                               t->tk_pid,
-                               (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
+                               t->tk_pid, proc,
                                t->tk_flags, t->tk_status,
                                t->tk_client,
                                (t->tk_client ? t->tk_client->cl_prog : 0),
index 669e12a4ed18a140a0ff94de8647aec344c39c66..c8433e8865aa63e7739fd5c0586fb977af2a207f 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/pagemap.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
 #include <linux/kernel.h>
 
 #include <asm/ioctls.h>
@@ -329,6 +329,7 @@ rpc_show_info(struct seq_file *m, void *v)
                        clnt->cl_prog, clnt->cl_vers);
        seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
        seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
+       seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
        return 0;
 }
 
@@ -585,6 +586,7 @@ rpc_populate(struct dentry *parent,
                if (S_ISDIR(mode))
                        inc_nlink(dir);
                d_add(dentry, inode);
+               fsnotify_create(dir, dentry);
        }
        mutex_unlock(&dir->i_mutex);
        return 0;
@@ -606,7 +608,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
        inode->i_ino = iunique(dir->i_sb, 100);
        d_instantiate(dentry, inode);
        inc_nlink(dir);
-       inode_dir_notify(dir, DN_CREATE);
+       fsnotify_mkdir(dir, dentry);
        return 0;
 out_err:
        printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
@@ -748,7 +750,7 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi
        rpci->flags = flags;
        rpci->ops = ops;
        rpci->nkern_readwriters = 1;
-       inode_dir_notify(dir, DN_CREATE);
+       fsnotify_create(dir, dentry);
        dget(dentry);
 out:
        mutex_unlock(&dir->i_mutex);
index d1740dbab991e98747593ebd16618a7245384567..a05493aedb6800b11c91b31f1587dd229ca5387f 100644 (file)
 
 #include <linux/types.h>
 #include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/xprtsock.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_BIND
@@ -90,26 +93,6 @@ enum {
  */
 #define RPCB_MAXADDRLEN                (128u)
 
-/*
- * r_netid
- *
- * Quoting RFC 3530, section 2.2:
- *
- * For TCP over IPv4 the value of r_netid is the string "tcp".  For UDP
- * over IPv4 the value of r_netid is the string "udp".
- *
- * ...
- *
- * For TCP over IPv6 the value of r_netid is the string "tcp6".  For UDP
- * over IPv6 the value of r_netid is the string "udp6".
- */
-#define RPCB_NETID_UDP "\165\144\160"          /* "udp" */
-#define RPCB_NETID_TCP "\164\143\160"          /* "tcp" */
-#define RPCB_NETID_UDP6        "\165\144\160\066"      /* "udp6" */
-#define RPCB_NETID_TCP6        "\164\143\160\066"      /* "tcp6" */
-
-#define RPCB_MAXNETIDLEN       (4u)
-
 /*
  * r_owner
  *
@@ -120,7 +103,7 @@ enum {
 #define RPCB_MAXOWNERLEN       sizeof(RPCB_OWNER_STRING)
 
 static void                    rpcb_getport_done(struct rpc_task *, void *);
-extern struct rpc_program      rpcb_program;
+static struct rpc_program      rpcb_program;
 
 struct rpcbind_args {
        struct rpc_xprt *       r_xprt;
@@ -137,10 +120,13 @@ struct rpcbind_args {
 static struct rpc_procinfo rpcb_procedures2[];
 static struct rpc_procinfo rpcb_procedures3[];
 
-static struct rpcb_info {
+struct rpcb_info {
        int                     rpc_vers;
        struct rpc_procinfo *   rpc_proc;
-} rpcb_next_version[];
+};
+
+static struct rpcb_info rpcb_next_version[];
+static struct rpcb_info rpcb_next_version6[];
 
 static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
 {
@@ -190,7 +176,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
                                   RPC_CLNT_CREATE_INTR),
        };
 
-       ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
+       switch (srvaddr->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
+               break;
+       default:
+               return NULL;
+       }
+
        if (!privileged)
                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
        return rpc_create(&args);
@@ -234,7 +230,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
                        prog, vers, prot, port);
 
        rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
-                                       IPPROTO_UDP, 2, 1);
+                                       XPRT_TRANSPORT_UDP, 2, 1);
        if (IS_ERR(rpcb_clnt))
                return PTR_ERR(rpcb_clnt);
 
@@ -316,6 +312,7 @@ void rpcb_getport_async(struct rpc_task *task)
        struct rpc_task *child;
        struct sockaddr addr;
        int status;
+       struct rpcb_info *info;
 
        dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
                task->tk_pid, __FUNCTION__,
@@ -325,7 +322,7 @@ void rpcb_getport_async(struct rpc_task *task)
        BUG_ON(clnt->cl_parent != clnt);
 
        if (xprt_test_and_set_binding(xprt)) {
-               status = -EACCES;               /* tell caller to check again */
+               status = -EAGAIN;       /* tell caller to check again */
                dprintk("RPC: %5u %s: waiting for another binder\n",
                        task->tk_pid, __FUNCTION__);
                goto bailout_nowake;
@@ -343,18 +340,43 @@ void rpcb_getport_async(struct rpc_task *task)
                goto bailout_nofree;
        }
 
-       if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) {
+       rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+
+       /* Don't ever use rpcbind v2 for AF_INET6 requests */
+       switch (addr.sa_family) {
+       case AF_INET:
+               info = rpcb_next_version;
+               break;
+       case AF_INET6:
+               info = rpcb_next_version6;
+               break;
+       default:
+               status = -EAFNOSUPPORT;
+               dprintk("RPC: %5u %s: bad address family\n",
+                               task->tk_pid, __FUNCTION__);
+               goto bailout_nofree;
+       }
+       if (info[xprt->bind_index].rpc_proc == NULL) {
                xprt->bind_index = 0;
-               status = -EACCES;       /* tell caller to try again later */
+               status = -EPFNOSUPPORT;
                dprintk("RPC: %5u %s: no more getport versions available\n",
                        task->tk_pid, __FUNCTION__);
                goto bailout_nofree;
        }
-       bind_version = rpcb_next_version[xprt->bind_index].rpc_vers;
+       bind_version = info[xprt->bind_index].rpc_vers;
 
        dprintk("RPC: %5u %s: trying rpcbind version %u\n",
                task->tk_pid, __FUNCTION__, bind_version);
 
+       rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot,
+                               bind_version, 0);
+       if (IS_ERR(rpcb_clnt)) {
+               status = PTR_ERR(rpcb_clnt);
+               dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
+                       task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
+               goto bailout_nofree;
+       }
+
        map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
        if (!map) {
                status = -ENOMEM;
@@ -367,28 +389,19 @@ void rpcb_getport_async(struct rpc_task *task)
        map->r_prot = xprt->prot;
        map->r_port = 0;
        map->r_xprt = xprt_get(xprt);
-       map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP :
-                                                  RPCB_NETID_UDP;
-       memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR),
-                       sizeof(map->r_addr));
+       map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
+       memcpy(map->r_addr,
+              rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR),
+              sizeof(map->r_addr));
        map->r_owner = RPCB_OWNER_STRING;       /* ignored for GETADDR */
 
-       rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
-       rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
-       if (IS_ERR(rpcb_clnt)) {
-               status = PTR_ERR(rpcb_clnt);
-               dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
-                       task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
-               goto bailout;
-       }
-
        child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
        rpc_release_client(rpcb_clnt);
        if (IS_ERR(child)) {
                status = -EIO;
                dprintk("RPC: %5u %s: rpc_run_task failed\n",
                        task->tk_pid, __FUNCTION__);
-               goto bailout_nofree;
+               goto bailout;
        }
        rpc_put_task(child);
 
@@ -403,6 +416,7 @@ bailout_nofree:
 bailout_nowake:
        task->tk_status = status;
 }
+EXPORT_SYMBOL_GPL(rpcb_getport_async);
 
 /*
  * Rpcbind child task calls this callback via tk_exit.
@@ -413,6 +427,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
        struct rpc_xprt *xprt = map->r_xprt;
        int status = child->tk_status;
 
+       /* Garbage reply: retry with a lesser rpcbind version */
+       if (status == -EIO)
+               status = -EPROTONOSUPPORT;
+
        /* rpcbind server doesn't support this rpcbind protocol version */
        if (status == -EPROTONOSUPPORT)
                xprt->bind_index++;
@@ -490,16 +508,24 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
                               unsigned short *portp)
 {
        char *addr;
-       int addr_len, c, i, f, first, val;
+       u32 addr_len;
+       int c, i, f, first, val;
 
        *portp = 0;
-       addr_len = (unsigned int) ntohl(*p++);
-       if (addr_len > RPCB_MAXADDRLEN)                 /* sanity */
-               return -EINVAL;
-
-       dprintk("RPC:       rpcb_decode_getaddr returned string: '%s'\n",
-                       (char *) p);
-
+       addr_len = ntohl(*p++);
+
+       /*
+        * Simple sanity check.  The smallest possible universal
+        * address is an IPv4 address string containing 11 bytes.
+        */
+       if (addr_len < 11 || addr_len > RPCB_MAXADDRLEN)
+               goto out_err;
+
+       /*
+        * Start at the end and walk backwards until the first dot
+        * is encountered.  When the second dot is found, we have
+        * both parts of the port number.
+        */
        addr = (char *)p;
        val = 0;
        first = 1;
@@ -521,8 +547,19 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
                }
        }
 
+       /*
+        * Simple sanity check.  If we never saw a dot in the reply,
+        * then this was probably just garbage.
+        */
+       if (first)
+               goto out_err;
+
        dprintk("RPC:       rpcb_decode_getaddr port=%u\n", *portp);
        return 0;
+
+out_err:
+       dprintk("RPC:       rpcbind server returned malformed reply\n");
+       return -EIO;
 }
 
 #define RPCB_program_sz                (1u)
@@ -531,7 +568,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
 #define RPCB_port_sz           (1u)
 #define RPCB_boolean_sz                (1u)
 
-#define RPCB_netid_sz          (1+XDR_QUADLEN(RPCB_MAXNETIDLEN))
+#define RPCB_netid_sz          (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
 #define RPCB_addr_sz           (1+XDR_QUADLEN(RPCB_MAXADDRLEN))
 #define RPCB_ownerstring_sz    (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
 
@@ -593,6 +630,14 @@ static struct rpcb_info rpcb_next_version[] = {
        { 0, NULL },
 };
 
+static struct rpcb_info rpcb_next_version6[] = {
+#ifdef CONFIG_SUNRPC_BIND34
+       { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
+       { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
+#endif
+       { 0, NULL },
+};
+
 static struct rpc_version rpcb_version2 = {
        .number         = 2,
        .nrprocs        = RPCB_HIGHPROC_2,
@@ -621,7 +666,7 @@ static struct rpc_version *rpcb_version[] = {
 
 static struct rpc_stat rpcb_stats;
 
-struct rpc_program rpcb_program = {
+static struct rpc_program rpcb_program = {
        .name           = "rpcbind",
        .number         = RPCBIND_PROGRAM,
        .nrvers         = ARRAY_SIZE(rpcb_version),
index 954d7ec86c7e201be80f0e19c41f3597125059e8..3c773c53e12e96e08207e50446a033132043e349 100644 (file)
@@ -777,6 +777,7 @@ void *rpc_malloc(struct rpc_task *task, size_t size)
                        task->tk_pid, size, buf);
        return &buf->data;
 }
+EXPORT_SYMBOL_GPL(rpc_malloc);
 
 /**
  * rpc_free - free buffer allocated via rpc_malloc
@@ -802,6 +803,7 @@ void rpc_free(void *buffer)
        else
                kfree(buf);
 }
+EXPORT_SYMBOL_GPL(rpc_free);
 
 /*
  * Creation and deletion of RPC task structures
index 1d377d1ab7f4a5018a18a876f87e337c022346c3..97ac45f034d6f35155537adc7face2cd47791a80 100644 (file)
@@ -34,6 +34,7 @@ size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)
        desc->offset += len;
        return len;
 }
+EXPORT_SYMBOL_GPL(xdr_skb_read_bits);
 
 /**
  * xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer
@@ -137,6 +138,7 @@ copy_tail:
 out:
        return copied;
 }
+EXPORT_SYMBOL_GPL(xdr_partial_copy_from_skb);
 
 /**
  * csum_partial_copy_to_xdr - checksum and copy data
@@ -179,3 +181,4 @@ no_checksum:
                return -1;
        return 0;
 }
+EXPORT_SYMBOL_GPL(csum_partial_copy_to_xdr);
index 384c4ad5ab86db1b2e657d46efdd46a609b808a0..33d89e842c8506ead293a7ac8460c71e8b392fb0 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
-
+#include <linux/sunrpc/xprtsock.h>
 
 /* RPC scheduler */
 EXPORT_SYMBOL(rpc_execute);
index 55ea6df069deeb2042b8b1b8dc4c5294d5bfa649..a4a6bf7deaa494407cff505ffc00057b6f25c8bd 100644 (file)
@@ -776,6 +776,30 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
        return error;
 }
 
+/*
+ * Printk the given error with the address of the client that caused it.
+ */
+static int
+__attribute__ ((format (printf, 2, 3)))
+svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
+{
+       va_list args;
+       int     r;
+       char    buf[RPC_MAX_ADDRBUFLEN];
+
+       if (!net_ratelimit())
+               return 0;
+
+       printk(KERN_WARNING "svc: %s: ",
+               svc_print_addr(rqstp, buf, sizeof(buf)));
+
+       va_start(args, fmt);
+       r = vprintk(fmt, args);
+       va_end(args);
+
+       return r;
+}
+
 /*
  * Process the RPC request.
  */
@@ -963,14 +987,13 @@ svc_process(struct svc_rqst *rqstp)
        return 0;
 
 err_short_len:
-       if (net_ratelimit())
-               printk("svc: short len %Zd, dropping request\n", argv->iov_len);
+       svc_printk(rqstp, "short len %Zd, dropping request\n",
+                       argv->iov_len);
 
        goto dropit;                    /* drop request */
 
 err_bad_dir:
-       if (net_ratelimit())
-               printk("svc: bad direction %d, dropping request\n", dir);
+       svc_printk(rqstp, "bad direction %d, dropping request\n", dir);
 
        serv->sv_stats->rpcbadfmt++;
        goto dropit;                    /* drop request */
@@ -1000,8 +1023,7 @@ err_bad_prog:
        goto sendit;
 
 err_bad_vers:
-       if (net_ratelimit())
-               printk("svc: unknown version (%d for prog %d, %s)\n",
+       svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
                       vers, prog, progp->pg_name);
 
        serv->sv_stats->rpcbadfmt++;
@@ -1011,16 +1033,14 @@ err_bad_vers:
        goto sendit;
 
 err_bad_proc:
-       if (net_ratelimit())
-               printk("svc: unknown procedure (%d)\n", proc);
+       svc_printk(rqstp, "unknown procedure (%d)\n", proc);
 
        serv->sv_stats->rpcbadfmt++;
        svc_putnl(resv, RPC_PROC_UNAVAIL);
        goto sendit;
 
 err_garbage:
-       if (net_ratelimit())
-               printk("svc: failed to decode args\n");
+       svc_printk(rqstp, "failed to decode args\n");
 
        rpc_stat = rpc_garbage_args;
 err_bad:
index 8142fdb8a9306530452bbe76e6162bc09db42b73..31becbf092632fcb4151b649c4507b6a794f46e8 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/types.h>
 #include <linux/unistd.h>
+#include <linux/module.h>
 
 #include <linux/sunrpc/clnt.h>
 
@@ -40,6 +41,7 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
                rt->ntimeouts[i] = 0;
        }
 }
+EXPORT_SYMBOL_GPL(rpc_init_rtt);
 
 /*
  * NB: When computing the smoothed RTT and standard deviation,
@@ -75,6 +77,7 @@ rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
        if (*sdrtt < RPC_RTO_MIN)
                *sdrtt = RPC_RTO_MIN;
 }
+EXPORT_SYMBOL_GPL(rpc_update_rtt);
 
 /*
  * Estimate rto for an nfs rpc sent via. an unreliable datagram.
@@ -103,3 +106,4 @@ rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
 
        return res;
 }
+EXPORT_SYMBOL_GPL(rpc_calc_rto);
index c8c2edccad7e0dc2db35c754c9b56890a7c73965..282a9a2ec90c6e5f6c78b1c8b0e6cfe95e04461c 100644 (file)
@@ -62,6 +62,9 @@ static inline void    do_xprt_reserve(struct rpc_task *);
 static void    xprt_connect_status(struct rpc_task *task);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
+static spinlock_t xprt_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(xprt_list);
+
 /*
  * The transport code maintains an estimate on the maximum number of out-
  * standing RPC requests, using a smoothed version of the congestion
@@ -80,6 +83,78 @@ static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
 #define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
 
+/**
+ * xprt_register_transport - register a transport implementation
+ * @transport: transport to register
+ *
+ * If a transport implementation is loaded as a kernel module, it can
+ * call this interface to make itself known to the RPC client.
+ *
+ * Returns:
+ * 0:          transport successfully registered
+ * -EEXIST:    transport already registered
+ * -EINVAL:    transport module being unloaded
+ */
+int xprt_register_transport(struct xprt_class *transport)
+{
+       struct xprt_class *t;
+       int result;
+
+       result = -EEXIST;
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               /* don't register the same transport class twice */
+               if (t->ident == transport->ident)
+                       goto out;
+       }
+
+       result = -EINVAL;
+       if (try_module_get(THIS_MODULE)) {
+               list_add_tail(&transport->list, &xprt_list);
+               printk(KERN_INFO "RPC: Registered %s transport module.\n",
+                       transport->name);
+               result = 0;
+       }
+
+out:
+       spin_unlock(&xprt_list_lock);
+       return result;
+}
+EXPORT_SYMBOL_GPL(xprt_register_transport);
+
+/**
+ * xprt_unregister_transport - unregister a transport implementation
+ * transport: transport to unregister
+ *
+ * Returns:
+ * 0:          transport successfully unregistered
+ * -ENOENT:    transport never registered
+ */
+int xprt_unregister_transport(struct xprt_class *transport)
+{
+       struct xprt_class *t;
+       int result;
+
+       result = 0;
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               if (t == transport) {
+                       printk(KERN_INFO
+                               "RPC: Unregistered %s transport module.\n",
+                               transport->name);
+                       list_del_init(&transport->list);
+                       module_put(THIS_MODULE);
+                       goto out;
+               }
+       }
+       result = -ENOENT;
+
+out:
+       spin_unlock(&xprt_list_lock);
+       return result;
+}
+EXPORT_SYMBOL_GPL(xprt_unregister_transport);
+
 /**
  * xprt_reserve_xprt - serialize write access to transports
  * @task: task that is requesting access to the transport
@@ -118,6 +193,7 @@ out_sleep:
                rpc_sleep_on(&xprt->sending, task, NULL, NULL);
        return 0;
 }
+EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
 
 static void xprt_clear_locked(struct rpc_xprt *xprt)
 {
@@ -167,6 +243,7 @@ out_sleep:
                rpc_sleep_on(&xprt->sending, task, NULL, NULL);
        return 0;
 }
+EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong);
 
 static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
 {
@@ -246,6 +323,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
                __xprt_lock_write_next(xprt);
        }
 }
+EXPORT_SYMBOL_GPL(xprt_release_xprt);
 
 /**
  * xprt_release_xprt_cong - allow other requests to use a transport
@@ -262,6 +340,7 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
                __xprt_lock_write_next_cong(xprt);
        }
 }
+EXPORT_SYMBOL_GPL(xprt_release_xprt_cong);
 
 static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
 {
@@ -314,6 +393,7 @@ void xprt_release_rqst_cong(struct rpc_task *task)
 {
        __xprt_put_cong(task->tk_xprt, task->tk_rqstp);
 }
+EXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
 
 /**
  * xprt_adjust_cwnd - adjust transport congestion window
@@ -345,6 +425,7 @@ void xprt_adjust_cwnd(struct rpc_task *task, int result)
        xprt->cwnd = cwnd;
        __xprt_put_cong(xprt, req);
 }
+EXPORT_SYMBOL_GPL(xprt_adjust_cwnd);
 
 /**
  * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue
@@ -359,6 +440,7 @@ void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status)
        else
                rpc_wake_up(&xprt->pending);
 }
+EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
 
 /**
  * xprt_wait_for_buffer_space - wait for transport output buffer to clear
@@ -373,6 +455,7 @@ void xprt_wait_for_buffer_space(struct rpc_task *task)
        task->tk_timeout = req->rq_timeout;
        rpc_sleep_on(&xprt->pending, task, NULL, NULL);
 }
+EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
 
 /**
  * xprt_write_space - wake the task waiting for transport output buffer space
@@ -393,6 +476,7 @@ void xprt_write_space(struct rpc_xprt *xprt)
        }
        spin_unlock_bh(&xprt->transport_lock);
 }
+EXPORT_SYMBOL_GPL(xprt_write_space);
 
 /**
  * xprt_set_retrans_timeout_def - set a request's retransmit timeout
@@ -406,6 +490,7 @@ void xprt_set_retrans_timeout_def(struct rpc_task *task)
 {
        task->tk_timeout = task->tk_rqstp->rq_timeout;
 }
+EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_def);
 
 /*
  * xprt_set_retrans_timeout_rtt - set a request's retransmit timeout
@@ -425,6 +510,7 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task)
        if (task->tk_timeout > max_timeout || task->tk_timeout == 0)
                task->tk_timeout = max_timeout;
 }
+EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_rtt);
 
 static void xprt_reset_majortimeo(struct rpc_rqst *req)
 {
@@ -500,6 +586,7 @@ void xprt_disconnect(struct rpc_xprt *xprt)
        xprt_wake_pending_tasks(xprt, -ENOTCONN);
        spin_unlock_bh(&xprt->transport_lock);
 }
+EXPORT_SYMBOL_GPL(xprt_disconnect);
 
 static void
 xprt_init_autodisconnect(unsigned long data)
@@ -610,6 +697,7 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
        xprt->stat.bad_xids++;
        return NULL;
 }
+EXPORT_SYMBOL_GPL(xprt_lookup_rqst);
 
 /**
  * xprt_update_rtt - update an RPC client's RTT state after receiving a reply
@@ -629,6 +717,7 @@ void xprt_update_rtt(struct rpc_task *task)
                rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
        }
 }
+EXPORT_SYMBOL_GPL(xprt_update_rtt);
 
 /**
  * xprt_complete_rqst - called when reply processing is complete
@@ -653,6 +742,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
        req->rq_received = req->rq_private_buf.len = copied;
        rpc_wake_up_task(task);
 }
+EXPORT_SYMBOL_GPL(xprt_complete_rqst);
 
 static void xprt_timer(struct rpc_task *task)
 {
@@ -889,23 +979,25 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i
  * @args: rpc transport creation arguments
  *
  */
-struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args)
+struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 {
        struct rpc_xprt *xprt;
        struct rpc_rqst *req;
+       struct xprt_class *t;
 
-       switch (args->proto) {
-       case IPPROTO_UDP:
-               xprt = xs_setup_udp(args);
-               break;
-       case IPPROTO_TCP:
-               xprt = xs_setup_tcp(args);
-               break;
-       default:
-               printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
-                               args->proto);
-               return ERR_PTR(-EIO);
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               if (t->ident == args->ident) {
+                       spin_unlock(&xprt_list_lock);
+                       goto found;
+               }
        }
+       spin_unlock(&xprt_list_lock);
+       printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident);
+       return ERR_PTR(-EIO);
+
+found:
+       xprt = t->setup(args);
        if (IS_ERR(xprt)) {
                dprintk("RPC:       xprt_create_transport: failed, %ld\n",
                                -PTR_ERR(xprt));
diff --git a/net/sunrpc/xprtrdma/Makefile b/net/sunrpc/xprtrdma/Makefile
new file mode 100644 (file)
index 0000000..264f0fe
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma.o
+
+xprtrdma-y := transport.o rpc_rdma.o verbs.o
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
new file mode 100644 (file)
index 0000000..12db635
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      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.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * rpc_rdma.c
+ *
+ * This file contains the guts of the RPC RDMA protocol, and
+ * does marshaling/unmarshaling, etc. It is also where interfacing
+ * to the Linux RPC framework lives.
+ */
+
+#include "xprt_rdma.h"
+
+#include <linux/highmem.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY       RPCDBG_TRANS
+#endif
+
+enum rpcrdma_chunktype {
+       rpcrdma_noch = 0,
+       rpcrdma_readch,
+       rpcrdma_areadch,
+       rpcrdma_writech,
+       rpcrdma_replych
+};
+
+#ifdef RPC_DEBUG
+static const char transfertypes[][12] = {
+       "pure inline",  /* no chunks */
+       " read chunk",  /* some argument via rdma read */
+       "*read chunk",  /* entire request via rdma read */
+       "write chunk",  /* some result via rdma write */
+       "reply chunk"   /* entire reply via rdma write */
+};
+#endif
+
+/*
+ * Chunk assembly from upper layer xdr_buf.
+ *
+ * Prepare the passed-in xdr_buf into representation as RPC/RDMA chunk
+ * elements. Segments are then coalesced when registered, if possible
+ * within the selected memreg mode.
+ *
+ * Note, this routine is never called if the connection's memory
+ * registration strategy is 0 (bounce buffers).
+ */
+
+static int
+rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, int pos,
+       enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs)
+{
+       int len, n = 0, p;
+
+       if (pos == 0 && xdrbuf->head[0].iov_len) {
+               seg[n].mr_page = NULL;
+               seg[n].mr_offset = xdrbuf->head[0].iov_base;
+               seg[n].mr_len = xdrbuf->head[0].iov_len;
+               pos += xdrbuf->head[0].iov_len;
+               ++n;
+       }
+
+       if (xdrbuf->page_len && (xdrbuf->pages[0] != NULL)) {
+               if (n == nsegs)
+                       return 0;
+               seg[n].mr_page = xdrbuf->pages[0];
+               seg[n].mr_offset = (void *)(unsigned long) xdrbuf->page_base;
+               seg[n].mr_len = min_t(u32,
+                       PAGE_SIZE - xdrbuf->page_base, xdrbuf->page_len);
+               len = xdrbuf->page_len - seg[n].mr_len;
+               pos += len;
+               ++n;
+               p = 1;
+               while (len > 0) {
+                       if (n == nsegs)
+                               return 0;
+                       seg[n].mr_page = xdrbuf->pages[p];
+                       seg[n].mr_offset = NULL;
+                       seg[n].mr_len = min_t(u32, PAGE_SIZE, len);
+                       len -= seg[n].mr_len;
+                       ++n;
+                       ++p;
+               }
+       }
+
+       if (pos < xdrbuf->len && xdrbuf->tail[0].iov_len) {
+               if (n == nsegs)
+                       return 0;
+               seg[n].mr_page = NULL;
+               seg[n].mr_offset = xdrbuf->tail[0].iov_base;
+               seg[n].mr_len = xdrbuf->tail[0].iov_len;
+               pos += xdrbuf->tail[0].iov_len;
+               ++n;
+       }
+
+       if (pos < xdrbuf->len)
+               dprintk("RPC:       %s: marshaled only %d of %d\n",
+                               __func__, pos, xdrbuf->len);
+
+       return n;
+}
+
+/*
+ * Create read/write chunk lists, and reply chunks, for RDMA
+ *
+ *   Assume check against THRESHOLD has been done, and chunks are required.
+ *   Assume only encoding one list entry for read|write chunks. The NFSv3
+ *     protocol is simple enough to allow this as it only has a single "bulk
+ *     result" in each procedure - complicated NFSv4 COMPOUNDs are not. (The
+ *     RDMA/Sessions NFSv4 proposal addresses this for future v4 revs.)
+ *
+ * When used for a single reply chunk (which is a special write
+ * chunk used for the entire reply, rather than just the data), it
+ * is used primarily for READDIR and READLINK which would otherwise
+ * be severely size-limited by a small rdma inline read max. The server
+ * response will come back as an RDMA Write, followed by a message
+ * of type RDMA_NOMSG carrying the xid and length. As a result, reply
+ * chunks do not provide data alignment, however they do not require
+ * "fixup" (moving the response to the upper layer buffer) either.
+ *
+ * Encoding key for single-list chunks (HLOO = Handle32 Length32 Offset64):
+ *
+ *  Read chunklist (a linked list):
+ *   N elements, position P (same P for all chunks of same arg!):
+ *    1 - PHLOO - 1 - PHLOO - ... - 1 - PHLOO - 0
+ *
+ *  Write chunklist (a list of (one) counted array):
+ *   N elements:
+ *    1 - N - HLOO - HLOO - ... - HLOO - 0
+ *
+ *  Reply chunk (a counted array):
+ *   N elements:
+ *    1 - N - HLOO - HLOO - ... - HLOO
+ */
+
+static unsigned int
+rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
+               struct rpcrdma_msg *headerp, enum rpcrdma_chunktype type)
+{
+       struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_task->tk_xprt);
+       int nsegs, nchunks = 0;
+       int pos;
+       struct rpcrdma_mr_seg *seg = req->rl_segments;
+       struct rpcrdma_read_chunk *cur_rchunk = NULL;
+       struct rpcrdma_write_array *warray = NULL;
+       struct rpcrdma_write_chunk *cur_wchunk = NULL;
+       u32 *iptr = headerp->rm_body.rm_chunks;
+
+       if (type == rpcrdma_readch || type == rpcrdma_areadch) {
+               /* a read chunk - server will RDMA Read our memory */
+               cur_rchunk = (struct rpcrdma_read_chunk *) iptr;
+       } else {
+               /* a write or reply chunk - server will RDMA Write our memory */
+               *iptr++ = xdr_zero;     /* encode a NULL read chunk list */
+               if (type == rpcrdma_replych)
+                       *iptr++ = xdr_zero;     /* a NULL write chunk list */
+               warray = (struct rpcrdma_write_array *) iptr;
+               cur_wchunk = (struct rpcrdma_write_chunk *) (warray + 1);
+       }
+
+       if (type == rpcrdma_replych || type == rpcrdma_areadch)
+               pos = 0;
+       else
+               pos = target->head[0].iov_len;
+
+       nsegs = rpcrdma_convert_iovs(target, pos, type, seg, RPCRDMA_MAX_SEGS);
+       if (nsegs == 0)
+               return 0;
+
+       do {
+               /* bind/register the memory, then build chunk from result. */
+               int n = rpcrdma_register_external(seg, nsegs,
+                                               cur_wchunk != NULL, r_xprt);
+               if (n <= 0)
+                       goto out;
+               if (cur_rchunk) {       /* read */
+                       cur_rchunk->rc_discrim = xdr_one;
+                       /* all read chunks have the same "position" */
+                       cur_rchunk->rc_position = htonl(pos);
+                       cur_rchunk->rc_target.rs_handle = htonl(seg->mr_rkey);
+                       cur_rchunk->rc_target.rs_length = htonl(seg->mr_len);
+                       xdr_encode_hyper(
+                                       (u32 *)&cur_rchunk->rc_target.rs_offset,
+                                       seg->mr_base);
+                       dprintk("RPC:       %s: read chunk "
+                               "elem %d@0x%llx:0x%x pos %d (%s)\n", __func__,
+                               seg->mr_len, seg->mr_base, seg->mr_rkey, pos,
+                               n < nsegs ? "more" : "last");
+                       cur_rchunk++;
+                       r_xprt->rx_stats.read_chunk_count++;
+               } else {                /* write/reply */
+                       cur_wchunk->wc_target.rs_handle = htonl(seg->mr_rkey);
+                       cur_wchunk->wc_target.rs_length = htonl(seg->mr_len);
+                       xdr_encode_hyper(
+                                       (u32 *)&cur_wchunk->wc_target.rs_offset,
+                                       seg->mr_base);
+                       dprintk("RPC:       %s: %s chunk "
+                               "elem %d@0x%llx:0x%x (%s)\n", __func__,
+                               (type == rpcrdma_replych) ? "reply" : "write",
+                               seg->mr_len, seg->mr_base, seg->mr_rkey,
+                               n < nsegs ? "more" : "last");
+                       cur_wchunk++;
+                       if (type == rpcrdma_replych)
+                               r_xprt->rx_stats.reply_chunk_count++;
+                       else
+                               r_xprt->rx_stats.write_chunk_count++;
+                       r_xprt->rx_stats.total_rdma_request += seg->mr_len;
+               }
+               nchunks++;
+               seg   += n;
+               nsegs -= n;
+       } while (nsegs);
+
+       /* success. all failures return above */
+       req->rl_nchunks = nchunks;
+
+       BUG_ON(nchunks == 0);
+
+       /*
+        * finish off header. If write, marshal discrim and nchunks.
+        */
+       if (cur_rchunk) {
+               iptr = (u32 *) cur_rchunk;
+               *iptr++ = xdr_zero;     /* finish the read chunk list */
+               *iptr++ = xdr_zero;     /* encode a NULL write chunk list */
+               *iptr++ = xdr_zero;     /* encode a NULL reply chunk */
+       } else {
+               warray->wc_discrim = xdr_one;
+               warray->wc_nchunks = htonl(nchunks);
+               iptr = (u32 *) cur_wchunk;
+               if (type == rpcrdma_writech) {
+                       *iptr++ = xdr_zero; /* finish the write chunk list */
+                       *iptr++ = xdr_zero; /* encode a NULL reply chunk */
+               }
+       }
+
+       /*
+        * Return header size.
+        */
+       return (unsigned char *)iptr - (unsigned char *)headerp;
+
+out:
+       for (pos = 0; nchunks--;)
+               pos += rpcrdma_deregister_external(
+                               &req->rl_segments[pos], r_xprt, NULL);
+       return 0;
+}
+
+/*
+ * Copy write data inline.
+ * This function is used for "small" requests. Data which is passed
+ * to RPC via iovecs (or page list) is copied directly into the
+ * pre-registered memory buffer for this request. For small amounts
+ * of data, this is efficient. The cutoff value is tunable.
+ */
+static int
+rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
+{
+       int i, npages, curlen;
+       int copy_len;
+       unsigned char *srcp, *destp;
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
+
+       destp = rqst->rq_svec[0].iov_base;
+       curlen = rqst->rq_svec[0].iov_len;
+       destp += curlen;
+       /*
+        * Do optional padding where it makes sense. Alignment of write
+        * payload can help the server, if our setting is accurate.
+        */
+       pad -= (curlen + 36/*sizeof(struct rpcrdma_msg_padded)*/);
+       if (pad < 0 || rqst->rq_slen - curlen < RPCRDMA_INLINE_PAD_THRESH)
+               pad = 0;        /* don't pad this request */
+
+       dprintk("RPC:       %s: pad %d destp 0x%p len %d hdrlen %d\n",
+               __func__, pad, destp, rqst->rq_slen, curlen);
+
+       copy_len = rqst->rq_snd_buf.page_len;
+       r_xprt->rx_stats.pullup_copy_count += copy_len;
+       npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT;
+       for (i = 0; copy_len && i < npages; i++) {
+               if (i == 0)
+                       curlen = PAGE_SIZE - rqst->rq_snd_buf.page_base;
+               else
+                       curlen = PAGE_SIZE;
+               if (curlen > copy_len)
+                       curlen = copy_len;
+               dprintk("RPC:       %s: page %d destp 0x%p len %d curlen %d\n",
+                       __func__, i, destp, copy_len, curlen);
+               srcp = kmap_atomic(rqst->rq_snd_buf.pages[i],
+                                       KM_SKB_SUNRPC_DATA);
+               if (i == 0)
+                       memcpy(destp, srcp+rqst->rq_snd_buf.page_base, curlen);
+               else
+                       memcpy(destp, srcp, curlen);
+               kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA);
+               rqst->rq_svec[0].iov_len += curlen;
+               destp += curlen;
+               copy_len -= curlen;
+       }
+       if (rqst->rq_snd_buf.tail[0].iov_len) {
+               curlen = rqst->rq_snd_buf.tail[0].iov_len;
+               if (destp != rqst->rq_snd_buf.tail[0].iov_base) {
+                       memcpy(destp,
+                               rqst->rq_snd_buf.tail[0].iov_base, curlen);
+                       r_xprt->rx_stats.pullup_copy_count += curlen;
+               }
+               dprintk("RPC:       %s: tail destp 0x%p len %d curlen %d\n",
+                       __func__, destp, copy_len, curlen);
+               rqst->rq_svec[0].iov_len += curlen;
+       }
+       /* header now contains entire send message */
+       return pad;
+}
+
+/*
+ * Marshal a request: the primary job of this routine is to choose
+ * the transfer modes. See comments below.
+ *
+ * Uses multiple RDMA IOVs for a request:
+ *  [0] -- RPC RDMA header, which uses memory from the *start* of the
+ *         preregistered buffer that already holds the RPC data in
+ *         its middle.
+ *  [1] -- the RPC header/data, marshaled by RPC and the NFS protocol.
+ *  [2] -- optional padding.
+ *  [3] -- if padded, header only in [1] and data here.
+ */
+
+int
+rpcrdma_marshal_req(struct rpc_rqst *rqst)
+{
+       struct rpc_xprt *xprt = rqst->rq_task->tk_xprt;
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+       struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
+       char *base;
+       size_t hdrlen, rpclen, padlen;
+       enum rpcrdma_chunktype rtype, wtype;
+       struct rpcrdma_msg *headerp;
+
+       /*
+        * rpclen gets amount of data in first buffer, which is the
+        * pre-registered buffer.
+        */
+       base = rqst->rq_svec[0].iov_base;
+       rpclen = rqst->rq_svec[0].iov_len;
+
+       /* build RDMA header in private area at front */
+       headerp = (struct rpcrdma_msg *) req->rl_base;
+       /* don't htonl XID, it's already done in request */
+       headerp->rm_xid = rqst->rq_xid;
+       headerp->rm_vers = xdr_one;
+       headerp->rm_credit = htonl(r_xprt->rx_buf.rb_max_requests);
+       headerp->rm_type = __constant_htonl(RDMA_MSG);
+
+       /*
+        * Chunks needed for results?
+        *
+        * o If the expected result is under the inline threshold, all ops
+        *   return as inline (but see later).
+        * o Large non-read ops return as a single reply chunk.
+        * o Large read ops return data as write chunk(s), header as inline.
+        *
+        * Note: the NFS code sending down multiple result segments implies
+        * the op is one of read, readdir[plus], readlink or NFSv4 getacl.
+        */
+
+       /*
+        * This code can handle read chunks, write chunks OR reply
+        * chunks -- only one type. If the request is too big to fit
+        * inline, then we will choose read chunks. If the request is
+        * a READ, then use write chunks to separate the file data
+        * into pages; otherwise use reply chunks.
+        */
+       if (rqst->rq_rcv_buf.buflen <= RPCRDMA_INLINE_READ_THRESHOLD(rqst))
+               wtype = rpcrdma_noch;
+       else if (rqst->rq_rcv_buf.page_len == 0)
+               wtype = rpcrdma_replych;
+       else if (rqst->rq_rcv_buf.flags & XDRBUF_READ)
+               wtype = rpcrdma_writech;
+       else
+               wtype = rpcrdma_replych;
+
+       /*
+        * Chunks needed for arguments?
+        *
+        * o If the total request is under the inline threshold, all ops
+        *   are sent as inline.
+        * o Large non-write ops are sent with the entire message as a
+        *   single read chunk (protocol 0-position special case).
+        * o Large write ops transmit data as read chunk(s), header as
+        *   inline.
+        *
+        * Note: the NFS code sending down multiple argument segments
+        * implies the op is a write.
+        * TBD check NFSv4 setacl
+        */
+       if (rqst->rq_snd_buf.len <= RPCRDMA_INLINE_WRITE_THRESHOLD(rqst))
+               rtype = rpcrdma_noch;
+       else if (rqst->rq_snd_buf.page_len == 0)
+               rtype = rpcrdma_areadch;
+       else
+               rtype = rpcrdma_readch;
+
+       /* The following simplification is not true forever */
+       if (rtype != rpcrdma_noch && wtype == rpcrdma_replych)
+               wtype = rpcrdma_noch;
+       BUG_ON(rtype != rpcrdma_noch && wtype != rpcrdma_noch);
+
+       if (r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_BOUNCEBUFFERS &&
+           (rtype != rpcrdma_noch || wtype != rpcrdma_noch)) {
+               /* forced to "pure inline"? */
+               dprintk("RPC:       %s: too much data (%d/%d) for inline\n",
+                       __func__, rqst->rq_rcv_buf.len, rqst->rq_snd_buf.len);
+               return -1;
+       }
+
+       hdrlen = 28; /*sizeof *headerp;*/
+       padlen = 0;
+
+       /*
+        * Pull up any extra send data into the preregistered buffer.
+        * When padding is in use and applies to the transfer, insert
+        * it and change the message type.
+        */
+       if (rtype == rpcrdma_noch) {
+
+               padlen = rpcrdma_inline_pullup(rqst,
+                                               RPCRDMA_INLINE_PAD_VALUE(rqst));
+
+               if (padlen) {
+                       headerp->rm_type = __constant_htonl(RDMA_MSGP);
+                       headerp->rm_body.rm_padded.rm_align =
+                               htonl(RPCRDMA_INLINE_PAD_VALUE(rqst));
+                       headerp->rm_body.rm_padded.rm_thresh =
+                               __constant_htonl(RPCRDMA_INLINE_PAD_THRESH);
+                       headerp->rm_body.rm_padded.rm_pempty[0] = xdr_zero;
+                       headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero;
+                       headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero;
+                       hdrlen += 2 * sizeof(u32); /* extra words in padhdr */
+                       BUG_ON(wtype != rpcrdma_noch);
+
+               } else {
+                       headerp->rm_body.rm_nochunks.rm_empty[0] = xdr_zero;
+                       headerp->rm_body.rm_nochunks.rm_empty[1] = xdr_zero;
+                       headerp->rm_body.rm_nochunks.rm_empty[2] = xdr_zero;
+                       /* new length after pullup */
+                       rpclen = rqst->rq_svec[0].iov_len;
+                       /*
+                        * Currently we try to not actually use read inline.
+                        * Reply chunks have the desirable property that
+                        * they land, packed, directly in the target buffers
+                        * without headers, so they require no fixup. The
+                        * additional RDMA Write op sends the same amount
+                        * of data, streams on-the-wire and adds no overhead
+                        * on receive. Therefore, we request a reply chunk
+                        * for non-writes wherever feasible and efficient.
+                        */
+                       if (wtype == rpcrdma_noch &&
+                           r_xprt->rx_ia.ri_memreg_strategy > RPCRDMA_REGISTER)
+                               wtype = rpcrdma_replych;
+               }
+       }
+
+       /*
+        * Marshal chunks. This routine will return the header length
+        * consumed by marshaling.
+        */
+       if (rtype != rpcrdma_noch) {
+               hdrlen = rpcrdma_create_chunks(rqst,
+                                       &rqst->rq_snd_buf, headerp, rtype);
+               wtype = rtype;  /* simplify dprintk */
+
+       } else if (wtype != rpcrdma_noch) {
+               hdrlen = rpcrdma_create_chunks(rqst,
+                                       &rqst->rq_rcv_buf, headerp, wtype);
+       }
+
+       if (hdrlen == 0)
+               return -1;
+
+       dprintk("RPC:       %s: %s: hdrlen %zd rpclen %zd padlen %zd\n"
+               "                   headerp 0x%p base 0x%p lkey 0x%x\n",
+               __func__, transfertypes[wtype], hdrlen, rpclen, padlen,
+               headerp, base, req->rl_iov.lkey);
+
+       /*
+        * initialize send_iov's - normally only two: rdma chunk header and
+        * single preregistered RPC header buffer, but if padding is present,
+        * then use a preregistered (and zeroed) pad buffer between the RPC
+        * header and any write data. In all non-rdma cases, any following
+        * data has been copied into the RPC header buffer.
+        */
+       req->rl_send_iov[0].addr = req->rl_iov.addr;
+       req->rl_send_iov[0].length = hdrlen;
+       req->rl_send_iov[0].lkey = req->rl_iov.lkey;
+
+       req->rl_send_iov[1].addr = req->rl_iov.addr + (base - req->rl_base);
+       req->rl_send_iov[1].length = rpclen;
+       req->rl_send_iov[1].lkey = req->rl_iov.lkey;
+
+       req->rl_niovs = 2;
+
+       if (padlen) {
+               struct rpcrdma_ep *ep = &r_xprt->rx_ep;
+
+               req->rl_send_iov[2].addr = ep->rep_pad.addr;
+               req->rl_send_iov[2].length = padlen;
+               req->rl_send_iov[2].lkey = ep->rep_pad.lkey;
+
+               req->rl_send_iov[3].addr = req->rl_send_iov[1].addr + rpclen;
+               req->rl_send_iov[3].length = rqst->rq_slen - rpclen;
+               req->rl_send_iov[3].lkey = req->rl_iov.lkey;
+
+               req->rl_niovs = 4;
+       }
+
+       return 0;
+}
+
+/*
+ * Chase down a received write or reply chunklist to get length
+ * RDMA'd by server. See map at rpcrdma_create_chunks()! :-)
+ */
+static int
+rpcrdma_count_chunks(struct rpcrdma_rep *rep, int max, int wrchunk, u32 **iptrp)
+{
+       unsigned int i, total_len;
+       struct rpcrdma_write_chunk *cur_wchunk;
+
+       i = ntohl(**iptrp);     /* get array count */
+       if (i > max)
+               return -1;
+       cur_wchunk = (struct rpcrdma_write_chunk *) (*iptrp + 1);
+       total_len = 0;
+       while (i--) {
+               struct rpcrdma_segment *seg = &cur_wchunk->wc_target;
+               ifdebug(FACILITY) {
+                       u64 off;
+                       xdr_decode_hyper((u32 *)&seg->rs_offset, &off);
+                       dprintk("RPC:       %s: chunk %d@0x%llx:0x%x\n",
+                               __func__,
+                               ntohl(seg->rs_length),
+                               off,
+                               ntohl(seg->rs_handle));
+               }
+               total_len += ntohl(seg->rs_length);
+               ++cur_wchunk;
+       }
+       /* check and adjust for properly terminated write chunk */
+       if (wrchunk) {
+               u32 *w = (u32 *) cur_wchunk;
+               if (*w++ != xdr_zero)
+                       return -1;
+               cur_wchunk = (struct rpcrdma_write_chunk *) w;
+       }
+       if ((char *) cur_wchunk > rep->rr_base + rep->rr_len)
+               return -1;
+
+       *iptrp = (u32 *) cur_wchunk;
+       return total_len;
+}
+
+/*
+ * Scatter inline received data back into provided iov's.
+ */
+static void
+rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len)
+{
+       int i, npages, curlen, olen;
+       char *destp;
+
+       curlen = rqst->rq_rcv_buf.head[0].iov_len;
+       if (curlen > copy_len) {        /* write chunk header fixup */
+               curlen = copy_len;
+               rqst->rq_rcv_buf.head[0].iov_len = curlen;
+       }
+
+       dprintk("RPC:       %s: srcp 0x%p len %d hdrlen %d\n",
+               __func__, srcp, copy_len, curlen);
+
+       /* Shift pointer for first receive segment only */
+       rqst->rq_rcv_buf.head[0].iov_base = srcp;
+       srcp += curlen;
+       copy_len -= curlen;
+
+       olen = copy_len;
+       i = 0;
+       rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen;
+       if (copy_len && rqst->rq_rcv_buf.page_len) {
+               npages = PAGE_ALIGN(rqst->rq_rcv_buf.page_base +
+                       rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT;
+               for (; i < npages; i++) {
+                       if (i == 0)
+                               curlen = PAGE_SIZE - rqst->rq_rcv_buf.page_base;
+                       else
+                               curlen = PAGE_SIZE;
+                       if (curlen > copy_len)
+                               curlen = copy_len;
+                       dprintk("RPC:       %s: page %d"
+                               " srcp 0x%p len %d curlen %d\n",
+                               __func__, i, srcp, copy_len, curlen);
+                       destp = kmap_atomic(rqst->rq_rcv_buf.pages[i],
+                                               KM_SKB_SUNRPC_DATA);
+                       if (i == 0)
+                               memcpy(destp + rqst->rq_rcv_buf.page_base,
+                                               srcp, curlen);
+                       else
+                               memcpy(destp, srcp, curlen);
+                       flush_dcache_page(rqst->rq_rcv_buf.pages[i]);
+                       kunmap_atomic(destp, KM_SKB_SUNRPC_DATA);
+                       srcp += curlen;
+                       copy_len -= curlen;
+                       if (copy_len == 0)
+                               break;
+               }
+               rqst->rq_rcv_buf.page_len = olen - copy_len;
+       } else
+               rqst->rq_rcv_buf.page_len = 0;
+
+       if (copy_len && rqst->rq_rcv_buf.tail[0].iov_len) {
+               curlen = copy_len;
+               if (curlen > rqst->rq_rcv_buf.tail[0].iov_len)
+                       curlen = rqst->rq_rcv_buf.tail[0].iov_len;
+               if (rqst->rq_rcv_buf.tail[0].iov_base != srcp)
+                       memcpy(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
+               dprintk("RPC:       %s: tail srcp 0x%p len %d curlen %d\n",
+                       __func__, srcp, copy_len, curlen);
+               rqst->rq_rcv_buf.tail[0].iov_len = curlen;
+               copy_len -= curlen; ++i;
+       } else
+               rqst->rq_rcv_buf.tail[0].iov_len = 0;
+
+       if (copy_len)
+               dprintk("RPC:       %s: %d bytes in"
+                       " %d extra segments (%d lost)\n",
+                       __func__, olen, i, copy_len);
+
+       /* TBD avoid a warning from call_decode() */
+       rqst->rq_private_buf = rqst->rq_rcv_buf;
+}
+
+/*
+ * This function is called when an async event is posted to
+ * the connection which changes the connection state. All it
+ * does at this point is mark the connection up/down, the rpc
+ * timers do the rest.
+ */
+void
+rpcrdma_conn_func(struct rpcrdma_ep *ep)
+{
+       struct rpc_xprt *xprt = ep->rep_xprt;
+
+       spin_lock_bh(&xprt->transport_lock);
+       if (ep->rep_connected > 0) {
+               if (!xprt_test_and_set_connected(xprt))
+                       xprt_wake_pending_tasks(xprt, 0);
+       } else {
+               if (xprt_test_and_clear_connected(xprt))
+                       xprt_wake_pending_tasks(xprt, ep->rep_connected);
+       }
+       spin_unlock_bh(&xprt->transport_lock);
+}
+
+/*
+ * This function is called when memory window unbind which we are waiting
+ * for completes. Just use rr_func (zeroed by upcall) to signal completion.
+ */
+static void
+rpcrdma_unbind_func(struct rpcrdma_rep *rep)
+{
+       wake_up(&rep->rr_unbind);
+}
+
+/*
+ * Called as a tasklet to do req/reply match and complete a request
+ * Errors must result in the RPC task either being awakened, or
+ * allowed to timeout, to discover the errors at that time.
+ */
+void
+rpcrdma_reply_handler(struct rpcrdma_rep *rep)
+{
+       struct rpcrdma_msg *headerp;
+       struct rpcrdma_req *req;
+       struct rpc_rqst *rqst;
+       struct rpc_xprt *xprt = rep->rr_xprt;
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+       u32 *iptr;
+       int i, rdmalen, status;
+
+       /* Check status. If bad, signal disconnect and return rep to pool */
+       if (rep->rr_len == ~0U) {
+               rpcrdma_recv_buffer_put(rep);
+               if (r_xprt->rx_ep.rep_connected == 1) {
+                       r_xprt->rx_ep.rep_connected = -EIO;
+                       rpcrdma_conn_func(&r_xprt->rx_ep);
+               }
+               return;
+       }
+       if (rep->rr_len < 28) {
+               dprintk("RPC:       %s: short/invalid reply\n", __func__);
+               goto repost;
+       }
+       headerp = (struct rpcrdma_msg *) rep->rr_base;
+       if (headerp->rm_vers != xdr_one) {
+               dprintk("RPC:       %s: invalid version %d\n",
+                       __func__, ntohl(headerp->rm_vers));
+               goto repost;
+       }
+
+       /* Get XID and try for a match. */
+       spin_lock(&xprt->transport_lock);
+       rqst = xprt_lookup_rqst(xprt, headerp->rm_xid);
+       if (rqst == NULL) {
+               spin_unlock(&xprt->transport_lock);
+               dprintk("RPC:       %s: reply 0x%p failed "
+                       "to match any request xid 0x%08x len %d\n",
+                       __func__, rep, headerp->rm_xid, rep->rr_len);
+repost:
+               r_xprt->rx_stats.bad_reply_count++;
+               rep->rr_func = rpcrdma_reply_handler;
+               if (rpcrdma_ep_post_recv(&r_xprt->rx_ia, &r_xprt->rx_ep, rep))
+                       rpcrdma_recv_buffer_put(rep);
+
+               return;
+       }
+
+       /* get request object */
+       req = rpcr_to_rdmar(rqst);
+
+       dprintk("RPC:       %s: reply 0x%p completes request 0x%p\n"
+               "                   RPC request 0x%p xid 0x%08x\n",
+                       __func__, rep, req, rqst, headerp->rm_xid);
+
+       BUG_ON(!req || req->rl_reply);
+
+       /* from here on, the reply is no longer an orphan */
+       req->rl_reply = rep;
+
+       /* check for expected message types */
+       /* The order of some of these tests is important. */
+       switch (headerp->rm_type) {
+       case __constant_htonl(RDMA_MSG):
+               /* never expect read chunks */
+               /* never expect reply chunks (two ways to check) */
+               /* never expect write chunks without having offered RDMA */
+               if (headerp->rm_body.rm_chunks[0] != xdr_zero ||
+                   (headerp->rm_body.rm_chunks[1] == xdr_zero &&
+                    headerp->rm_body.rm_chunks[2] != xdr_zero) ||
+                   (headerp->rm_body.rm_chunks[1] != xdr_zero &&
+                    req->rl_nchunks == 0))
+                       goto badheader;
+               if (headerp->rm_body.rm_chunks[1] != xdr_zero) {
+                       /* count any expected write chunks in read reply */
+                       /* start at write chunk array count */
+                       iptr = &headerp->rm_body.rm_chunks[2];
+                       rdmalen = rpcrdma_count_chunks(rep,
+                                               req->rl_nchunks, 1, &iptr);
+                       /* check for validity, and no reply chunk after */
+                       if (rdmalen < 0 || *iptr++ != xdr_zero)
+                               goto badheader;
+                       rep->rr_len -=
+                           ((unsigned char *)iptr - (unsigned char *)headerp);
+                       status = rep->rr_len + rdmalen;
+                       r_xprt->rx_stats.total_rdma_reply += rdmalen;
+               } else {
+                       /* else ordinary inline */
+                       iptr = (u32 *)((unsigned char *)headerp + 28);
+                       rep->rr_len -= 28; /*sizeof *headerp;*/
+                       status = rep->rr_len;
+               }
+               /* Fix up the rpc results for upper layer */
+               rpcrdma_inline_fixup(rqst, (char *)iptr, rep->rr_len);
+               break;
+
+       case __constant_htonl(RDMA_NOMSG):
+               /* never expect read or write chunks, always reply chunks */
+               if (headerp->rm_body.rm_chunks[0] != xdr_zero ||
+                   headerp->rm_body.rm_chunks[1] != xdr_zero ||
+                   headerp->rm_body.rm_chunks[2] != xdr_one ||
+                   req->rl_nchunks == 0)
+                       goto badheader;
+               iptr = (u32 *)((unsigned char *)headerp + 28);
+               rdmalen = rpcrdma_count_chunks(rep, req->rl_nchunks, 0, &iptr);
+               if (rdmalen < 0)
+                       goto badheader;
+               r_xprt->rx_stats.total_rdma_reply += rdmalen;
+               /* Reply chunk buffer already is the reply vector - no fixup. */
+               status = rdmalen;
+               break;
+
+badheader:
+       default:
+               dprintk("%s: invalid rpcrdma reply header (type %d):"
+                               " chunks[012] == %d %d %d"
+                               " expected chunks <= %d\n",
+                               __func__, ntohl(headerp->rm_type),
+                               headerp->rm_body.rm_chunks[0],
+                               headerp->rm_body.rm_chunks[1],
+                               headerp->rm_body.rm_chunks[2],
+                               req->rl_nchunks);
+               status = -EIO;
+               r_xprt->rx_stats.bad_reply_count++;
+               break;
+       }
+
+       /* If using mw bind, start the deregister process now. */
+       /* (Note: if mr_free(), cannot perform it here, in tasklet context) */
+       if (req->rl_nchunks) switch (r_xprt->rx_ia.ri_memreg_strategy) {
+       case RPCRDMA_MEMWINDOWS:
+               for (i = 0; req->rl_nchunks-- > 1;)
+                       i += rpcrdma_deregister_external(
+                               &req->rl_segments[i], r_xprt, NULL);
+               /* Optionally wait (not here) for unbinds to complete */
+               rep->rr_func = rpcrdma_unbind_func;
+               (void) rpcrdma_deregister_external(&req->rl_segments[i],
+                                                  r_xprt, rep);
+               break;
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+               for (i = 0; req->rl_nchunks--;)
+                       i += rpcrdma_deregister_external(&req->rl_segments[i],
+                                                        r_xprt, NULL);
+               break;
+       default:
+               break;
+       }
+
+       dprintk("RPC:       %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n",
+                       __func__, xprt, rqst, status);
+       xprt_complete_rqst(rqst->rq_task, status);
+       spin_unlock(&xprt->transport_lock);
+}
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
new file mode 100644 (file)
index 0000000..dc55cc9
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      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.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * transport.c
+ *
+ * This file contains the top-level implementation of an RPC RDMA
+ * transport.
+ *
+ * Naming convention: functions beginning with xprt_ are part of the
+ * transport switch. All others are RPC RDMA internal.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+#include "xprt_rdma.h"
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY       RPCDBG_TRANS
+#endif
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_DESCRIPTION("RPC/RDMA Transport for Linux kernel NFS");
+MODULE_AUTHOR("Network Appliance, Inc.");
+
+/*
+ * tunables
+ */
+
+static unsigned int xprt_rdma_slot_table_entries = RPCRDMA_DEF_SLOT_TABLE;
+static unsigned int xprt_rdma_max_inline_read = RPCRDMA_DEF_INLINE;
+static unsigned int xprt_rdma_max_inline_write = RPCRDMA_DEF_INLINE;
+static unsigned int xprt_rdma_inline_write_padding;
+#if !RPCRDMA_PERSISTENT_REGISTRATION
+static unsigned int xprt_rdma_memreg_strategy = RPCRDMA_REGISTER; /* FMR? */
+#else
+static unsigned int xprt_rdma_memreg_strategy = RPCRDMA_ALLPHYSICAL;
+#endif
+
+#ifdef RPC_DEBUG
+
+static unsigned int min_slot_table_size = RPCRDMA_MIN_SLOT_TABLE;
+static unsigned int max_slot_table_size = RPCRDMA_MAX_SLOT_TABLE;
+static unsigned int zero;
+static unsigned int max_padding = PAGE_SIZE;
+static unsigned int min_memreg = RPCRDMA_BOUNCEBUFFERS;
+static unsigned int max_memreg = RPCRDMA_LAST - 1;
+
+static struct ctl_table_header *sunrpc_table_header;
+
+static ctl_table xr_tunables_table[] = {
+       {
+               .ctl_name       = CTL_SLOTTABLE_RDMA,
+               .procname       = "rdma_slot_table_entries",
+               .data           = &xprt_rdma_slot_table_entries,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_slot_table_size,
+               .extra2         = &max_slot_table_size
+       },
+       {
+               .ctl_name       = CTL_RDMA_MAXINLINEREAD,
+               .procname       = "rdma_max_inline_read",
+               .data           = &xprt_rdma_max_inline_read,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+               .strategy       = &sysctl_intvec,
+       },
+       {
+               .ctl_name       = CTL_RDMA_MAXINLINEWRITE,
+               .procname       = "rdma_max_inline_write",
+               .data           = &xprt_rdma_max_inline_write,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+               .strategy       = &sysctl_intvec,
+       },
+       {
+               .ctl_name       = CTL_RDMA_WRITEPADDING,
+               .procname       = "rdma_inline_write_padding",
+               .data           = &xprt_rdma_inline_write_padding,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &max_padding,
+       },
+       {
+               .ctl_name       = CTL_RDMA_MEMREG,
+               .procname       = "rdma_memreg_strategy",
+               .data           = &xprt_rdma_memreg_strategy,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_memreg,
+               .extra2         = &max_memreg,
+       },
+       {
+               .ctl_name = 0,
+       },
+};
+
+static ctl_table sunrpc_table[] = {
+       {
+               .ctl_name       = CTL_SUNRPC,
+               .procname       = "sunrpc",
+               .mode           = 0555,
+               .child          = xr_tunables_table
+       },
+       {
+               .ctl_name = 0,
+       },
+};
+
+#endif
+
+static struct rpc_xprt_ops xprt_rdma_procs;    /* forward reference */
+
+static void
+xprt_rdma_format_addresses(struct rpc_xprt *xprt)
+{
+       struct sockaddr_in *addr = (struct sockaddr_in *)
+                                       &rpcx_to_rdmad(xprt).addr;
+       char *buf;
+
+       buf = kzalloc(20, GFP_KERNEL);
+       if (buf)
+               snprintf(buf, 20, NIPQUAD_FMT, NIPQUAD(addr->sin_addr.s_addr));
+       xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
+
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf)
+               snprintf(buf, 8, "%u", ntohs(addr->sin_port));
+       xprt->address_strings[RPC_DISPLAY_PORT] = buf;
+
+       xprt->address_strings[RPC_DISPLAY_PROTO] = "rdma";
+
+       buf = kzalloc(48, GFP_KERNEL);
+       if (buf)
+               snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s",
+                       NIPQUAD(addr->sin_addr.s_addr),
+                       ntohs(addr->sin_port), "rdma");
+       xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+
+       buf = kzalloc(10, GFP_KERNEL);
+       if (buf)
+               snprintf(buf, 10, "%02x%02x%02x%02x",
+                       NIPQUAD(addr->sin_addr.s_addr));
+       xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf)
+               snprintf(buf, 8, "%4hx", ntohs(addr->sin_port));
+       xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+
+       buf = kzalloc(30, GFP_KERNEL);
+       if (buf)
+               snprintf(buf, 30, NIPQUAD_FMT".%u.%u",
+                       NIPQUAD(addr->sin_addr.s_addr),
+                       ntohs(addr->sin_port) >> 8,
+                       ntohs(addr->sin_port) & 0xff);
+       xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+
+       /* netid */
+       xprt->address_strings[RPC_DISPLAY_NETID] = "rdma";
+}
+
+static void
+xprt_rdma_free_addresses(struct rpc_xprt *xprt)
+{
+       kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
+       kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
+       kfree(xprt->address_strings[RPC_DISPLAY_ALL]);
+       kfree(xprt->address_strings[RPC_DISPLAY_HEX_ADDR]);
+       kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]);
+       kfree(xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR]);
+}
+
+static void
+xprt_rdma_connect_worker(struct work_struct *work)
+{
+       struct rpcrdma_xprt *r_xprt =
+               container_of(work, struct rpcrdma_xprt, rdma_connect.work);
+       struct rpc_xprt *xprt = &r_xprt->xprt;
+       int rc = 0;
+
+       if (!xprt->shutdown) {
+               xprt_clear_connected(xprt);
+
+               dprintk("RPC:       %s: %sconnect\n", __func__,
+                               r_xprt->rx_ep.rep_connected != 0 ? "re" : "");
+               rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
+               if (rc)
+                       goto out;
+       }
+       goto out_clear;
+
+out:
+       xprt_wake_pending_tasks(xprt, rc);
+
+out_clear:
+       dprintk("RPC:       %s: exit\n", __func__);
+       xprt_clear_connecting(xprt);
+}
+
+/*
+ * xprt_rdma_destroy
+ *
+ * Destroy the xprt.
+ * Free all memory associated with the object, including its own.
+ * NOTE: none of the *destroy methods free memory for their top-level
+ * objects, even though they may have allocated it (they do free
+ * private memory). It's up to the caller to handle it. In this
+ * case (RDMA transport), all structure memory is inlined with the
+ * struct rpcrdma_xprt.
+ */
+static void
+xprt_rdma_destroy(struct rpc_xprt *xprt)
+{
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+       int rc;
+
+       dprintk("RPC:       %s: called\n", __func__);
+
+       cancel_delayed_work(&r_xprt->rdma_connect);
+       flush_scheduled_work();
+
+       xprt_clear_connected(xprt);
+
+       rpcrdma_buffer_destroy(&r_xprt->rx_buf);
+       rc = rpcrdma_ep_destroy(&r_xprt->rx_ep, &r_xprt->rx_ia);
+       if (rc)
+               dprintk("RPC:       %s: rpcrdma_ep_destroy returned %i\n",
+                       __func__, rc);
+       rpcrdma_ia_close(&r_xprt->rx_ia);
+
+       xprt_rdma_free_addresses(xprt);
+
+       kfree(xprt->slot);
+       xprt->slot = NULL;
+       kfree(xprt);
+
+       dprintk("RPC:       %s: returning\n", __func__);
+
+       module_put(THIS_MODULE);
+}
+
+/**
+ * xprt_setup_rdma - Set up transport to use RDMA
+ *
+ * @args: rpc transport arguments
+ */
+static struct rpc_xprt *
+xprt_setup_rdma(struct xprt_create *args)
+{
+       struct rpcrdma_create_data_internal cdata;
+       struct rpc_xprt *xprt;
+       struct rpcrdma_xprt *new_xprt;
+       struct rpcrdma_ep *new_ep;
+       struct sockaddr_in *sin;
+       int rc;
+
+       if (args->addrlen > sizeof(xprt->addr)) {
+               dprintk("RPC:       %s: address too large\n", __func__);
+               return ERR_PTR(-EBADF);
+       }
+
+       xprt = kzalloc(sizeof(struct rpcrdma_xprt), GFP_KERNEL);
+       if (xprt == NULL) {
+               dprintk("RPC:       %s: couldn't allocate rpcrdma_xprt\n",
+                       __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       xprt->max_reqs = xprt_rdma_slot_table_entries;
+       xprt->slot = kcalloc(xprt->max_reqs,
+                               sizeof(struct rpc_rqst), GFP_KERNEL);
+       if (xprt->slot == NULL) {
+               kfree(xprt);
+               dprintk("RPC:       %s: couldn't allocate %d slots\n",
+                       __func__, xprt->max_reqs);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* 60 second timeout, no retries */
+       xprt_set_timeout(&xprt->timeout, 0, 60UL * HZ);
+       xprt->bind_timeout = (60U * HZ);
+       xprt->connect_timeout = (60U * HZ);
+       xprt->reestablish_timeout = (5U * HZ);
+       xprt->idle_timeout = (5U * 60 * HZ);
+
+       xprt->resvport = 0;             /* privileged port not needed */
+       xprt->tsh_size = 0;             /* RPC-RDMA handles framing */
+       xprt->max_payload = RPCRDMA_MAX_DATA_SEGS * PAGE_SIZE;
+       xprt->ops = &xprt_rdma_procs;
+
+       /*
+        * Set up RDMA-specific connect data.
+        */
+
+       /* Put server RDMA address in local cdata */
+       memcpy(&cdata.addr, args->dstaddr, args->addrlen);
+
+       /* Ensure xprt->addr holds valid server TCP (not RDMA)
+        * address, for any side protocols which peek at it */
+       xprt->prot = IPPROTO_TCP;
+       xprt->addrlen = args->addrlen;
+       memcpy(&xprt->addr, &cdata.addr, xprt->addrlen);
+
+       sin = (struct sockaddr_in *)&cdata.addr;
+       if (ntohs(sin->sin_port) != 0)
+               xprt_set_bound(xprt);
+
+       dprintk("RPC:       %s: %u.%u.%u.%u:%u\n", __func__,
+                       NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+
+       /* Set max requests */
+       cdata.max_requests = xprt->max_reqs;
+
+       /* Set some length limits */
+       cdata.rsize = RPCRDMA_MAX_SEGS * PAGE_SIZE; /* RDMA write max */
+       cdata.wsize = RPCRDMA_MAX_SEGS * PAGE_SIZE; /* RDMA read max */
+
+       cdata.inline_wsize = xprt_rdma_max_inline_write;
+       if (cdata.inline_wsize > cdata.wsize)
+               cdata.inline_wsize = cdata.wsize;
+
+       cdata.inline_rsize = xprt_rdma_max_inline_read;
+       if (cdata.inline_rsize > cdata.rsize)
+               cdata.inline_rsize = cdata.rsize;
+
+       cdata.padding = xprt_rdma_inline_write_padding;
+
+       /*
+        * Create new transport instance, which includes initialized
+        *  o ia
+        *  o endpoint
+        *  o buffers
+        */
+
+       new_xprt = rpcx_to_rdmax(xprt);
+
+       rc = rpcrdma_ia_open(new_xprt, (struct sockaddr *) &cdata.addr,
+                               xprt_rdma_memreg_strategy);
+       if (rc)
+               goto out1;
+
+       /*
+        * initialize and create ep
+        */
+       new_xprt->rx_data = cdata;
+       new_ep = &new_xprt->rx_ep;
+       new_ep->rep_remote_addr = cdata.addr;
+
+       rc = rpcrdma_ep_create(&new_xprt->rx_ep,
+                               &new_xprt->rx_ia, &new_xprt->rx_data);
+       if (rc)
+               goto out2;
+
+       /*
+        * Allocate pre-registered send and receive buffers for headers and
+        * any inline data. Also specify any padding which will be provided
+        * from a preregistered zero buffer.
+        */
+       rc = rpcrdma_buffer_create(&new_xprt->rx_buf, new_ep, &new_xprt->rx_ia,
+                               &new_xprt->rx_data);
+       if (rc)
+               goto out3;
+
+       /*
+        * Register a callback for connection events. This is necessary because
+        * connection loss notification is async. We also catch connection loss
+        * when reaping receives.
+        */
+       INIT_DELAYED_WORK(&new_xprt->rdma_connect, xprt_rdma_connect_worker);
+       new_ep->rep_func = rpcrdma_conn_func;
+       new_ep->rep_xprt = xprt;
+
+       xprt_rdma_format_addresses(xprt);
+
+       if (!try_module_get(THIS_MODULE))
+               goto out4;
+
+       return xprt;
+
+out4:
+       xprt_rdma_free_addresses(xprt);
+       rc = -EINVAL;
+out3:
+       (void) rpcrdma_ep_destroy(new_ep, &new_xprt->rx_ia);
+out2:
+       rpcrdma_ia_close(&new_xprt->rx_ia);
+out1:
+       kfree(xprt->slot);
+       kfree(xprt);
+       return ERR_PTR(rc);
+}
+
+/*
+ * Close a connection, during shutdown or timeout/reconnect
+ */
+static void
+xprt_rdma_close(struct rpc_xprt *xprt)
+{
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+       dprintk("RPC:       %s: closing\n", __func__);
+       xprt_disconnect(xprt);
+       (void) rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia);
+}
+
+static void
+xprt_rdma_set_port(struct rpc_xprt *xprt, u16 port)
+{
+       struct sockaddr_in *sap;
+
+       sap = (struct sockaddr_in *)&xprt->addr;
+       sap->sin_port = htons(port);
+       sap = (struct sockaddr_in *)&rpcx_to_rdmad(xprt).addr;
+       sap->sin_port = htons(port);
+       dprintk("RPC:       %s: %u\n", __func__, port);
+}
+
+static void
+xprt_rdma_connect(struct rpc_task *task)
+{
+       struct rpc_xprt *xprt = (struct rpc_xprt *)task->tk_xprt;
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+       if (!xprt_test_and_set_connecting(xprt)) {
+               if (r_xprt->rx_ep.rep_connected != 0) {
+                       /* Reconnect */
+                       schedule_delayed_work(&r_xprt->rdma_connect,
+                               xprt->reestablish_timeout);
+               } else {
+                       schedule_delayed_work(&r_xprt->rdma_connect, 0);
+                       if (!RPC_IS_ASYNC(task))
+                               flush_scheduled_work();
+               }
+       }
+}
+
+static int
+xprt_rdma_reserve_xprt(struct rpc_task *task)
+{
+       struct rpc_xprt *xprt = task->tk_xprt;
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+       int credits = atomic_read(&r_xprt->rx_buf.rb_credits);
+
+       /* == RPC_CWNDSCALE @ init, but *after* setup */
+       if (r_xprt->rx_buf.rb_cwndscale == 0UL) {
+               r_xprt->rx_buf.rb_cwndscale = xprt->cwnd;
+               dprintk("RPC:       %s: cwndscale %lu\n", __func__,
+                       r_xprt->rx_buf.rb_cwndscale);
+               BUG_ON(r_xprt->rx_buf.rb_cwndscale <= 0);
+       }
+       xprt->cwnd = credits * r_xprt->rx_buf.rb_cwndscale;
+       return xprt_reserve_xprt_cong(task);
+}
+
+/*
+ * The RDMA allocate/free functions need the task structure as a place
+ * to hide the struct rpcrdma_req, which is necessary for the actual send/recv
+ * sequence. For this reason, the recv buffers are attached to send
+ * buffers for portions of the RPC. Note that the RPC layer allocates
+ * both send and receive buffers in the same call. We may register
+ * the receive buffer portion when using reply chunks.
+ */
+static void *
+xprt_rdma_allocate(struct rpc_task *task, size_t size)
+{
+       struct rpc_xprt *xprt = task->tk_xprt;
+       struct rpcrdma_req *req, *nreq;
+
+       req = rpcrdma_buffer_get(&rpcx_to_rdmax(xprt)->rx_buf);
+       BUG_ON(NULL == req);
+
+       if (size > req->rl_size) {
+               dprintk("RPC:       %s: size %zd too large for buffer[%zd]: "
+                       "prog %d vers %d proc %d\n",
+                       __func__, size, req->rl_size,
+                       task->tk_client->cl_prog, task->tk_client->cl_vers,
+                       task->tk_msg.rpc_proc->p_proc);
+               /*
+                * Outgoing length shortage. Our inline write max must have
+                * been configured to perform direct i/o.
+                *
+                * This is therefore a large metadata operation, and the
+                * allocate call was made on the maximum possible message,
+                * e.g. containing long filename(s) or symlink data. In
+                * fact, while these metadata operations *might* carry
+                * large outgoing payloads, they rarely *do*. However, we
+                * have to commit to the request here, so reallocate and
+                * register it now. The data path will never require this
+                * reallocation.
+                *
+                * If the allocation or registration fails, the RPC framework
+                * will (doggedly) retry.
+                */
+               if (rpcx_to_rdmax(xprt)->rx_ia.ri_memreg_strategy ==
+                               RPCRDMA_BOUNCEBUFFERS) {
+                       /* forced to "pure inline" */
+                       dprintk("RPC:       %s: too much data (%zd) for inline "
+                                       "(r/w max %d/%d)\n", __func__, size,
+                                       rpcx_to_rdmad(xprt).inline_rsize,
+                                       rpcx_to_rdmad(xprt).inline_wsize);
+                       size = req->rl_size;
+                       rpc_exit(task, -EIO);           /* fail the operation */
+                       rpcx_to_rdmax(xprt)->rx_stats.failed_marshal_count++;
+                       goto out;
+               }
+               if (task->tk_flags & RPC_TASK_SWAPPER)
+                       nreq = kmalloc(sizeof *req + size, GFP_ATOMIC);
+               else
+                       nreq = kmalloc(sizeof *req + size, GFP_NOFS);
+               if (nreq == NULL)
+                       goto outfail;
+
+               if (rpcrdma_register_internal(&rpcx_to_rdmax(xprt)->rx_ia,
+                               nreq->rl_base, size + sizeof(struct rpcrdma_req)
+                               - offsetof(struct rpcrdma_req, rl_base),
+                               &nreq->rl_handle, &nreq->rl_iov)) {
+                       kfree(nreq);
+                       goto outfail;
+               }
+               rpcx_to_rdmax(xprt)->rx_stats.hardway_register_count += size;
+               nreq->rl_size = size;
+               nreq->rl_niovs = 0;
+               nreq->rl_nchunks = 0;
+               nreq->rl_buffer = (struct rpcrdma_buffer *)req;
+               nreq->rl_reply = req->rl_reply;
+               memcpy(nreq->rl_segments,
+                       req->rl_segments, sizeof nreq->rl_segments);
+               /* flag the swap with an unused field */
+               nreq->rl_iov.length = 0;
+               req->rl_reply = NULL;
+               req = nreq;
+       }
+       dprintk("RPC:       %s: size %zd, request 0x%p\n", __func__, size, req);
+out:
+       return req->rl_xdr_buf;
+
+outfail:
+       rpcrdma_buffer_put(req);
+       rpcx_to_rdmax(xprt)->rx_stats.failed_marshal_count++;
+       return NULL;
+}
+
+/*
+ * This function returns all RDMA resources to the pool.
+ */
+static void
+xprt_rdma_free(void *buffer)
+{
+       struct rpcrdma_req *req;
+       struct rpcrdma_xprt *r_xprt;
+       struct rpcrdma_rep *rep;
+       int i;
+
+       if (buffer == NULL)
+               return;
+
+       req = container_of(buffer, struct rpcrdma_req, rl_xdr_buf[0]);
+       r_xprt = container_of(req->rl_buffer, struct rpcrdma_xprt, rx_buf);
+       rep = req->rl_reply;
+
+       dprintk("RPC:       %s: called on 0x%p%s\n",
+               __func__, rep, (rep && rep->rr_func) ? " (with waiter)" : "");
+
+       /*
+        * Finish the deregistration. When using mw bind, this was
+        * begun in rpcrdma_reply_handler(). In all other modes, we
+        * do it here, in thread context. The process is considered
+        * complete when the rr_func vector becomes NULL - this
+        * was put in place during rpcrdma_reply_handler() - the wait
+        * call below will not block if the dereg is "done". If
+        * interrupted, our framework will clean up.
+        */
+       for (i = 0; req->rl_nchunks;) {
+               --req->rl_nchunks;
+               i += rpcrdma_deregister_external(
+                       &req->rl_segments[i], r_xprt, NULL);
+       }
+
+       if (rep && wait_event_interruptible(rep->rr_unbind, !rep->rr_func)) {
+               rep->rr_func = NULL;    /* abandon the callback */
+               req->rl_reply = NULL;
+       }
+
+       if (req->rl_iov.length == 0) {  /* see allocate above */
+               struct rpcrdma_req *oreq = (struct rpcrdma_req *)req->rl_buffer;
+               oreq->rl_reply = req->rl_reply;
+               (void) rpcrdma_deregister_internal(&r_xprt->rx_ia,
+                                                  req->rl_handle,
+                                                  &req->rl_iov);
+               kfree(req);
+               req = oreq;
+       }
+
+       /* Put back request+reply buffers */
+       rpcrdma_buffer_put(req);
+}
+
+/*
+ * send_request invokes the meat of RPC RDMA. It must do the following:
+ *  1.  Marshal the RPC request into an RPC RDMA request, which means
+ *     putting a header in front of data, and creating IOVs for RDMA
+ *     from those in the request.
+ *  2.  In marshaling, detect opportunities for RDMA, and use them.
+ *  3.  Post a recv message to set up asynch completion, then send
+ *     the request (rpcrdma_ep_post).
+ *  4.  No partial sends are possible in the RPC-RDMA protocol (as in UDP).
+ */
+
+static int
+xprt_rdma_send_request(struct rpc_task *task)
+{
+       struct rpc_rqst *rqst = task->tk_rqstp;
+       struct rpc_xprt *xprt = task->tk_xprt;
+       struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+       /* marshal the send itself */
+       if (req->rl_niovs == 0 && rpcrdma_marshal_req(rqst) != 0) {
+               r_xprt->rx_stats.failed_marshal_count++;
+               dprintk("RPC:       %s: rpcrdma_marshal_req failed\n",
+                       __func__);
+               return -EIO;
+       }
+
+       if (req->rl_reply == NULL)              /* e.g. reconnection */
+               rpcrdma_recv_buffer_get(req);
+
+       if (req->rl_reply) {
+               req->rl_reply->rr_func = rpcrdma_reply_handler;
+               /* this need only be done once, but... */
+               req->rl_reply->rr_xprt = xprt;
+       }
+
+       if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req)) {
+               xprt_disconnect(xprt);
+               return -ENOTCONN;       /* implies disconnect */
+       }
+
+       rqst->rq_bytes_sent = 0;
+       return 0;
+}
+
+static void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
+{
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+       long idle_time = 0;
+
+       if (xprt_connected(xprt))
+               idle_time = (long)(jiffies - xprt->last_used) / HZ;
+
+       seq_printf(seq,
+         "\txprt:\trdma %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu "
+         "%lu %lu %lu %Lu %Lu %Lu %Lu %lu %lu %lu\n",
+
+          0,   /* need a local port? */
+          xprt->stat.bind_count,
+          xprt->stat.connect_count,
+          xprt->stat.connect_time,
+          idle_time,
+          xprt->stat.sends,
+          xprt->stat.recvs,
+          xprt->stat.bad_xids,
+          xprt->stat.req_u,
+          xprt->stat.bklog_u,
+
+          r_xprt->rx_stats.read_chunk_count,
+          r_xprt->rx_stats.write_chunk_count,
+          r_xprt->rx_stats.reply_chunk_count,
+          r_xprt->rx_stats.total_rdma_request,
+          r_xprt->rx_stats.total_rdma_reply,
+          r_xprt->rx_stats.pullup_copy_count,
+          r_xprt->rx_stats.fixup_copy_count,
+          r_xprt->rx_stats.hardway_register_count,
+          r_xprt->rx_stats.failed_marshal_count,
+          r_xprt->rx_stats.bad_reply_count);
+}
+
+/*
+ * Plumbing for rpc transport switch and kernel module
+ */
+
+static struct rpc_xprt_ops xprt_rdma_procs = {
+       .reserve_xprt           = xprt_rdma_reserve_xprt,
+       .release_xprt           = xprt_release_xprt_cong, /* sunrpc/xprt.c */
+       .release_request        = xprt_release_rqst_cong,       /* ditto */
+       .set_retrans_timeout    = xprt_set_retrans_timeout_def, /* ditto */
+       .rpcbind                = rpcb_getport_async,   /* sunrpc/rpcb_clnt.c */
+       .set_port               = xprt_rdma_set_port,
+       .connect                = xprt_rdma_connect,
+       .buf_alloc              = xprt_rdma_allocate,
+       .buf_free               = xprt_rdma_free,
+       .send_request           = xprt_rdma_send_request,
+       .close                  = xprt_rdma_close,
+       .destroy                = xprt_rdma_destroy,
+       .print_stats            = xprt_rdma_print_stats
+};
+
+static struct xprt_class xprt_rdma = {
+       .list                   = LIST_HEAD_INIT(xprt_rdma.list),
+       .name                   = "rdma",
+       .owner                  = THIS_MODULE,
+       .ident                  = XPRT_TRANSPORT_RDMA,
+       .setup                  = xprt_setup_rdma,
+};
+
+static void __exit xprt_rdma_cleanup(void)
+{
+       int rc;
+
+       dprintk("RPCRDMA Module Removed, deregister RPC RDMA transport\n");
+#ifdef RPC_DEBUG
+       if (sunrpc_table_header) {
+               unregister_sysctl_table(sunrpc_table_header);
+               sunrpc_table_header = NULL;
+       }
+#endif
+       rc = xprt_unregister_transport(&xprt_rdma);
+       if (rc)
+               dprintk("RPC:       %s: xprt_unregister returned %i\n",
+                       __func__, rc);
+}
+
+static int __init xprt_rdma_init(void)
+{
+       int rc;
+
+       rc = xprt_register_transport(&xprt_rdma);
+
+       if (rc)
+               return rc;
+
+       dprintk(KERN_INFO "RPCRDMA Module Init, register RPC RDMA transport\n");
+
+       dprintk(KERN_INFO "Defaults:\n");
+       dprintk(KERN_INFO "\tSlots %d\n"
+               "\tMaxInlineRead %d\n\tMaxInlineWrite %d\n",
+               xprt_rdma_slot_table_entries,
+               xprt_rdma_max_inline_read, xprt_rdma_max_inline_write);
+       dprintk(KERN_INFO "\tPadding %d\n\tMemreg %d\n",
+               xprt_rdma_inline_write_padding, xprt_rdma_memreg_strategy);
+
+#ifdef RPC_DEBUG
+       if (!sunrpc_table_header)
+               sunrpc_table_header = register_sysctl_table(sunrpc_table);
+#endif
+       return 0;
+}
+
+module_init(xprt_rdma_init);
+module_exit(xprt_rdma_cleanup);
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
new file mode 100644 (file)
index 0000000..9ec8ca4
--- /dev/null
@@ -0,0 +1,1626 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      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.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * verbs.c
+ *
+ * Encapsulates the major functions managing:
+ *  o adapters
+ *  o endpoints
+ *  o connections
+ *  o buffer memory
+ */
+
+#include <linux/pci.h> /* for Tavor hack below */
+
+#include "xprt_rdma.h"
+
+/*
+ * Globals/Macros
+ */
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY       RPCDBG_TRANS
+#endif
+
+/*
+ * internal functions
+ */
+
+/*
+ * handle replies in tasklet context, using a single, global list
+ * rdma tasklet function -- just turn around and call the func
+ * for all replies on the list
+ */
+
+static DEFINE_SPINLOCK(rpcrdma_tk_lock_g);
+static LIST_HEAD(rpcrdma_tasklets_g);
+
+static void
+rpcrdma_run_tasklet(unsigned long data)
+{
+       struct rpcrdma_rep *rep;
+       void (*func)(struct rpcrdma_rep *);
+       unsigned long flags;
+
+       data = data;
+       spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
+       while (!list_empty(&rpcrdma_tasklets_g)) {
+               rep = list_entry(rpcrdma_tasklets_g.next,
+                                struct rpcrdma_rep, rr_list);
+               list_del(&rep->rr_list);
+               func = rep->rr_func;
+               rep->rr_func = NULL;
+               spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
+
+               if (func)
+                       func(rep);
+               else
+                       rpcrdma_recv_buffer_put(rep);
+
+               spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
+       }
+       spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
+}
+
+static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL);
+
+static inline void
+rpcrdma_schedule_tasklet(struct rpcrdma_rep *rep)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
+       list_add_tail(&rep->rr_list, &rpcrdma_tasklets_g);
+       spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
+       tasklet_schedule(&rpcrdma_tasklet_g);
+}
+
+static void
+rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context)
+{
+       struct rpcrdma_ep *ep = context;
+
+       dprintk("RPC:       %s: QP error %X on device %s ep %p\n",
+               __func__, event->event, event->device->name, context);
+       if (ep->rep_connected == 1) {
+               ep->rep_connected = -EIO;
+               ep->rep_func(ep);
+               wake_up_all(&ep->rep_connect_wait);
+       }
+}
+
+static void
+rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
+{
+       struct rpcrdma_ep *ep = context;
+
+       dprintk("RPC:       %s: CQ error %X on device %s ep %p\n",
+               __func__, event->event, event->device->name, context);
+       if (ep->rep_connected == 1) {
+               ep->rep_connected = -EIO;
+               ep->rep_func(ep);
+               wake_up_all(&ep->rep_connect_wait);
+       }
+}
+
+static inline
+void rpcrdma_event_process(struct ib_wc *wc)
+{
+       struct rpcrdma_rep *rep =
+                       (struct rpcrdma_rep *)(unsigned long) wc->wr_id;
+
+       dprintk("RPC:       %s: event rep %p status %X opcode %X length %u\n",
+               __func__, rep, wc->status, wc->opcode, wc->byte_len);
+
+       if (!rep) /* send or bind completion that we don't care about */
+               return;
+
+       if (IB_WC_SUCCESS != wc->status) {
+               dprintk("RPC:       %s: %s WC status %X, connection lost\n",
+                       __func__, (wc->opcode & IB_WC_RECV) ? "recv" : "send",
+                        wc->status);
+               rep->rr_len = ~0U;
+               rpcrdma_schedule_tasklet(rep);
+               return;
+       }
+
+       switch (wc->opcode) {
+       case IB_WC_RECV:
+               rep->rr_len = wc->byte_len;
+               ib_dma_sync_single_for_cpu(
+                       rdmab_to_ia(rep->rr_buffer)->ri_id->device,
+                       rep->rr_iov.addr, rep->rr_len, DMA_FROM_DEVICE);
+               /* Keep (only) the most recent credits, after check validity */
+               if (rep->rr_len >= 16) {
+                       struct rpcrdma_msg *p =
+                                       (struct rpcrdma_msg *) rep->rr_base;
+                       unsigned int credits = ntohl(p->rm_credit);
+                       if (credits == 0) {
+                               dprintk("RPC:       %s: server"
+                                       " dropped credits to 0!\n", __func__);
+                               /* don't deadlock */
+                               credits = 1;
+                       } else if (credits > rep->rr_buffer->rb_max_requests) {
+                               dprintk("RPC:       %s: server"
+                                       " over-crediting: %d (%d)\n",
+                                       __func__, credits,
+                                       rep->rr_buffer->rb_max_requests);
+                               credits = rep->rr_buffer->rb_max_requests;
+                       }
+                       atomic_set(&rep->rr_buffer->rb_credits, credits);
+               }
+               /* fall through */
+       case IB_WC_BIND_MW:
+               rpcrdma_schedule_tasklet(rep);
+               break;
+       default:
+               dprintk("RPC:       %s: unexpected WC event %X\n",
+                       __func__, wc->opcode);
+               break;
+       }
+}
+
+static inline int
+rpcrdma_cq_poll(struct ib_cq *cq)
+{
+       struct ib_wc wc;
+       int rc;
+
+       for (;;) {
+               rc = ib_poll_cq(cq, 1, &wc);
+               if (rc < 0) {
+                       dprintk("RPC:       %s: ib_poll_cq failed %i\n",
+                               __func__, rc);
+                       return rc;
+               }
+               if (rc == 0)
+                       break;
+
+               rpcrdma_event_process(&wc);
+       }
+
+       return 0;
+}
+
+/*
+ * rpcrdma_cq_event_upcall
+ *
+ * This upcall handles recv, send, bind and unbind events.
+ * It is reentrant but processes single events in order to maintain
+ * ordering of receives to keep server credits.
+ *
+ * It is the responsibility of the scheduled tasklet to return
+ * recv buffers to the pool. NOTE: this affects synchronization of
+ * connection shutdown. That is, the structures required for
+ * the completion of the reply handler must remain intact until
+ * all memory has been reclaimed.
+ *
+ * Note that send events are suppressed and do not result in an upcall.
+ */
+static void
+rpcrdma_cq_event_upcall(struct ib_cq *cq, void *context)
+{
+       int rc;
+
+       rc = rpcrdma_cq_poll(cq);
+       if (rc)
+               return;
+
+       rc = ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+       if (rc) {
+               dprintk("RPC:       %s: ib_req_notify_cq failed %i\n",
+                       __func__, rc);
+               return;
+       }
+
+       rpcrdma_cq_poll(cq);
+}
+
+#ifdef RPC_DEBUG
+static const char * const conn[] = {
+       "address resolved",
+       "address error",
+       "route resolved",
+       "route error",
+       "connect request",
+       "connect response",
+       "connect error",
+       "unreachable",
+       "rejected",
+       "established",
+       "disconnected",
+       "device removal"
+};
+#endif
+
+static int
+rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
+{
+       struct rpcrdma_xprt *xprt = id->context;
+       struct rpcrdma_ia *ia = &xprt->rx_ia;
+       struct rpcrdma_ep *ep = &xprt->rx_ep;
+       struct sockaddr_in *addr = (struct sockaddr_in *) &ep->rep_remote_addr;
+       struct ib_qp_attr attr;
+       struct ib_qp_init_attr iattr;
+       int connstate = 0;
+
+       switch (event->event) {
+       case RDMA_CM_EVENT_ADDR_RESOLVED:
+       case RDMA_CM_EVENT_ROUTE_RESOLVED:
+               complete(&ia->ri_done);
+               break;
+       case RDMA_CM_EVENT_ADDR_ERROR:
+               ia->ri_async_rc = -EHOSTUNREACH;
+               dprintk("RPC:       %s: CM address resolution error, ep 0x%p\n",
+                       __func__, ep);
+               complete(&ia->ri_done);
+               break;
+       case RDMA_CM_EVENT_ROUTE_ERROR:
+               ia->ri_async_rc = -ENETUNREACH;
+               dprintk("RPC:       %s: CM route resolution error, ep 0x%p\n",
+                       __func__, ep);
+               complete(&ia->ri_done);
+               break;
+       case RDMA_CM_EVENT_ESTABLISHED:
+               connstate = 1;
+               ib_query_qp(ia->ri_id->qp, &attr,
+                       IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC,
+                       &iattr);
+               dprintk("RPC:       %s: %d responder resources"
+                       " (%d initiator)\n",
+                       __func__, attr.max_dest_rd_atomic, attr.max_rd_atomic);
+               goto connected;
+       case RDMA_CM_EVENT_CONNECT_ERROR:
+               connstate = -ENOTCONN;
+               goto connected;
+       case RDMA_CM_EVENT_UNREACHABLE:
+               connstate = -ENETDOWN;
+               goto connected;
+       case RDMA_CM_EVENT_REJECTED:
+               connstate = -ECONNREFUSED;
+               goto connected;
+       case RDMA_CM_EVENT_DISCONNECTED:
+               connstate = -ECONNABORTED;
+               goto connected;
+       case RDMA_CM_EVENT_DEVICE_REMOVAL:
+               connstate = -ENODEV;
+connected:
+               dprintk("RPC:       %s: %s: %u.%u.%u.%u:%u"
+                       " (ep 0x%p event 0x%x)\n",
+                       __func__,
+                       (event->event <= 11) ? conn[event->event] :
+                                               "unknown connection error",
+                       NIPQUAD(addr->sin_addr.s_addr),
+                       ntohs(addr->sin_port),
+                       ep, event->event);
+               atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1);
+               dprintk("RPC:       %s: %sconnected\n",
+                                       __func__, connstate > 0 ? "" : "dis");
+               ep->rep_connected = connstate;
+               ep->rep_func(ep);
+               wake_up_all(&ep->rep_connect_wait);
+               break;
+       default:
+               ia->ri_async_rc = -EINVAL;
+               dprintk("RPC:       %s: unexpected CM event %X\n",
+                       __func__, event->event);
+               complete(&ia->ri_done);
+               break;
+       }
+
+       return 0;
+}
+
+static struct rdma_cm_id *
+rpcrdma_create_id(struct rpcrdma_xprt *xprt,
+                       struct rpcrdma_ia *ia, struct sockaddr *addr)
+{
+       struct rdma_cm_id *id;
+       int rc;
+
+       id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP);
+       if (IS_ERR(id)) {
+               rc = PTR_ERR(id);
+               dprintk("RPC:       %s: rdma_create_id() failed %i\n",
+                       __func__, rc);
+               return id;
+       }
+
+       ia->ri_async_rc = 0;
+       rc = rdma_resolve_addr(id, NULL, addr, RDMA_RESOLVE_TIMEOUT);
+       if (rc) {
+               dprintk("RPC:       %s: rdma_resolve_addr() failed %i\n",
+                       __func__, rc);
+               goto out;
+       }
+       wait_for_completion(&ia->ri_done);
+       rc = ia->ri_async_rc;
+       if (rc)
+               goto out;
+
+       ia->ri_async_rc = 0;
+       rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT);
+       if (rc) {
+               dprintk("RPC:       %s: rdma_resolve_route() failed %i\n",
+                       __func__, rc);
+               goto out;
+       }
+       wait_for_completion(&ia->ri_done);
+       rc = ia->ri_async_rc;
+       if (rc)
+               goto out;
+
+       return id;
+
+out:
+       rdma_destroy_id(id);
+       return ERR_PTR(rc);
+}
+
+/*
+ * Drain any cq, prior to teardown.
+ */
+static void
+rpcrdma_clean_cq(struct ib_cq *cq)
+{
+       struct ib_wc wc;
+       int count = 0;
+
+       while (1 == ib_poll_cq(cq, 1, &wc))
+               ++count;
+
+       if (count)
+               dprintk("RPC:       %s: flushed %d events (last 0x%x)\n",
+                       __func__, count, wc.opcode);
+}
+
+/*
+ * Exported functions.
+ */
+
+/*
+ * Open and initialize an Interface Adapter.
+ *  o initializes fields of struct rpcrdma_ia, including
+ *    interface and provider attributes and protection zone.
+ */
+int
+rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg)
+{
+       int rc;
+       struct rpcrdma_ia *ia = &xprt->rx_ia;
+
+       init_completion(&ia->ri_done);
+
+       ia->ri_id = rpcrdma_create_id(xprt, ia, addr);
+       if (IS_ERR(ia->ri_id)) {
+               rc = PTR_ERR(ia->ri_id);
+               goto out1;
+       }
+
+       ia->ri_pd = ib_alloc_pd(ia->ri_id->device);
+       if (IS_ERR(ia->ri_pd)) {
+               rc = PTR_ERR(ia->ri_pd);
+               dprintk("RPC:       %s: ib_alloc_pd() failed %i\n",
+                       __func__, rc);
+               goto out2;
+       }
+
+       /*
+        * Optionally obtain an underlying physical identity mapping in
+        * order to do a memory window-based bind. This base registration
+        * is protected from remote access - that is enabled only by binding
+        * for the specific bytes targeted during each RPC operation, and
+        * revoked after the corresponding completion similar to a storage
+        * adapter.
+        */
+       if (memreg > RPCRDMA_REGISTER) {
+               int mem_priv = IB_ACCESS_LOCAL_WRITE;
+               switch (memreg) {
+#if RPCRDMA_PERSISTENT_REGISTRATION
+               case RPCRDMA_ALLPHYSICAL:
+                       mem_priv |= IB_ACCESS_REMOTE_WRITE;
+                       mem_priv |= IB_ACCESS_REMOTE_READ;
+                       break;
+#endif
+               case RPCRDMA_MEMWINDOWS_ASYNC:
+               case RPCRDMA_MEMWINDOWS:
+                       mem_priv |= IB_ACCESS_MW_BIND;
+                       break;
+               default:
+                       break;
+               }
+               ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv);
+               if (IS_ERR(ia->ri_bind_mem)) {
+                       printk(KERN_ALERT "%s: ib_get_dma_mr for "
+                               "phys register failed with %lX\n\t"
+                               "Will continue with degraded performance\n",
+                               __func__, PTR_ERR(ia->ri_bind_mem));
+                       memreg = RPCRDMA_REGISTER;
+                       ia->ri_bind_mem = NULL;
+               }
+       }
+
+       /* Else will do memory reg/dereg for each chunk */
+       ia->ri_memreg_strategy = memreg;
+
+       return 0;
+out2:
+       rdma_destroy_id(ia->ri_id);
+out1:
+       return rc;
+}
+
+/*
+ * Clean up/close an IA.
+ *   o if event handles and PD have been initialized, free them.
+ *   o close the IA
+ */
+void
+rpcrdma_ia_close(struct rpcrdma_ia *ia)
+{
+       int rc;
+
+       dprintk("RPC:       %s: entering\n", __func__);
+       if (ia->ri_bind_mem != NULL) {
+               rc = ib_dereg_mr(ia->ri_bind_mem);
+               dprintk("RPC:       %s: ib_dereg_mr returned %i\n",
+                       __func__, rc);
+       }
+       if (ia->ri_id != NULL && !IS_ERR(ia->ri_id) && ia->ri_id->qp)
+               rdma_destroy_qp(ia->ri_id);
+       if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
+               rc = ib_dealloc_pd(ia->ri_pd);
+               dprintk("RPC:       %s: ib_dealloc_pd returned %i\n",
+                       __func__, rc);
+       }
+       if (ia->ri_id != NULL && !IS_ERR(ia->ri_id))
+               rdma_destroy_id(ia->ri_id);
+}
+
+/*
+ * Create unconnected endpoint.
+ */
+int
+rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
+                               struct rpcrdma_create_data_internal *cdata)
+{
+       struct ib_device_attr devattr;
+       int rc;
+
+       rc = ib_query_device(ia->ri_id->device, &devattr);
+       if (rc) {
+               dprintk("RPC:       %s: ib_query_device failed %d\n",
+                       __func__, rc);
+               return rc;
+       }
+
+       /* check provider's send/recv wr limits */
+       if (cdata->max_requests > devattr.max_qp_wr)
+               cdata->max_requests = devattr.max_qp_wr;
+
+       ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall;
+       ep->rep_attr.qp_context = ep;
+       /* send_cq and recv_cq initialized below */
+       ep->rep_attr.srq = NULL;
+       ep->rep_attr.cap.max_send_wr = cdata->max_requests;
+       switch (ia->ri_memreg_strategy) {
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+       case RPCRDMA_MEMWINDOWS:
+               /* Add room for mw_binds+unbinds - overkill! */
+               ep->rep_attr.cap.max_send_wr++;
+               ep->rep_attr.cap.max_send_wr *= (2 * RPCRDMA_MAX_SEGS);
+               if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr)
+                       return -EINVAL;
+               break;
+       default:
+               break;
+       }
+       ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
+       ep->rep_attr.cap.max_send_sge = (cdata->padding ? 4 : 2);
+       ep->rep_attr.cap.max_recv_sge = 1;
+       ep->rep_attr.cap.max_inline_data = 0;
+       ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+       ep->rep_attr.qp_type = IB_QPT_RC;
+       ep->rep_attr.port_num = ~0;
+
+       dprintk("RPC:       %s: requested max: dtos: send %d recv %d; "
+               "iovs: send %d recv %d\n",
+               __func__,
+               ep->rep_attr.cap.max_send_wr,
+               ep->rep_attr.cap.max_recv_wr,
+               ep->rep_attr.cap.max_send_sge,
+               ep->rep_attr.cap.max_recv_sge);
+
+       /* set trigger for requesting send completion */
+       ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 /*  - 1*/;
+       switch (ia->ri_memreg_strategy) {
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+       case RPCRDMA_MEMWINDOWS:
+               ep->rep_cqinit -= RPCRDMA_MAX_SEGS;
+               break;
+       default:
+               break;
+       }
+       if (ep->rep_cqinit <= 2)
+               ep->rep_cqinit = 0;
+       INIT_CQCOUNT(ep);
+       ep->rep_ia = ia;
+       init_waitqueue_head(&ep->rep_connect_wait);
+
+       /*
+        * Create a single cq for receive dto and mw_bind (only ever
+        * care about unbind, really). Send completions are suppressed.
+        * Use single threaded tasklet upcalls to maintain ordering.
+        */
+       ep->rep_cq = ib_create_cq(ia->ri_id->device, rpcrdma_cq_event_upcall,
+                                 rpcrdma_cq_async_error_upcall, NULL,
+                                 ep->rep_attr.cap.max_recv_wr +
+                                 ep->rep_attr.cap.max_send_wr + 1, 0);
+       if (IS_ERR(ep->rep_cq)) {
+               rc = PTR_ERR(ep->rep_cq);
+               dprintk("RPC:       %s: ib_create_cq failed: %i\n",
+                       __func__, rc);
+               goto out1;
+       }
+
+       rc = ib_req_notify_cq(ep->rep_cq, IB_CQ_NEXT_COMP);
+       if (rc) {
+               dprintk("RPC:       %s: ib_req_notify_cq failed: %i\n",
+                       __func__, rc);
+               goto out2;
+       }
+
+       ep->rep_attr.send_cq = ep->rep_cq;
+       ep->rep_attr.recv_cq = ep->rep_cq;
+
+       /* Initialize cma parameters */
+
+       /* RPC/RDMA does not use private data */
+       ep->rep_remote_cma.private_data = NULL;
+       ep->rep_remote_cma.private_data_len = 0;
+
+       /* Client offers RDMA Read but does not initiate */
+       switch (ia->ri_memreg_strategy) {
+       case RPCRDMA_BOUNCEBUFFERS:
+               ep->rep_remote_cma.responder_resources = 0;
+               break;
+       case RPCRDMA_MTHCAFMR:
+       case RPCRDMA_REGISTER:
+               ep->rep_remote_cma.responder_resources = cdata->max_requests *
+                               (RPCRDMA_MAX_DATA_SEGS / 8);
+               break;
+       case RPCRDMA_MEMWINDOWS:
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+#if RPCRDMA_PERSISTENT_REGISTRATION
+       case RPCRDMA_ALLPHYSICAL:
+#endif
+               ep->rep_remote_cma.responder_resources = cdata->max_requests *
+                               (RPCRDMA_MAX_DATA_SEGS / 2);
+               break;
+       default:
+               break;
+       }
+       if (ep->rep_remote_cma.responder_resources > devattr.max_qp_rd_atom)
+               ep->rep_remote_cma.responder_resources = devattr.max_qp_rd_atom;
+       ep->rep_remote_cma.initiator_depth = 0;
+
+       ep->rep_remote_cma.retry_count = 7;
+       ep->rep_remote_cma.flow_control = 0;
+       ep->rep_remote_cma.rnr_retry_count = 0;
+
+       return 0;
+
+out2:
+       if (ib_destroy_cq(ep->rep_cq))
+               ;
+out1:
+       return rc;
+}
+
+/*
+ * rpcrdma_ep_destroy
+ *
+ * Disconnect and destroy endpoint. After this, the only
+ * valid operations on the ep are to free it (if dynamically
+ * allocated) or re-create it.
+ *
+ * The caller's error handling must be sure to not leak the endpoint
+ * if this function fails.
+ */
+int
+rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
+{
+       int rc;
+
+       dprintk("RPC:       %s: entering, connected is %d\n",
+               __func__, ep->rep_connected);
+
+       if (ia->ri_id->qp) {
+               rc = rpcrdma_ep_disconnect(ep, ia);
+               if (rc)
+                       dprintk("RPC:       %s: rpcrdma_ep_disconnect"
+                               " returned %i\n", __func__, rc);
+       }
+
+       ep->rep_func = NULL;
+
+       /* padding - could be done in rpcrdma_buffer_destroy... */
+       if (ep->rep_pad_mr) {
+               rpcrdma_deregister_internal(ia, ep->rep_pad_mr, &ep->rep_pad);
+               ep->rep_pad_mr = NULL;
+       }
+
+       if (ia->ri_id->qp) {
+               rdma_destroy_qp(ia->ri_id);
+               ia->ri_id->qp = NULL;
+       }
+
+       rpcrdma_clean_cq(ep->rep_cq);
+       rc = ib_destroy_cq(ep->rep_cq);
+       if (rc)
+               dprintk("RPC:       %s: ib_destroy_cq returned %i\n",
+                       __func__, rc);
+
+       return rc;
+}
+
+/*
+ * Connect unconnected endpoint.
+ */
+int
+rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
+{
+       struct rdma_cm_id *id;
+       int rc = 0;
+       int retry_count = 0;
+       int reconnect = (ep->rep_connected != 0);
+
+       if (reconnect) {
+               struct rpcrdma_xprt *xprt;
+retry:
+               rc = rpcrdma_ep_disconnect(ep, ia);
+               if (rc && rc != -ENOTCONN)
+                       dprintk("RPC:       %s: rpcrdma_ep_disconnect"
+                               " status %i\n", __func__, rc);
+               rpcrdma_clean_cq(ep->rep_cq);
+
+               xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
+               id = rpcrdma_create_id(xprt, ia,
+                               (struct sockaddr *)&xprt->rx_data.addr);
+               if (IS_ERR(id)) {
+                       rc = PTR_ERR(id);
+                       goto out;
+               }
+               /* TEMP TEMP TEMP - fail if new device:
+                * Deregister/remarshal *all* requests!
+                * Close and recreate adapter, pd, etc!
+                * Re-determine all attributes still sane!
+                * More stuff I haven't thought of!
+                * Rrrgh!
+                */
+               if (ia->ri_id->device != id->device) {
+                       printk("RPC:       %s: can't reconnect on "
+                               "different device!\n", __func__);
+                       rdma_destroy_id(id);
+                       rc = -ENETDOWN;
+                       goto out;
+               }
+               /* END TEMP */
+               rdma_destroy_id(ia->ri_id);
+               ia->ri_id = id;
+       }
+
+       rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr);
+       if (rc) {
+               dprintk("RPC:       %s: rdma_create_qp failed %i\n",
+                       __func__, rc);
+               goto out;
+       }
+
+/* XXX Tavor device performs badly with 2K MTU! */
+if (strnicmp(ia->ri_id->device->dma_device->bus->name, "pci", 3) == 0) {
+       struct pci_dev *pcid = to_pci_dev(ia->ri_id->device->dma_device);
+       if (pcid->device == PCI_DEVICE_ID_MELLANOX_TAVOR &&
+           (pcid->vendor == PCI_VENDOR_ID_MELLANOX ||
+            pcid->vendor == PCI_VENDOR_ID_TOPSPIN)) {
+               struct ib_qp_attr attr = {
+                       .path_mtu = IB_MTU_1024
+               };
+               rc = ib_modify_qp(ia->ri_id->qp, &attr, IB_QP_PATH_MTU);
+       }
+}
+
+       /* Theoretically a client initiator_depth > 0 is not needed,
+        * but many peers fail to complete the connection unless they
+        * == responder_resources! */
+       if (ep->rep_remote_cma.initiator_depth !=
+                               ep->rep_remote_cma.responder_resources)
+               ep->rep_remote_cma.initiator_depth =
+                       ep->rep_remote_cma.responder_resources;
+
+       ep->rep_connected = 0;
+
+       rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma);
+       if (rc) {
+               dprintk("RPC:       %s: rdma_connect() failed with %i\n",
+                               __func__, rc);
+               goto out;
+       }
+
+       if (reconnect)
+               return 0;
+
+       wait_event_interruptible(ep->rep_connect_wait, ep->rep_connected != 0);
+
+       /*
+        * Check state. A non-peer reject indicates no listener
+        * (ECONNREFUSED), which may be a transient state. All
+        * others indicate a transport condition which has already
+        * undergone a best-effort.
+        */
+       if (ep->rep_connected == -ECONNREFUSED
+           && ++retry_count <= RDMA_CONNECT_RETRY_MAX) {
+               dprintk("RPC:       %s: non-peer_reject, retry\n", __func__);
+               goto retry;
+       }
+       if (ep->rep_connected <= 0) {
+               /* Sometimes, the only way to reliably connect to remote
+                * CMs is to use same nonzero values for ORD and IRD. */
+               ep->rep_remote_cma.initiator_depth =
+                                       ep->rep_remote_cma.responder_resources;
+               if (ep->rep_remote_cma.initiator_depth == 0)
+                       ++ep->rep_remote_cma.initiator_depth;
+               if (ep->rep_remote_cma.responder_resources == 0)
+                       ++ep->rep_remote_cma.responder_resources;
+               if (retry_count++ == 0)
+                       goto retry;
+               rc = ep->rep_connected;
+       } else {
+               dprintk("RPC:       %s: connected\n", __func__);
+       }
+
+out:
+       if (rc)
+               ep->rep_connected = rc;
+       return rc;
+}
+
+/*
+ * rpcrdma_ep_disconnect
+ *
+ * This is separate from destroy to facilitate the ability
+ * to reconnect without recreating the endpoint.
+ *
+ * This call is not reentrant, and must not be made in parallel
+ * on the same endpoint.
+ */
+int
+rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
+{
+       int rc;
+
+       rpcrdma_clean_cq(ep->rep_cq);
+       rc = rdma_disconnect(ia->ri_id);
+       if (!rc) {
+               /* returns without wait if not connected */
+               wait_event_interruptible(ep->rep_connect_wait,
+                                                       ep->rep_connected != 1);
+               dprintk("RPC:       %s: after wait, %sconnected\n", __func__,
+                       (ep->rep_connected == 1) ? "still " : "dis");
+       } else {
+               dprintk("RPC:       %s: rdma_disconnect %i\n", __func__, rc);
+               ep->rep_connected = rc;
+       }
+       return rc;
+}
+
+/*
+ * Initialize buffer memory
+ */
+int
+rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep,
+       struct rpcrdma_ia *ia, struct rpcrdma_create_data_internal *cdata)
+{
+       char *p;
+       size_t len;
+       int i, rc;
+
+       buf->rb_max_requests = cdata->max_requests;
+       spin_lock_init(&buf->rb_lock);
+       atomic_set(&buf->rb_credits, 1);
+
+       /* Need to allocate:
+        *   1.  arrays for send and recv pointers
+        *   2.  arrays of struct rpcrdma_req to fill in pointers
+        *   3.  array of struct rpcrdma_rep for replies
+        *   4.  padding, if any
+        *   5.  mw's, if any
+        * Send/recv buffers in req/rep need to be registered
+        */
+
+       len = buf->rb_max_requests *
+               (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *));
+       len += cdata->padding;
+       switch (ia->ri_memreg_strategy) {
+       case RPCRDMA_MTHCAFMR:
+               /* TBD we are perhaps overallocating here */
+               len += (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS *
+                               sizeof(struct rpcrdma_mw);
+               break;
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+       case RPCRDMA_MEMWINDOWS:
+               len += (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS *
+                               sizeof(struct rpcrdma_mw);
+               break;
+       default:
+               break;
+       }
+
+       /* allocate 1, 4 and 5 in one shot */
+       p = kzalloc(len, GFP_KERNEL);
+       if (p == NULL) {
+               dprintk("RPC:       %s: req_t/rep_t/pad kzalloc(%zd) failed\n",
+                       __func__, len);
+               rc = -ENOMEM;
+               goto out;
+       }
+       buf->rb_pool = p;       /* for freeing it later */
+
+       buf->rb_send_bufs = (struct rpcrdma_req **) p;
+       p = (char *) &buf->rb_send_bufs[buf->rb_max_requests];
+       buf->rb_recv_bufs = (struct rpcrdma_rep **) p;
+       p = (char *) &buf->rb_recv_bufs[buf->rb_max_requests];
+
+       /*
+        * Register the zeroed pad buffer, if any.
+        */
+       if (cdata->padding) {
+               rc = rpcrdma_register_internal(ia, p, cdata->padding,
+                                           &ep->rep_pad_mr, &ep->rep_pad);
+               if (rc)
+                       goto out;
+       }
+       p += cdata->padding;
+
+       /*
+        * Allocate the fmr's, or mw's for mw_bind chunk registration.
+        * We "cycle" the mw's in order to minimize rkey reuse,
+        * and also reduce unbind-to-bind collision.
+        */
+       INIT_LIST_HEAD(&buf->rb_mws);
+       switch (ia->ri_memreg_strategy) {
+       case RPCRDMA_MTHCAFMR:
+               {
+               struct rpcrdma_mw *r = (struct rpcrdma_mw *)p;
+               struct ib_fmr_attr fa = {
+                       RPCRDMA_MAX_DATA_SEGS, 1, PAGE_SHIFT
+               };
+               /* TBD we are perhaps overallocating here */
+               for (i = (buf->rb_max_requests+1) * RPCRDMA_MAX_SEGS; i; i--) {
+                       r->r.fmr = ib_alloc_fmr(ia->ri_pd,
+                               IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ,
+                               &fa);
+                       if (IS_ERR(r->r.fmr)) {
+                               rc = PTR_ERR(r->r.fmr);
+                               dprintk("RPC:       %s: ib_alloc_fmr"
+                                       " failed %i\n", __func__, rc);
+                               goto out;
+                       }
+                       list_add(&r->mw_list, &buf->rb_mws);
+                       ++r;
+               }
+               }
+               break;
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+       case RPCRDMA_MEMWINDOWS:
+               {
+               struct rpcrdma_mw *r = (struct rpcrdma_mw *)p;
+               /* Allocate one extra request's worth, for full cycling */
+               for (i = (buf->rb_max_requests+1) * RPCRDMA_MAX_SEGS; i; i--) {
+                       r->r.mw = ib_alloc_mw(ia->ri_pd);
+                       if (IS_ERR(r->r.mw)) {
+                               rc = PTR_ERR(r->r.mw);
+                               dprintk("RPC:       %s: ib_alloc_mw"
+                                       " failed %i\n", __func__, rc);
+                               goto out;
+                       }
+                       list_add(&r->mw_list, &buf->rb_mws);
+                       ++r;
+               }
+               }
+               break;
+       default:
+               break;
+       }
+
+       /*
+        * Allocate/init the request/reply buffers. Doing this
+        * using kmalloc for now -- one for each buf.
+        */
+       for (i = 0; i < buf->rb_max_requests; i++) {
+               struct rpcrdma_req *req;
+               struct rpcrdma_rep *rep;
+
+               len = cdata->inline_wsize + sizeof(struct rpcrdma_req);
+               /* RPC layer requests *double* size + 1K RPC_SLACK_SPACE! */
+               /* Typical ~2400b, so rounding up saves work later */
+               if (len < 4096)
+                       len = 4096;
+               req = kmalloc(len, GFP_KERNEL);
+               if (req == NULL) {
+                       dprintk("RPC:       %s: request buffer %d alloc"
+                               " failed\n", __func__, i);
+                       rc = -ENOMEM;
+                       goto out;
+               }
+               memset(req, 0, sizeof(struct rpcrdma_req));
+               buf->rb_send_bufs[i] = req;
+               buf->rb_send_bufs[i]->rl_buffer = buf;
+
+               rc = rpcrdma_register_internal(ia, req->rl_base,
+                               len - offsetof(struct rpcrdma_req, rl_base),
+                               &buf->rb_send_bufs[i]->rl_handle,
+                               &buf->rb_send_bufs[i]->rl_iov);
+               if (rc)
+                       goto out;
+
+               buf->rb_send_bufs[i]->rl_size = len-sizeof(struct rpcrdma_req);
+
+               len = cdata->inline_rsize + sizeof(struct rpcrdma_rep);
+               rep = kmalloc(len, GFP_KERNEL);
+               if (rep == NULL) {
+                       dprintk("RPC:       %s: reply buffer %d alloc failed\n",
+                               __func__, i);
+                       rc = -ENOMEM;
+                       goto out;
+               }
+               memset(rep, 0, sizeof(struct rpcrdma_rep));
+               buf->rb_recv_bufs[i] = rep;
+               buf->rb_recv_bufs[i]->rr_buffer = buf;
+               init_waitqueue_head(&rep->rr_unbind);
+
+               rc = rpcrdma_register_internal(ia, rep->rr_base,
+                               len - offsetof(struct rpcrdma_rep, rr_base),
+                               &buf->rb_recv_bufs[i]->rr_handle,
+                               &buf->rb_recv_bufs[i]->rr_iov);
+               if (rc)
+                       goto out;
+
+       }
+       dprintk("RPC:       %s: max_requests %d\n",
+               __func__, buf->rb_max_requests);
+       /* done */
+       return 0;
+out:
+       rpcrdma_buffer_destroy(buf);
+       return rc;
+}
+
+/*
+ * Unregister and destroy buffer memory. Need to deal with
+ * partial initialization, so it's callable from failed create.
+ * Must be called before destroying endpoint, as registrations
+ * reference it.
+ */
+void
+rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
+{
+       int rc, i;
+       struct rpcrdma_ia *ia = rdmab_to_ia(buf);
+
+       /* clean up in reverse order from create
+        *   1.  recv mr memory (mr free, then kfree)
+        *   1a. bind mw memory
+        *   2.  send mr memory (mr free, then kfree)
+        *   3.  padding (if any) [moved to rpcrdma_ep_destroy]
+        *   4.  arrays
+        */
+       dprintk("RPC:       %s: entering\n", __func__);
+
+       for (i = 0; i < buf->rb_max_requests; i++) {
+               if (buf->rb_recv_bufs && buf->rb_recv_bufs[i]) {
+                       rpcrdma_deregister_internal(ia,
+                                       buf->rb_recv_bufs[i]->rr_handle,
+                                       &buf->rb_recv_bufs[i]->rr_iov);
+                       kfree(buf->rb_recv_bufs[i]);
+               }
+               if (buf->rb_send_bufs && buf->rb_send_bufs[i]) {
+                       while (!list_empty(&buf->rb_mws)) {
+                               struct rpcrdma_mw *r;
+                               r = list_entry(buf->rb_mws.next,
+                                       struct rpcrdma_mw, mw_list);
+                               list_del(&r->mw_list);
+                               switch (ia->ri_memreg_strategy) {
+                               case RPCRDMA_MTHCAFMR:
+                                       rc = ib_dealloc_fmr(r->r.fmr);
+                                       if (rc)
+                                               dprintk("RPC:       %s:"
+                                                       " ib_dealloc_fmr"
+                                                       " failed %i\n",
+                                                       __func__, rc);
+                                       break;
+                               case RPCRDMA_MEMWINDOWS_ASYNC:
+                               case RPCRDMA_MEMWINDOWS:
+                                       rc = ib_dealloc_mw(r->r.mw);
+                                       if (rc)
+                                               dprintk("RPC:       %s:"
+                                                       " ib_dealloc_mw"
+                                                       " failed %i\n",
+                                                       __func__, rc);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       rpcrdma_deregister_internal(ia,
+                                       buf->rb_send_bufs[i]->rl_handle,
+                                       &buf->rb_send_bufs[i]->rl_iov);
+                       kfree(buf->rb_send_bufs[i]);
+               }
+       }
+
+       kfree(buf->rb_pool);
+}
+
+/*
+ * Get a set of request/reply buffers.
+ *
+ * Reply buffer (if needed) is attached to send buffer upon return.
+ * Rule:
+ *    rb_send_index and rb_recv_index MUST always be pointing to the
+ *    *next* available buffer (non-NULL). They are incremented after
+ *    removing buffers, and decremented *before* returning them.
+ */
+struct rpcrdma_req *
+rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
+{
+       struct rpcrdma_req *req;
+       unsigned long flags;
+
+       spin_lock_irqsave(&buffers->rb_lock, flags);
+       if (buffers->rb_send_index == buffers->rb_max_requests) {
+               spin_unlock_irqrestore(&buffers->rb_lock, flags);
+               dprintk("RPC:       %s: out of request buffers\n", __func__);
+               return ((struct rpcrdma_req *)NULL);
+       }
+
+       req = buffers->rb_send_bufs[buffers->rb_send_index];
+       if (buffers->rb_send_index < buffers->rb_recv_index) {
+               dprintk("RPC:       %s: %d extra receives outstanding (ok)\n",
+                       __func__,
+                       buffers->rb_recv_index - buffers->rb_send_index);
+               req->rl_reply = NULL;
+       } else {
+               req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
+               buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
+       }
+       buffers->rb_send_bufs[buffers->rb_send_index++] = NULL;
+       if (!list_empty(&buffers->rb_mws)) {
+               int i = RPCRDMA_MAX_SEGS - 1;
+               do {
+                       struct rpcrdma_mw *r;
+                       r = list_entry(buffers->rb_mws.next,
+                                       struct rpcrdma_mw, mw_list);
+                       list_del(&r->mw_list);
+                       req->rl_segments[i].mr_chunk.rl_mw = r;
+               } while (--i >= 0);
+       }
+       spin_unlock_irqrestore(&buffers->rb_lock, flags);
+       return req;
+}
+
+/*
+ * Put request/reply buffers back into pool.
+ * Pre-decrement counter/array index.
+ */
+void
+rpcrdma_buffer_put(struct rpcrdma_req *req)
+{
+       struct rpcrdma_buffer *buffers = req->rl_buffer;
+       struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
+       int i;
+       unsigned long flags;
+
+       BUG_ON(req->rl_nchunks != 0);
+       spin_lock_irqsave(&buffers->rb_lock, flags);
+       buffers->rb_send_bufs[--buffers->rb_send_index] = req;
+       req->rl_niovs = 0;
+       if (req->rl_reply) {
+               buffers->rb_recv_bufs[--buffers->rb_recv_index] = req->rl_reply;
+               init_waitqueue_head(&req->rl_reply->rr_unbind);
+               req->rl_reply->rr_func = NULL;
+               req->rl_reply = NULL;
+       }
+       switch (ia->ri_memreg_strategy) {
+       case RPCRDMA_MTHCAFMR:
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+       case RPCRDMA_MEMWINDOWS:
+               /*
+                * Cycle mw's back in reverse order, and "spin" them.
+                * This delays and scrambles reuse as much as possible.
+                */
+               i = 1;
+               do {
+                       struct rpcrdma_mw **mw;
+                       mw = &req->rl_segments[i].mr_chunk.rl_mw;
+                       list_add_tail(&(*mw)->mw_list, &buffers->rb_mws);
+                       *mw = NULL;
+               } while (++i < RPCRDMA_MAX_SEGS);
+               list_add_tail(&req->rl_segments[0].mr_chunk.rl_mw->mw_list,
+                                       &buffers->rb_mws);
+               req->rl_segments[0].mr_chunk.rl_mw = NULL;
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&buffers->rb_lock, flags);
+}
+
+/*
+ * Recover reply buffers from pool.
+ * This happens when recovering from error conditions.
+ * Post-increment counter/array index.
+ */
+void
+rpcrdma_recv_buffer_get(struct rpcrdma_req *req)
+{
+       struct rpcrdma_buffer *buffers = req->rl_buffer;
+       unsigned long flags;
+
+       if (req->rl_iov.length == 0)    /* special case xprt_rdma_allocate() */
+               buffers = ((struct rpcrdma_req *) buffers)->rl_buffer;
+       spin_lock_irqsave(&buffers->rb_lock, flags);
+       if (buffers->rb_recv_index < buffers->rb_max_requests) {
+               req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
+               buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
+       }
+       spin_unlock_irqrestore(&buffers->rb_lock, flags);
+}
+
+/*
+ * Put reply buffers back into pool when not attached to
+ * request. This happens in error conditions, and when
+ * aborting unbinds. Pre-decrement counter/array index.
+ */
+void
+rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
+{
+       struct rpcrdma_buffer *buffers = rep->rr_buffer;
+       unsigned long flags;
+
+       rep->rr_func = NULL;
+       spin_lock_irqsave(&buffers->rb_lock, flags);
+       buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep;
+       spin_unlock_irqrestore(&buffers->rb_lock, flags);
+}
+
+/*
+ * Wrappers for internal-use kmalloc memory registration, used by buffer code.
+ */
+
+int
+rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len,
+                               struct ib_mr **mrp, struct ib_sge *iov)
+{
+       struct ib_phys_buf ipb;
+       struct ib_mr *mr;
+       int rc;
+
+       /*
+        * All memory passed here was kmalloc'ed, therefore phys-contiguous.
+        */
+       iov->addr = ib_dma_map_single(ia->ri_id->device,
+                       va, len, DMA_BIDIRECTIONAL);
+       iov->length = len;
+
+       if (ia->ri_bind_mem != NULL) {
+               *mrp = NULL;
+               iov->lkey = ia->ri_bind_mem->lkey;
+               return 0;
+       }
+
+       ipb.addr = iov->addr;
+       ipb.size = iov->length;
+       mr = ib_reg_phys_mr(ia->ri_pd, &ipb, 1,
+                       IB_ACCESS_LOCAL_WRITE, &iov->addr);
+
+       dprintk("RPC:       %s: phys convert: 0x%llx "
+                       "registered 0x%llx length %d\n",
+                       __func__, ipb.addr, iov->addr, len);
+
+       if (IS_ERR(mr)) {
+               *mrp = NULL;
+               rc = PTR_ERR(mr);
+               dprintk("RPC:       %s: failed with %i\n", __func__, rc);
+       } else {
+               *mrp = mr;
+               iov->lkey = mr->lkey;
+               rc = 0;
+       }
+
+       return rc;
+}
+
+int
+rpcrdma_deregister_internal(struct rpcrdma_ia *ia,
+                               struct ib_mr *mr, struct ib_sge *iov)
+{
+       int rc;
+
+       ib_dma_unmap_single(ia->ri_id->device,
+                       iov->addr, iov->length, DMA_BIDIRECTIONAL);
+
+       if (NULL == mr)
+               return 0;
+
+       rc = ib_dereg_mr(mr);
+       if (rc)
+               dprintk("RPC:       %s: ib_dereg_mr failed %i\n", __func__, rc);
+       return rc;
+}
+
+/*
+ * Wrappers for chunk registration, shared by read/write chunk code.
+ */
+
+static void
+rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing)
+{
+       seg->mr_dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+       seg->mr_dmalen = seg->mr_len;
+       if (seg->mr_page)
+               seg->mr_dma = ib_dma_map_page(ia->ri_id->device,
+                               seg->mr_page, offset_in_page(seg->mr_offset),
+                               seg->mr_dmalen, seg->mr_dir);
+       else
+               seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
+                               seg->mr_offset,
+                               seg->mr_dmalen, seg->mr_dir);
+}
+
+static void
+rpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg)
+{
+       if (seg->mr_page)
+               ib_dma_unmap_page(ia->ri_id->device,
+                               seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
+       else
+               ib_dma_unmap_single(ia->ri_id->device,
+                               seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
+}
+
+int
+rpcrdma_register_external(struct rpcrdma_mr_seg *seg,
+                       int nsegs, int writing, struct rpcrdma_xprt *r_xprt)
+{
+       struct rpcrdma_ia *ia = &r_xprt->rx_ia;
+       int mem_priv = (writing ? IB_ACCESS_REMOTE_WRITE :
+                                 IB_ACCESS_REMOTE_READ);
+       struct rpcrdma_mr_seg *seg1 = seg;
+       int i;
+       int rc = 0;
+
+       switch (ia->ri_memreg_strategy) {
+
+#if RPCRDMA_PERSISTENT_REGISTRATION
+       case RPCRDMA_ALLPHYSICAL:
+               rpcrdma_map_one(ia, seg, writing);
+               seg->mr_rkey = ia->ri_bind_mem->rkey;
+               seg->mr_base = seg->mr_dma;
+               seg->mr_nsegs = 1;
+               nsegs = 1;
+               break;
+#endif
+
+       /* Registration using fast memory registration */
+       case RPCRDMA_MTHCAFMR:
+               {
+               u64 physaddrs[RPCRDMA_MAX_DATA_SEGS];
+               int len, pageoff = offset_in_page(seg->mr_offset);
+               seg1->mr_offset -= pageoff;     /* start of page */
+               seg1->mr_len += pageoff;
+               len = -pageoff;
+               if (nsegs > RPCRDMA_MAX_DATA_SEGS)
+                       nsegs = RPCRDMA_MAX_DATA_SEGS;
+               for (i = 0; i < nsegs;) {
+                       rpcrdma_map_one(ia, seg, writing);
+                       physaddrs[i] = seg->mr_dma;
+                       len += seg->mr_len;
+                       ++seg;
+                       ++i;
+                       /* Check for holes */
+                       if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
+                           offset_in_page((seg-1)->mr_offset+(seg-1)->mr_len))
+                               break;
+               }
+               nsegs = i;
+               rc = ib_map_phys_fmr(seg1->mr_chunk.rl_mw->r.fmr,
+                                       physaddrs, nsegs, seg1->mr_dma);
+               if (rc) {
+                       dprintk("RPC:       %s: failed ib_map_phys_fmr "
+                               "%u@0x%llx+%i (%d)... status %i\n", __func__,
+                               len, (unsigned long long)seg1->mr_dma,
+                               pageoff, nsegs, rc);
+                       while (nsegs--)
+                               rpcrdma_unmap_one(ia, --seg);
+               } else {
+                       seg1->mr_rkey = seg1->mr_chunk.rl_mw->r.fmr->rkey;
+                       seg1->mr_base = seg1->mr_dma + pageoff;
+                       seg1->mr_nsegs = nsegs;
+                       seg1->mr_len = len;
+               }
+               }
+               break;
+
+       /* Registration using memory windows */
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+       case RPCRDMA_MEMWINDOWS:
+               {
+               struct ib_mw_bind param;
+               rpcrdma_map_one(ia, seg, writing);
+               param.mr = ia->ri_bind_mem;
+               param.wr_id = 0ULL;     /* no send cookie */
+               param.addr = seg->mr_dma;
+               param.length = seg->mr_len;
+               param.send_flags = 0;
+               param.mw_access_flags = mem_priv;
+
+               DECR_CQCOUNT(&r_xprt->rx_ep);
+               rc = ib_bind_mw(ia->ri_id->qp,
+                                       seg->mr_chunk.rl_mw->r.mw, &param);
+               if (rc) {
+                       dprintk("RPC:       %s: failed ib_bind_mw "
+                               "%u@0x%llx status %i\n",
+                               __func__, seg->mr_len,
+                               (unsigned long long)seg->mr_dma, rc);
+                       rpcrdma_unmap_one(ia, seg);
+               } else {
+                       seg->mr_rkey = seg->mr_chunk.rl_mw->r.mw->rkey;
+                       seg->mr_base = param.addr;
+                       seg->mr_nsegs = 1;
+                       nsegs = 1;
+               }
+               }
+               break;
+
+       /* Default registration each time */
+       default:
+               {
+               struct ib_phys_buf ipb[RPCRDMA_MAX_DATA_SEGS];
+               int len = 0;
+               if (nsegs > RPCRDMA_MAX_DATA_SEGS)
+                       nsegs = RPCRDMA_MAX_DATA_SEGS;
+               for (i = 0; i < nsegs;) {
+                       rpcrdma_map_one(ia, seg, writing);
+                       ipb[i].addr = seg->mr_dma;
+                       ipb[i].size = seg->mr_len;
+                       len += seg->mr_len;
+                       ++seg;
+                       ++i;
+                       /* Check for holes */
+                       if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
+                           offset_in_page((seg-1)->mr_offset+(seg-1)->mr_len))
+                               break;
+               }
+               nsegs = i;
+               seg1->mr_base = seg1->mr_dma;
+               seg1->mr_chunk.rl_mr = ib_reg_phys_mr(ia->ri_pd,
+                                       ipb, nsegs, mem_priv, &seg1->mr_base);
+               if (IS_ERR(seg1->mr_chunk.rl_mr)) {
+                       rc = PTR_ERR(seg1->mr_chunk.rl_mr);
+                       dprintk("RPC:       %s: failed ib_reg_phys_mr "
+                               "%u@0x%llx (%d)... status %i\n",
+                               __func__, len,
+                               (unsigned long long)seg1->mr_dma, nsegs, rc);
+                       while (nsegs--)
+                               rpcrdma_unmap_one(ia, --seg);
+               } else {
+                       seg1->mr_rkey = seg1->mr_chunk.rl_mr->rkey;
+                       seg1->mr_nsegs = nsegs;
+                       seg1->mr_len = len;
+               }
+               }
+               break;
+       }
+       if (rc)
+               return -1;
+
+       return nsegs;
+}
+
+int
+rpcrdma_deregister_external(struct rpcrdma_mr_seg *seg,
+               struct rpcrdma_xprt *r_xprt, void *r)
+{
+       struct rpcrdma_ia *ia = &r_xprt->rx_ia;
+       struct rpcrdma_mr_seg *seg1 = seg;
+       int nsegs = seg->mr_nsegs, rc;
+
+       switch (ia->ri_memreg_strategy) {
+
+#if RPCRDMA_PERSISTENT_REGISTRATION
+       case RPCRDMA_ALLPHYSICAL:
+               BUG_ON(nsegs != 1);
+               rpcrdma_unmap_one(ia, seg);
+               rc = 0;
+               break;
+#endif
+
+       case RPCRDMA_MTHCAFMR:
+               {
+               LIST_HEAD(l);
+               list_add(&seg->mr_chunk.rl_mw->r.fmr->list, &l);
+               rc = ib_unmap_fmr(&l);
+               while (seg1->mr_nsegs--)
+                       rpcrdma_unmap_one(ia, seg++);
+               }
+               if (rc)
+                       dprintk("RPC:       %s: failed ib_unmap_fmr,"
+                               " status %i\n", __func__, rc);
+               break;
+
+       case RPCRDMA_MEMWINDOWS_ASYNC:
+       case RPCRDMA_MEMWINDOWS:
+               {
+               struct ib_mw_bind param;
+               BUG_ON(nsegs != 1);
+               param.mr = ia->ri_bind_mem;
+               param.addr = 0ULL;      /* unbind */
+               param.length = 0;
+               param.mw_access_flags = 0;
+               if (r) {
+                       param.wr_id = (u64) (unsigned long) r;
+                       param.send_flags = IB_SEND_SIGNALED;
+                       INIT_CQCOUNT(&r_xprt->rx_ep);
+               } else {
+                       param.wr_id = 0ULL;
+                       param.send_flags = 0;
+                       DECR_CQCOUNT(&r_xprt->rx_ep);
+               }
+               rc = ib_bind_mw(ia->ri_id->qp,
+                               seg->mr_chunk.rl_mw->r.mw, &param);
+               rpcrdma_unmap_one(ia, seg);
+               }
+               if (rc)
+                       dprintk("RPC:       %s: failed ib_(un)bind_mw,"
+                               " status %i\n", __func__, rc);
+               else
+                       r = NULL;       /* will upcall on completion */
+               break;
+
+       default:
+               rc = ib_dereg_mr(seg1->mr_chunk.rl_mr);
+               seg1->mr_chunk.rl_mr = NULL;
+               while (seg1->mr_nsegs--)
+                       rpcrdma_unmap_one(ia, seg++);
+               if (rc)
+                       dprintk("RPC:       %s: failed ib_dereg_mr,"
+                               " status %i\n", __func__, rc);
+               break;
+       }
+       if (r) {
+               struct rpcrdma_rep *rep = r;
+               void (*func)(struct rpcrdma_rep *) = rep->rr_func;
+               rep->rr_func = NULL;
+               func(rep);      /* dereg done, callback now */
+       }
+       return nsegs;
+}
+
+/*
+ * Prepost any receive buffer, then post send.
+ *
+ * Receive buffer is donated to hardware, reclaimed upon recv completion.
+ */
+int
+rpcrdma_ep_post(struct rpcrdma_ia *ia,
+               struct rpcrdma_ep *ep,
+               struct rpcrdma_req *req)
+{
+       struct ib_send_wr send_wr, *send_wr_fail;
+       struct rpcrdma_rep *rep = req->rl_reply;
+       int rc;
+
+       if (rep) {
+               rc = rpcrdma_ep_post_recv(ia, ep, rep);
+               if (rc)
+                       goto out;
+               req->rl_reply = NULL;
+       }
+
+       send_wr.next = NULL;
+       send_wr.wr_id = 0ULL;   /* no send cookie */
+       send_wr.sg_list = req->rl_send_iov;
+       send_wr.num_sge = req->rl_niovs;
+       send_wr.opcode = IB_WR_SEND;
+       send_wr.imm_data = 0;
+       if (send_wr.num_sge == 4)       /* no need to sync any pad (constant) */
+               ib_dma_sync_single_for_device(ia->ri_id->device,
+                       req->rl_send_iov[3].addr, req->rl_send_iov[3].length,
+                       DMA_TO_DEVICE);
+       ib_dma_sync_single_for_device(ia->ri_id->device,
+               req->rl_send_iov[1].addr, req->rl_send_iov[1].length,
+               DMA_TO_DEVICE);
+       ib_dma_sync_single_for_device(ia->ri_id->device,
+               req->rl_send_iov[0].addr, req->rl_send_iov[0].length,
+               DMA_TO_DEVICE);
+
+       if (DECR_CQCOUNT(ep) > 0)
+               send_wr.send_flags = 0;
+       else { /* Provider must take a send completion every now and then */
+               INIT_CQCOUNT(ep);
+               send_wr.send_flags = IB_SEND_SIGNALED;
+       }
+
+       rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail);
+       if (rc)
+               dprintk("RPC:       %s: ib_post_send returned %i\n", __func__,
+                       rc);
+out:
+       return rc;
+}
+
+/*
+ * (Re)post a receive buffer.
+ */
+int
+rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
+                    struct rpcrdma_ep *ep,
+                    struct rpcrdma_rep *rep)
+{
+       struct ib_recv_wr recv_wr, *recv_wr_fail;
+       int rc;
+
+       recv_wr.next = NULL;
+       recv_wr.wr_id = (u64) (unsigned long) rep;
+       recv_wr.sg_list = &rep->rr_iov;
+       recv_wr.num_sge = 1;
+
+       ib_dma_sync_single_for_cpu(ia->ri_id->device,
+               rep->rr_iov.addr, rep->rr_iov.length, DMA_BIDIRECTIONAL);
+
+       DECR_CQCOUNT(ep);
+       rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail);
+
+       if (rc)
+               dprintk("RPC:       %s: ib_post_recv returned %i\n", __func__,
+                       rc);
+       return rc;
+}
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
new file mode 100644 (file)
index 0000000..2427822
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      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.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_SUNRPC_XPRT_RDMA_H
+#define _LINUX_SUNRPC_XPRT_RDMA_H
+
+#include <linux/wait.h>                /* wait_queue_head_t, etc */
+#include <linux/spinlock.h>            /* spinlock_t, etc */
+#include <asm/atomic.h>                        /* atomic_t, etc */
+
+#include <rdma/rdma_cm.h>              /* RDMA connection api */
+#include <rdma/ib_verbs.h>             /* RDMA verbs api */
+
+#include <linux/sunrpc/clnt.h>                 /* rpc_xprt */
+#include <linux/sunrpc/rpc_rdma.h>     /* RPC/RDMA protocol */
+#include <linux/sunrpc/xprtrdma.h>     /* xprt parameters */
+
+/*
+ * Interface Adapter -- one per transport instance
+ */
+struct rpcrdma_ia {
+       struct rdma_cm_id       *ri_id;
+       struct ib_pd            *ri_pd;
+       struct ib_mr            *ri_bind_mem;
+       struct completion       ri_done;
+       int                     ri_async_rc;
+       enum rpcrdma_memreg     ri_memreg_strategy;
+};
+
+/*
+ * RDMA Endpoint -- one per transport instance
+ */
+
+struct rpcrdma_ep {
+       atomic_t                rep_cqcount;
+       int                     rep_cqinit;
+       int                     rep_connected;
+       struct rpcrdma_ia       *rep_ia;
+       struct ib_cq            *rep_cq;
+       struct ib_qp_init_attr  rep_attr;
+       wait_queue_head_t       rep_connect_wait;
+       struct ib_sge           rep_pad;        /* holds zeroed pad */
+       struct ib_mr            *rep_pad_mr;    /* holds zeroed pad */
+       void                    (*rep_func)(struct rpcrdma_ep *);
+       struct rpc_xprt         *rep_xprt;      /* for rep_func */
+       struct rdma_conn_param  rep_remote_cma;
+       struct sockaddr_storage rep_remote_addr;
+};
+
+#define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit)
+#define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount)
+
+/*
+ * struct rpcrdma_rep -- this structure encapsulates state required to recv
+ * and complete a reply, asychronously. It needs several pieces of
+ * state:
+ *   o recv buffer (posted to provider)
+ *   o ib_sge (also donated to provider)
+ *   o status of reply (length, success or not)
+ *   o bookkeeping state to get run by tasklet (list, etc)
+ *
+ * These are allocated during initialization, per-transport instance;
+ * however, the tasklet execution list itself is global, as it should
+ * always be pretty short.
+ *
+ * N of these are associated with a transport instance, and stored in
+ * struct rpcrdma_buffer. N is the max number of outstanding requests.
+ */
+
+/* temporary static scatter/gather max */
+#define RPCRDMA_MAX_DATA_SEGS  (8)     /* max scatter/gather */
+#define RPCRDMA_MAX_SEGS       (RPCRDMA_MAX_DATA_SEGS + 2) /* head+tail = 2 */
+#define MAX_RPCRDMAHDR (\
+       /* max supported RPC/RDMA header */ \
+       sizeof(struct rpcrdma_msg) + (2 * sizeof(u32)) + \
+       (sizeof(struct rpcrdma_read_chunk) * RPCRDMA_MAX_SEGS) + sizeof(u32))
+
+struct rpcrdma_buffer;
+
+struct rpcrdma_rep {
+       unsigned int    rr_len;         /* actual received reply length */
+       struct rpcrdma_buffer *rr_buffer; /* home base for this structure */
+       struct rpc_xprt *rr_xprt;       /* needed for request/reply matching */
+       void (*rr_func)(struct rpcrdma_rep *);/* called by tasklet in softint */
+       struct list_head rr_list;       /* tasklet list */
+       wait_queue_head_t rr_unbind;    /* optional unbind wait */
+       struct ib_sge   rr_iov;         /* for posting */
+       struct ib_mr    *rr_handle;     /* handle for mem in rr_iov */
+       char    rr_base[MAX_RPCRDMAHDR]; /* minimal inline receive buffer */
+};
+
+/*
+ * struct rpcrdma_req -- structure central to the request/reply sequence.
+ *
+ * N of these are associated with a transport instance, and stored in
+ * struct rpcrdma_buffer. N is the max number of outstanding requests.
+ *
+ * It includes pre-registered buffer memory for send AND recv.
+ * The recv buffer, however, is not owned by this structure, and
+ * is "donated" to the hardware when a recv is posted. When a
+ * reply is handled, the recv buffer used is given back to the
+ * struct rpcrdma_req associated with the request.
+ *
+ * In addition to the basic memory, this structure includes an array
+ * of iovs for send operations. The reason is that the iovs passed to
+ * ib_post_{send,recv} must not be modified until the work request
+ * completes.
+ *
+ * NOTES:
+ *   o RPCRDMA_MAX_SEGS is the max number of addressible chunk elements we
+ *     marshal. The number needed varies depending on the iov lists that
+ *     are passed to us, the memory registration mode we are in, and if
+ *     physical addressing is used, the layout.
+ */
+
+struct rpcrdma_mr_seg {                /* chunk descriptors */
+       union {                         /* chunk memory handles */
+               struct ib_mr    *rl_mr;         /* if registered directly */
+               struct rpcrdma_mw {             /* if registered from region */
+                       union {
+                               struct ib_mw    *mw;
+                               struct ib_fmr   *fmr;
+                       } r;
+                       struct list_head mw_list;
+               } *rl_mw;
+       } mr_chunk;
+       u64             mr_base;        /* registration result */
+       u32             mr_rkey;        /* registration result */
+       u32             mr_len;         /* length of chunk or segment */
+       int             mr_nsegs;       /* number of segments in chunk or 0 */
+       enum dma_data_direction mr_dir; /* segment mapping direction */
+       dma_addr_t      mr_dma;         /* segment mapping address */
+       size_t          mr_dmalen;      /* segment mapping length */
+       struct page     *mr_page;       /* owning page, if any */
+       char            *mr_offset;     /* kva if no page, else offset */
+};
+
+struct rpcrdma_req {
+       size_t          rl_size;        /* actual length of buffer */
+       unsigned int    rl_niovs;       /* 0, 2 or 4 */
+       unsigned int    rl_nchunks;     /* non-zero if chunks */
+       struct rpcrdma_buffer *rl_buffer; /* home base for this structure */
+       struct rpcrdma_rep      *rl_reply;/* holder for reply buffer */
+       struct rpcrdma_mr_seg rl_segments[RPCRDMA_MAX_SEGS];/* chunk segments */
+       struct ib_sge   rl_send_iov[4]; /* for active requests */
+       struct ib_sge   rl_iov;         /* for posting */
+       struct ib_mr    *rl_handle;     /* handle for mem in rl_iov */
+       char            rl_base[MAX_RPCRDMAHDR]; /* start of actual buffer */
+       __u32           rl_xdr_buf[0];  /* start of returned rpc rq_buffer */
+};
+#define rpcr_to_rdmar(r) \
+       container_of((r)->rq_buffer, struct rpcrdma_req, rl_xdr_buf[0])
+
+/*
+ * struct rpcrdma_buffer -- holds list/queue of pre-registered memory for
+ * inline requests/replies, and client/server credits.
+ *
+ * One of these is associated with a transport instance
+ */
+struct rpcrdma_buffer {
+       spinlock_t      rb_lock;        /* protects indexes */
+       atomic_t        rb_credits;     /* most recent server credits */
+       unsigned long   rb_cwndscale;   /* cached framework rpc_cwndscale */
+       int             rb_max_requests;/* client max requests */
+       struct list_head rb_mws;        /* optional memory windows/fmrs */
+       int             rb_send_index;
+       struct rpcrdma_req      **rb_send_bufs;
+       int             rb_recv_index;
+       struct rpcrdma_rep      **rb_recv_bufs;
+       char            *rb_pool;
+};
+#define rdmab_to_ia(b) (&container_of((b), struct rpcrdma_xprt, rx_buf)->rx_ia)
+
+/*
+ * Internal structure for transport instance creation. This
+ * exists primarily for modularity.
+ *
+ * This data should be set with mount options
+ */
+struct rpcrdma_create_data_internal {
+       struct sockaddr_storage addr;   /* RDMA server address */
+       unsigned int    max_requests;   /* max requests (slots) in flight */
+       unsigned int    rsize;          /* mount rsize - max read hdr+data */
+       unsigned int    wsize;          /* mount wsize - max write hdr+data */
+       unsigned int    inline_rsize;   /* max non-rdma read data payload */
+       unsigned int    inline_wsize;   /* max non-rdma write data payload */
+       unsigned int    padding;        /* non-rdma write header padding */
+};
+
+#define RPCRDMA_INLINE_READ_THRESHOLD(rq) \
+       (rpcx_to_rdmad(rq->rq_task->tk_xprt).inline_rsize)
+
+#define RPCRDMA_INLINE_WRITE_THRESHOLD(rq)\
+       (rpcx_to_rdmad(rq->rq_task->tk_xprt).inline_wsize)
+
+#define RPCRDMA_INLINE_PAD_VALUE(rq)\
+       rpcx_to_rdmad(rq->rq_task->tk_xprt).padding
+
+/*
+ * Statistics for RPCRDMA
+ */
+struct rpcrdma_stats {
+       unsigned long           read_chunk_count;
+       unsigned long           write_chunk_count;
+       unsigned long           reply_chunk_count;
+
+       unsigned long long      total_rdma_request;
+       unsigned long long      total_rdma_reply;
+
+       unsigned long long      pullup_copy_count;
+       unsigned long long      fixup_copy_count;
+       unsigned long           hardway_register_count;
+       unsigned long           failed_marshal_count;
+       unsigned long           bad_reply_count;
+};
+
+/*
+ * RPCRDMA transport -- encapsulates the structures above for
+ * integration with RPC.
+ *
+ * The contained structures are embedded, not pointers,
+ * for convenience. This structure need not be visible externally.
+ *
+ * It is allocated and initialized during mount, and released
+ * during unmount.
+ */
+struct rpcrdma_xprt {
+       struct rpc_xprt         xprt;
+       struct rpcrdma_ia       rx_ia;
+       struct rpcrdma_ep       rx_ep;
+       struct rpcrdma_buffer   rx_buf;
+       struct rpcrdma_create_data_internal rx_data;
+       struct delayed_work     rdma_connect;
+       struct rpcrdma_stats    rx_stats;
+};
+
+#define rpcx_to_rdmax(x) container_of(x, struct rpcrdma_xprt, xprt)
+#define rpcx_to_rdmad(x) (rpcx_to_rdmax(x)->rx_data)
+
+/*
+ * Interface Adapter calls - xprtrdma/verbs.c
+ */
+int rpcrdma_ia_open(struct rpcrdma_xprt *, struct sockaddr *, int);
+void rpcrdma_ia_close(struct rpcrdma_ia *);
+
+/*
+ * Endpoint calls - xprtrdma/verbs.c
+ */
+int rpcrdma_ep_create(struct rpcrdma_ep *, struct rpcrdma_ia *,
+                               struct rpcrdma_create_data_internal *);
+int rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *);
+int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *);
+int rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *);
+
+int rpcrdma_ep_post(struct rpcrdma_ia *, struct rpcrdma_ep *,
+                               struct rpcrdma_req *);
+int rpcrdma_ep_post_recv(struct rpcrdma_ia *, struct rpcrdma_ep *,
+                               struct rpcrdma_rep *);
+
+/*
+ * Buffer calls - xprtrdma/verbs.c
+ */
+int rpcrdma_buffer_create(struct rpcrdma_buffer *, struct rpcrdma_ep *,
+                               struct rpcrdma_ia *,
+                               struct rpcrdma_create_data_internal *);
+void rpcrdma_buffer_destroy(struct rpcrdma_buffer *);
+
+struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *);
+void rpcrdma_buffer_put(struct rpcrdma_req *);
+void rpcrdma_recv_buffer_get(struct rpcrdma_req *);
+void rpcrdma_recv_buffer_put(struct rpcrdma_rep *);
+
+int rpcrdma_register_internal(struct rpcrdma_ia *, void *, int,
+                               struct ib_mr **, struct ib_sge *);
+int rpcrdma_deregister_internal(struct rpcrdma_ia *,
+                               struct ib_mr *, struct ib_sge *);
+
+int rpcrdma_register_external(struct rpcrdma_mr_seg *,
+                               int, int, struct rpcrdma_xprt *);
+int rpcrdma_deregister_external(struct rpcrdma_mr_seg *,
+                               struct rpcrdma_xprt *, void *);
+
+/*
+ * RPC/RDMA connection management calls - xprtrdma/rpc_rdma.c
+ */
+void rpcrdma_conn_func(struct rpcrdma_ep *);
+void rpcrdma_reply_handler(struct rpcrdma_rep *);
+
+/*
+ * RPC/RDMA protocol calls - xprtrdma/rpc_rdma.c
+ */
+int rpcrdma_marshal_req(struct rpc_rqst *);
+
+#endif                         /* _LINUX_SUNRPC_XPRT_RDMA_H */
index 282efd447a61d535b23c6322aecc2bc756a73195..02298f529dad3f4a068ed86d4cf00cbe8e352eaf 100644 (file)
  *  (C) 1999 Trond Myklebust <trond.myklebust@fys.uio.no>
  *
  * IP socket transport implementation, (C) 2005 Chuck Lever <cel@netapp.com>
+ *
+ * IPv6 support contributed by Gilles Quillard, Bull Open Source, 2005.
+ *   <gilles.quillard@bull.net>
  */
 
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/capability.h>
 #include <linux/pagemap.h>
 #include <linux/errno.h>
@@ -28,6 +32,7 @@
 #include <linux/tcp.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/xprtsock.h>
 #include <linux/file.h>
 
 #include <net/sock.h>
@@ -260,14 +265,29 @@ struct sock_xprt {
 #define TCP_RCV_COPY_XID       (1UL << 2)
 #define TCP_RCV_COPY_DATA      (1UL << 3)
 
-static void xs_format_peer_addresses(struct rpc_xprt *xprt)
+static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
+{
+       return (struct sockaddr *) &xprt->addr;
+}
+
+static inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt)
 {
-       struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
+       return (struct sockaddr_in *) &xprt->addr;
+}
+
+static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt)
+{
+       return (struct sockaddr_in6 *) &xprt->addr;
+}
+
+static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt)
+{
+       struct sockaddr_in *addr = xs_addr_in(xprt);
        char *buf;
 
        buf = kzalloc(20, GFP_KERNEL);
        if (buf) {
-               snprintf(buf, 20, "%u.%u.%u.%u",
+               snprintf(buf, 20, NIPQUAD_FMT,
                                NIPQUAD(addr->sin_addr.s_addr));
        }
        xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
@@ -279,26 +299,123 @@ static void xs_format_peer_addresses(struct rpc_xprt *xprt)
        }
        xprt->address_strings[RPC_DISPLAY_PORT] = buf;
 
-       if (xprt->prot == IPPROTO_UDP)
-               xprt->address_strings[RPC_DISPLAY_PROTO] = "udp";
-       else
-               xprt->address_strings[RPC_DISPLAY_PROTO] = "tcp";
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               if (xprt->prot == IPPROTO_UDP)
+                       snprintf(buf, 8, "udp");
+               else
+                       snprintf(buf, 8, "tcp");
+       }
+       xprt->address_strings[RPC_DISPLAY_PROTO] = buf;
 
        buf = kzalloc(48, GFP_KERNEL);
        if (buf) {
-               snprintf(buf, 48, "addr=%u.%u.%u.%u port=%u proto=%s",
+               snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s",
                        NIPQUAD(addr->sin_addr.s_addr),
                        ntohs(addr->sin_port),
                        xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
        }
        xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+
+       buf = kzalloc(10, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 10, "%02x%02x%02x%02x",
+                               NIPQUAD(addr->sin_addr.s_addr));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 8, "%4hx",
+                               ntohs(addr->sin_port));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+
+       buf = kzalloc(30, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 30, NIPQUAD_FMT".%u.%u",
+                               NIPQUAD(addr->sin_addr.s_addr),
+                               ntohs(addr->sin_port) >> 8,
+                               ntohs(addr->sin_port) & 0xff);
+       }
+       xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+
+       xprt->address_strings[RPC_DISPLAY_NETID] =
+               kstrdup(xprt->prot == IPPROTO_UDP ?
+                       RPCBIND_NETID_UDP : RPCBIND_NETID_TCP, GFP_KERNEL);
+}
+
+static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt)
+{
+       struct sockaddr_in6 *addr = xs_addr_in6(xprt);
+       char *buf;
+
+       buf = kzalloc(40, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 40, NIP6_FMT,
+                               NIP6(addr->sin6_addr));
+       }
+       xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
+
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 8, "%u",
+                               ntohs(addr->sin6_port));
+       }
+       xprt->address_strings[RPC_DISPLAY_PORT] = buf;
+
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               if (xprt->prot == IPPROTO_UDP)
+                       snprintf(buf, 8, "udp");
+               else
+                       snprintf(buf, 8, "tcp");
+       }
+       xprt->address_strings[RPC_DISPLAY_PROTO] = buf;
+
+       buf = kzalloc(64, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s",
+                               NIP6(addr->sin6_addr),
+                               ntohs(addr->sin6_port),
+                               xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
+       }
+       xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+
+       buf = kzalloc(36, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 36, NIP6_SEQFMT,
+                               NIP6(addr->sin6_addr));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 8, "%4hx",
+                               ntohs(addr->sin6_port));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+
+       buf = kzalloc(50, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 50, NIP6_FMT".%u.%u",
+                               NIP6(addr->sin6_addr),
+                               ntohs(addr->sin6_port) >> 8,
+                               ntohs(addr->sin6_port) & 0xff);
+       }
+       xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+
+       xprt->address_strings[RPC_DISPLAY_NETID] =
+               kstrdup(xprt->prot == IPPROTO_UDP ?
+                       RPCBIND_NETID_UDP6 : RPCBIND_NETID_TCP6, GFP_KERNEL);
 }
 
 static void xs_free_peer_addresses(struct rpc_xprt *xprt)
 {
-       kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
-       kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
-       kfree(xprt->address_strings[RPC_DISPLAY_ALL]);
+       int i;
+
+       for (i = 0; i < RPC_DISPLAY_MAX; i++)
+               kfree(xprt->address_strings[i]);
 }
 
 #define XS_SENDMSG_FLAGS       (MSG_DONTWAIT | MSG_NOSIGNAL)
@@ -463,19 +580,20 @@ static int xs_udp_send_request(struct rpc_task *task)
 
        req->rq_xtime = jiffies;
        status = xs_sendpages(transport->sock,
-                             (struct sockaddr *) &xprt->addr,
+                             xs_addr(xprt),
                              xprt->addrlen, xdr,
                              req->rq_bytes_sent);
 
        dprintk("RPC:       xs_udp_send_request(%u) = %d\n",
                        xdr->len - req->rq_bytes_sent, status);
 
-       if (likely(status >= (int) req->rq_slen))
-               return 0;
-
-       /* Still some bytes left; set up for a retry later. */
-       if (status > 0)
+       if (status >= 0) {
+               task->tk_bytes_sent += status;
+               if (status >= req->rq_slen)
+                       return 0;
+               /* Still some bytes left; set up for a retry later. */
                status = -EAGAIN;
+       }
 
        switch (status) {
        case -ENETUNREACH:
@@ -523,7 +641,8 @@ static int xs_tcp_send_request(struct rpc_task *task)
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct xdr_buf *xdr = &req->rq_snd_buf;
-       int status, retry = 0;
+       int status;
+       unsigned int retry = 0;
 
        xs_encode_tcp_record_marker(&req->rq_snd_buf);
 
@@ -661,6 +780,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
        xs_free_peer_addresses(xprt);
        kfree(xprt->slot);
        kfree(xprt);
+       module_put(THIS_MODULE);
 }
 
 static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
@@ -1139,14 +1259,23 @@ static unsigned short xs_get_random_port(void)
  */
 static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
 {
-       struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr;
+       struct sockaddr *addr = xs_addr(xprt);
 
        dprintk("RPC:       setting port for xprt %p to %u\n", xprt, port);
 
-       sap->sin_port = htons(port);
+       switch (addr->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *)addr)->sin_port = htons(port);
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
+               break;
+       default:
+               BUG();
+       }
 }
 
-static int xs_bind(struct sock_xprt *transport, struct socket *sock)
+static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
 {
        struct sockaddr_in myaddr = {
                .sin_family = AF_INET,
@@ -1174,8 +1303,42 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
                else
                        port--;
        } while (err == -EADDRINUSE && port != transport->port);
-       dprintk("RPC:       xs_bind "NIPQUAD_FMT":%u: %s (%d)\n",
-               NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err);
+       dprintk("RPC:       %s "NIPQUAD_FMT":%u: %s (%d)\n",
+                       __FUNCTION__, NIPQUAD(myaddr.sin_addr),
+                       port, err ? "failed" : "ok", err);
+       return err;
+}
+
+static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
+{
+       struct sockaddr_in6 myaddr = {
+               .sin6_family = AF_INET6,
+       };
+       struct sockaddr_in6 *sa;
+       int err;
+       unsigned short port = transport->port;
+
+       if (!transport->xprt.resvport)
+               port = 0;
+       sa = (struct sockaddr_in6 *)&transport->addr;
+       myaddr.sin6_addr = sa->sin6_addr;
+       do {
+               myaddr.sin6_port = htons(port);
+               err = kernel_bind(sock, (struct sockaddr *) &myaddr,
+                                               sizeof(myaddr));
+               if (!transport->xprt.resvport)
+                       break;
+               if (err == 0) {
+                       transport->port = port;
+                       break;
+               }
+               if (port <= xprt_min_resvport)
+                       port = xprt_max_resvport;
+               else
+                       port--;
+       } while (err == -EADDRINUSE && port != transport->port);
+       dprintk("RPC:       xs_bind6 "NIP6_FMT":%u: %s (%d)\n",
+               NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err);
        return err;
 }
 
@@ -1183,38 +1346,69 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
 static struct lock_class_key xs_key[2];
 static struct lock_class_key xs_slock_key[2];
 
-static inline void xs_reclassify_socket(struct socket *sock)
+static inline void xs_reclassify_socket4(struct socket *sock)
 {
        struct sock *sk = sock->sk;
+
        BUG_ON(sock_owned_by_user(sk));
-       switch (sk->sk_family) {
-       case AF_INET:
-               sock_lock_init_class_and_name(sk, "slock-AF_INET-NFS",
-                       &xs_slock_key[0], "sk_lock-AF_INET-NFS", &xs_key[0]);
-               break;
+       sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC",
+               &xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]);
+}
 
-       case AF_INET6:
-               sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFS",
-                       &xs_slock_key[1], "sk_lock-AF_INET6-NFS", &xs_key[1]);
-               break;
+static inline void xs_reclassify_socket6(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
 
-       default:
-               BUG();
-       }
+       BUG_ON(sock_owned_by_user(sk));
+       sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
+               &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
 }
 #else
-static inline void xs_reclassify_socket(struct socket *sock)
+static inline void xs_reclassify_socket4(struct socket *sock)
+{
+}
+
+static inline void xs_reclassify_socket6(struct socket *sock)
 {
 }
 #endif
 
+static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+{
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+
+       if (!transport->inet) {
+               struct sock *sk = sock->sk;
+
+               write_lock_bh(&sk->sk_callback_lock);
+
+               sk->sk_user_data = xprt;
+               transport->old_data_ready = sk->sk_data_ready;
+               transport->old_state_change = sk->sk_state_change;
+               transport->old_write_space = sk->sk_write_space;
+               sk->sk_data_ready = xs_udp_data_ready;
+               sk->sk_write_space = xs_udp_write_space;
+               sk->sk_no_check = UDP_CSUM_NORCV;
+               sk->sk_allocation = GFP_ATOMIC;
+
+               xprt_set_connected(xprt);
+
+               /* Reset to new socket */
+               transport->sock = sock;
+               transport->inet = sk;
+
+               write_unlock_bh(&sk->sk_callback_lock);
+       }
+       xs_udp_do_set_buffer_size(xprt);
+}
+
 /**
- * xs_udp_connect_worker - set up a UDP socket
+ * xs_udp_connect_worker4 - set up a UDP socket
  * @work: RPC transport to connect
  *
  * Invoked by a work queue tasklet.
  */
-static void xs_udp_connect_worker(struct work_struct *work)
+static void xs_udp_connect_worker4(struct work_struct *work)
 {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
@@ -1232,9 +1426,9 @@ static void xs_udp_connect_worker(struct work_struct *work)
                dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
                goto out;
        }
-       xs_reclassify_socket(sock);
+       xs_reclassify_socket4(sock);
 
-       if (xs_bind(transport, sock)) {
+       if (xs_bind4(transport, sock)) {
                sock_release(sock);
                goto out;
        }
@@ -1242,29 +1436,48 @@ static void xs_udp_connect_worker(struct work_struct *work)
        dprintk("RPC:       worker connecting xprt %p to address: %s\n",
                        xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
 
-       if (!transport->inet) {
-               struct sock *sk = sock->sk;
+       xs_udp_finish_connecting(xprt, sock);
+       status = 0;
+out:
+       xprt_wake_pending_tasks(xprt, status);
+       xprt_clear_connecting(xprt);
+}
 
-               write_lock_bh(&sk->sk_callback_lock);
+/**
+ * xs_udp_connect_worker6 - set up a UDP socket
+ * @work: RPC transport to connect
+ *
+ * Invoked by a work queue tasklet.
+ */
+static void xs_udp_connect_worker6(struct work_struct *work)
+{
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
+       struct rpc_xprt *xprt = &transport->xprt;
+       struct socket *sock = transport->sock;
+       int err, status = -EIO;
 
-               sk->sk_user_data = xprt;
-               transport->old_data_ready = sk->sk_data_ready;
-               transport->old_state_change = sk->sk_state_change;
-               transport->old_write_space = sk->sk_write_space;
-               sk->sk_data_ready = xs_udp_data_ready;
-               sk->sk_write_space = xs_udp_write_space;
-               sk->sk_no_check = UDP_CSUM_NORCV;
-               sk->sk_allocation = GFP_ATOMIC;
+       if (xprt->shutdown || !xprt_bound(xprt))
+               goto out;
 
-               xprt_set_connected(xprt);
+       /* Start by resetting any existing state */
+       xs_close(xprt);
 
-               /* Reset to new socket */
-               transport->sock = sock;
-               transport->inet = sk;
+       if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
+               dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
+               goto out;
+       }
+       xs_reclassify_socket6(sock);
 
-               write_unlock_bh(&sk->sk_callback_lock);
+       if (xs_bind6(transport, sock) < 0) {
+               sock_release(sock);
+               goto out;
        }
-       xs_udp_do_set_buffer_size(xprt);
+
+       dprintk("RPC:       worker connecting xprt %p to address: %s\n",
+                       xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+
+       xs_udp_finish_connecting(xprt, sock);
        status = 0;
 out:
        xprt_wake_pending_tasks(xprt, status);
@@ -1295,13 +1508,52 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
                                result);
 }
 
+static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+{
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+
+       if (!transport->inet) {
+               struct sock *sk = sock->sk;
+
+               write_lock_bh(&sk->sk_callback_lock);
+
+               sk->sk_user_data = xprt;
+               transport->old_data_ready = sk->sk_data_ready;
+               transport->old_state_change = sk->sk_state_change;
+               transport->old_write_space = sk->sk_write_space;
+               sk->sk_data_ready = xs_tcp_data_ready;
+               sk->sk_state_change = xs_tcp_state_change;
+               sk->sk_write_space = xs_tcp_write_space;
+               sk->sk_allocation = GFP_ATOMIC;
+
+               /* socket options */
+               sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
+               sock_reset_flag(sk, SOCK_LINGER);
+               tcp_sk(sk)->linger2 = 0;
+               tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
+
+               xprt_clear_connected(xprt);
+
+               /* Reset to new socket */
+               transport->sock = sock;
+               transport->inet = sk;
+
+               write_unlock_bh(&sk->sk_callback_lock);
+       }
+
+       /* Tell the socket layer to start connecting... */
+       xprt->stat.connect_count++;
+       xprt->stat.connect_start = jiffies;
+       return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK);
+}
+
 /**
- * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint
+ * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
  * @work: RPC transport to connect
  *
  * Invoked by a work queue tasklet.
  */
-static void xs_tcp_connect_worker(struct work_struct *work)
+static void xs_tcp_connect_worker4(struct work_struct *work)
 {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
@@ -1315,13 +1567,12 @@ static void xs_tcp_connect_worker(struct work_struct *work)
        if (!sock) {
                /* start from scratch */
                if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
-                       dprintk("RPC:       can't create TCP transport "
-                                       "socket (%d).\n", -err);
+                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
                        goto out;
                }
-               xs_reclassify_socket(sock);
+               xs_reclassify_socket4(sock);
 
-               if (xs_bind(transport, sock)) {
+               if (xs_bind4(transport, sock) < 0) {
                        sock_release(sock);
                        goto out;
                }
@@ -1332,43 +1583,70 @@ static void xs_tcp_connect_worker(struct work_struct *work)
        dprintk("RPC:       worker connecting xprt %p to address: %s\n",
                        xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
 
-       if (!transport->inet) {
-               struct sock *sk = sock->sk;
-
-               write_lock_bh(&sk->sk_callback_lock);
+       status = xs_tcp_finish_connecting(xprt, sock);
+       dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
+                       xprt, -status, xprt_connected(xprt),
+                       sock->sk->sk_state);
+       if (status < 0) {
+               switch (status) {
+                       case -EINPROGRESS:
+                       case -EALREADY:
+                               goto out_clear;
+                       case -ECONNREFUSED:
+                       case -ECONNRESET:
+                               /* retry with existing socket, after a delay */
+                               break;
+                       default:
+                               /* get rid of existing socket, and retry */
+                               xs_close(xprt);
+                               break;
+               }
+       }
+out:
+       xprt_wake_pending_tasks(xprt, status);
+out_clear:
+       xprt_clear_connecting(xprt);
+}
 
-               sk->sk_user_data = xprt;
-               transport->old_data_ready = sk->sk_data_ready;
-               transport->old_state_change = sk->sk_state_change;
-               transport->old_write_space = sk->sk_write_space;
-               sk->sk_data_ready = xs_tcp_data_ready;
-               sk->sk_state_change = xs_tcp_state_change;
-               sk->sk_write_space = xs_tcp_write_space;
-               sk->sk_allocation = GFP_ATOMIC;
+/**
+ * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
+ * @work: RPC transport to connect
+ *
+ * Invoked by a work queue tasklet.
+ */
+static void xs_tcp_connect_worker6(struct work_struct *work)
+{
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
+       struct rpc_xprt *xprt = &transport->xprt;
+       struct socket *sock = transport->sock;
+       int err, status = -EIO;
 
-               /* socket options */
-               sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
-               sock_reset_flag(sk, SOCK_LINGER);
-               tcp_sk(sk)->linger2 = 0;
-               tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
+       if (xprt->shutdown || !xprt_bound(xprt))
+               goto out;
 
-               xprt_clear_connected(xprt);
+       if (!sock) {
+               /* start from scratch */
+               if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
+                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
+                       goto out;
+               }
+               xs_reclassify_socket6(sock);
 
-               /* Reset to new socket */
-               transport->sock = sock;
-               transport->inet = sk;
+               if (xs_bind6(transport, sock) < 0) {
+                       sock_release(sock);
+                       goto out;
+               }
+       } else
+               /* "close" the socket, preserving the local port */
+               xs_tcp_reuse_connection(xprt);
 
-               write_unlock_bh(&sk->sk_callback_lock);
-       }
+       dprintk("RPC:       worker connecting xprt %p to address: %s\n",
+                       xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
 
-       /* Tell the socket layer to start connecting... */
-       xprt->stat.connect_count++;
-       xprt->stat.connect_start = jiffies;
-       status = kernel_connect(sock, (struct sockaddr *) &xprt->addr,
-                       xprt->addrlen, O_NONBLOCK);
+       status = xs_tcp_finish_connecting(xprt, sock);
        dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
-                       xprt, -status, xprt_connected(xprt),
-                       sock->sk->sk_state);
+                       xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
        if (status < 0) {
                switch (status) {
                        case -EINPROGRESS:
@@ -1508,7 +1786,8 @@ static struct rpc_xprt_ops xs_tcp_ops = {
        .print_stats            = xs_tcp_print_stats,
 };
 
-static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned int slot_table_size)
+static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
+                                     unsigned int slot_table_size)
 {
        struct rpc_xprt *xprt;
        struct sock_xprt *new;
@@ -1549,8 +1828,9 @@ static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned
  * @args: rpc transport creation arguments
  *
  */
-struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
+struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
 {
+       struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
 
@@ -1559,15 +1839,11 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
 
-       if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
-               xprt_set_bound(xprt);
-
        xprt->prot = IPPROTO_UDP;
        xprt->tsh_size = 0;
        /* XXX: header size can vary due to auth type, IPv6, etc. */
        xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
 
-       INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker);
        xprt->bind_timeout = XS_BIND_TO;
        xprt->connect_timeout = XS_UDP_CONN_TO;
        xprt->reestablish_timeout = XS_UDP_REEST_TO;
@@ -1580,11 +1856,37 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
        else
                xprt_set_timeout(&xprt->timeout, 5, 5 * HZ);
 
-       xs_format_peer_addresses(xprt);
+       switch (addr->sa_family) {
+       case AF_INET:
+               if (((struct sockaddr_in *)addr)->sin_port != htons(0))
+                       xprt_set_bound(xprt);
+
+               INIT_DELAYED_WORK(&transport->connect_worker,
+                                       xs_udp_connect_worker4);
+               xs_format_ipv4_peer_addresses(xprt);
+               break;
+       case AF_INET6:
+               if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
+                       xprt_set_bound(xprt);
+
+               INIT_DELAYED_WORK(&transport->connect_worker,
+                                       xs_udp_connect_worker6);
+               xs_format_ipv6_peer_addresses(xprt);
+               break;
+       default:
+               kfree(xprt);
+               return ERR_PTR(-EAFNOSUPPORT);
+       }
+
        dprintk("RPC:       set up transport to address %s\n",
                        xprt->address_strings[RPC_DISPLAY_ALL]);
 
-       return xprt;
+       if (try_module_get(THIS_MODULE))
+               return xprt;
+
+       kfree(xprt->slot);
+       kfree(xprt);
+       return ERR_PTR(-EINVAL);
 }
 
 /**
@@ -1592,8 +1894,9 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
  * @args: rpc transport creation arguments
  *
  */
-struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
+struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
 {
+       struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
 
@@ -1602,14 +1905,10 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
 
-       if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
-               xprt_set_bound(xprt);
-
        xprt->prot = IPPROTO_TCP;
        xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
        xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
 
-       INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker);
        xprt->bind_timeout = XS_BIND_TO;
        xprt->connect_timeout = XS_TCP_CONN_TO;
        xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
@@ -1622,15 +1921,55 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
        else
                xprt_set_timeout(&xprt->timeout, 2, 60 * HZ);
 
-       xs_format_peer_addresses(xprt);
+       switch (addr->sa_family) {
+       case AF_INET:
+               if (((struct sockaddr_in *)addr)->sin_port != htons(0))
+                       xprt_set_bound(xprt);
+
+               INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4);
+               xs_format_ipv4_peer_addresses(xprt);
+               break;
+       case AF_INET6:
+               if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
+                       xprt_set_bound(xprt);
+
+               INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6);
+               xs_format_ipv6_peer_addresses(xprt);
+               break;
+       default:
+               kfree(xprt);
+               return ERR_PTR(-EAFNOSUPPORT);
+       }
+
        dprintk("RPC:       set up transport to address %s\n",
                        xprt->address_strings[RPC_DISPLAY_ALL]);
 
-       return xprt;
+       if (try_module_get(THIS_MODULE))
+               return xprt;
+
+       kfree(xprt->slot);
+       kfree(xprt);
+       return ERR_PTR(-EINVAL);
 }
 
+static struct xprt_class       xs_udp_transport = {
+       .list           = LIST_HEAD_INIT(xs_udp_transport.list),
+       .name           = "udp",
+       .owner          = THIS_MODULE,
+       .ident          = IPPROTO_UDP,
+       .setup          = xs_setup_udp,
+};
+
+static struct xprt_class       xs_tcp_transport = {
+       .list           = LIST_HEAD_INIT(xs_tcp_transport.list),
+       .name           = "tcp",
+       .owner          = THIS_MODULE,
+       .ident          = IPPROTO_TCP,
+       .setup          = xs_setup_tcp,
+};
+
 /**
- * init_socket_xprt - set up xprtsock's sysctls
+ * init_socket_xprt - set up xprtsock's sysctls, register with RPC client
  *
  */
 int init_socket_xprt(void)
@@ -1640,11 +1979,14 @@ int init_socket_xprt(void)
                sunrpc_table_header = register_sysctl_table(sunrpc_table);
 #endif
 
+       xprt_register_transport(&xs_udp_transport);
+       xprt_register_transport(&xs_tcp_transport);
+
        return 0;
 }
 
 /**
- * cleanup_socket_xprt - remove xprtsock's sysctls
+ * cleanup_socket_xprt - remove xprtsock's sysctls, unregister
  *
  */
 void cleanup_socket_xprt(void)
@@ -1655,4 +1997,7 @@ void cleanup_socket_xprt(void)
                sunrpc_table_header = NULL;
        }
 #endif
+
+       xprt_unregister_transport(&xs_udp_transport);
+       xprt_unregister_transport(&xs_tcp_transport);
 }
index 2b57eaf66abc4086f7387704c1993ee399ba65c3..6996cba5aa9664ac99f706b626137d98fb99d286 100644 (file)
@@ -334,7 +334,7 @@ static void unix_write_space(struct sock *sk)
        read_lock(&sk->sk_callback_lock);
        if (unix_writable(sk)) {
                if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-                       wake_up_interruptible(sk->sk_sleep);
+                       wake_up_interruptible_sync(sk->sk_sleep);
                sk_wake_async(sk, 2, POLL_OUT);
        }
        read_unlock(&sk->sk_callback_lock);
@@ -1639,7 +1639,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (!skb)
                goto out_unlock;
 
-       wake_up_interruptible(&u->peer_wait);
+       wake_up_interruptible_sync(&u->peer_wait);
 
        if (msg->msg_name)
                unix_copy_addr(msg, skb->sk);
index 36e3754db53a5b0951fb0a6c180f111ae2f9c54a..494435ca88fa704ef130ae4d9fd8e8d18456886f 100644 (file)
@@ -396,13 +396,6 @@ static int do_vio_entry(const char *filename, struct vio_device_id *vio,
        return 1;
 }
 
-static int do_i2c_entry(const char *filename, struct i2c_device_id *i2c, char *alias)
-{
-       strcpy(alias, "i2c:");
-       ADD(alias, "id", 1, i2c->id);
-       return 1;
-}
-
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
 static void do_input(char *alias,
@@ -613,10 +606,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct vio_device_id), "vio",
                         do_vio_entry, mod);
-       else if (sym_is(symname, "__mod_i2c_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct i2c_device_id), "i2c",
-                        do_i2c_entry, mod);
        else if (sym_is(symname, "__mod_input_device_table"))
                do_table(symval, sym->st_size,
                         sizeof(struct input_device_id), "input",
index 188c7cf21b8227465fdd248b6286efabc6f373d6..131952f558576127a35e888139ef3f5a4f07f610 100644 (file)
@@ -157,7 +157,7 @@ struct snd_bt87x {
        int dig_rate;
 
        spinlock_t reg_lock;
-       long opened;
+       unsigned long opened;
        struct snd_pcm_substream *substream;
 
        struct snd_dma_buffer dma_risc;
index 7bd5852fcc0d1aa1cd0056c083929f2f69197369..ac5666f4c6d59c02146e56f1a49da1c257572712 100644 (file)
@@ -2876,7 +2876,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        struct audioformat *fp;
        struct usb_host_interface *alts;
        int stream, err;
-       int *rate_table = NULL;
+       unsigned *rate_table = NULL;
 
        fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
        if (! fp) {